1(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,204776,293457,19529,e=>{"use strict";let o=`#version 300 es 2precision highp float; 3 4in vec2 vUv; 5out vec4 fragColor; 6 7uniform float u_time; 8uniform float u_speed; 9uniform vec3 u_colors[12]; 10uniform float u_colorPositions[12]; 11uniform int u_colorCount; 12uniform float u_direction; 13uniform float u_grain; 14uniform vec2 u_resolution; 15 16// Blend uniforms 17uniform int u_blendMode; 18uniform float u_blendIntensity; 19uniform float u_blendOffset; 20uniform float u_blendRotation; 21uniform float u_blendScale; 22uniform int u_blendAnimRotation; 23uniform int u_blendAnimIntensity; 24uniform int u_blendAnimOffset; 25uniform float u_blendAnimSpeed; 26uniform float u_blendNoiseMask; 27uniform float u_blendNoiseScale; 28uniform float u_blendFalloff; 29uniform int u_blendDualLayer; 30uniform int u_blendMode2; 31uniform float u_blendIntensity2; 32uniform float u_blendOffset2; 33uniform float u_blendRotation2; 34uniform float u_blendScale2; 35 36// Simple mode uniforms 37uniform int u_simpleType; // 0=linear, 1=radial, 2=geometric 38uniform float u_centerX; 39uniform float u_centerY; 40uniform float u_radius; 41uniform int u_shape; // 0=diamond, 1=conic, 2=square, 3=burst 42uniform float u_segments; 43uniform float u_rotation; 44uniform float u_scale; 45uniform float u_sharpness; 46uniform float u_distortion; 47uniform float u_swirl; 48 49// Figma-style gradient line endpoints (for linear mode) 50uniform vec2 u_gradientStart; 51uniform vec2 u_gradientEnd; 52 53__COMMON__ 54 55#define TAU 6.28318530718 56#define PI 3.14159265359 57 58// Distortion â noise-based UV warp 59vec2 applyDistortion(vec2 uv, float distortion, float t) { 60 float n1 = snoise(uv * 3.0 + t * 0.2); 61 float n2 = snoise(uv * 3.0 + vec2(5.2, 1.3) + t * 0.2); 62 return uv + vec2(n1, n2) * distortion * 0.15; 63} 64 65// Swirl â radial UV twist 66vec2 applySwirl(vec2 uv, float swirl) { 67 vec2 center = vec2(0.5); 68 vec2 delta = uv - center; 69 float dist = length(delta); 70 float angle = swirl * 6.2832 * (1.0 - smoothstep(0.0, 0.5, dist)); 71 float s = sin(angle), c = cos(angle); 72 return center + vec2(c * delta.x - s * delta.y, s * delta.x + c * delta.y); 73} 74 75void main() { 76 vec2 uv = vUv; 77 float time = u_time * u_speed; 78 float t = 0.0; 79 80 // Correct for aspect ratio 81 float aspect = u_resolution.x / u_resolution.y; 82 uv = applyMouseWarp(uv, aspect); 83 84 // Apply distortion and swirl 85 if (u_distortion > 0.0) uv = applyDistortion(uv, u_distortion, time); 86 if (u_swirl > 0.0) uv = applySwirl(uv, u_swirl); 87 88 if (u_simpleType == 0) { 89 // === LINEAR (Figma-style two-point) === 90 vec2 gradLine = u_gradientEnd - u_gradientStart; 91 float gradLen2 = dot(gradLine, gradLine); 92 // Project UV onto gradient line: t=0 at start, t=1 at end, overflows for negative space 93 t = (gradLen2 > 0.00001) ? dot(uv - u_gradientStart, gradLine) / gradLen2 : 0.5; 94 95 } else if (u_simpleType == 1) { 96 // === RADIAL === 97 vec2 center = vec2(u_centerX, u_centerY); 98 vec2 diff = uv - center; 99 diff.x *= aspect; 100 // Apply direction as rotation for elliptical radial gradients 101 float rAngle = radians(u_direction); 102 float rCs = cos(rAngle); 103 float rSn = sin(rAngle); 104 diff = vec2(diff.x * rCs - diff.y * rSn, diff.x * rSn + diff.y * rCs); 105 float dist = length(diff); 106 t = dist / u_radius; 107 108 } else { 109 // === GEOMETRIC === 110 vec2 center = vec2(u_centerX, u_centerY); 111 vec2 diff = uv - center; 112 diff.x *= aspect; 113 114 // Apply rotation 115 float rotAngle = radians(u_rotation); 116 float cs = cos(rotAngle); 117 float sn = sin(rotAngle); 118 vec2 rotated = vec2(diff.x * cs - diff.y * sn, diff.x * sn + diff.y * cs); 119 120 // Apply scale 121 rotated /= max(u_scale, 0.01); 122 123 if (u_shape == 0) { 124 // Diamond 125 t = abs(rotated.x) + abs(rotated.y); 126 } else if (u_shape == 1) { 127 // Conic (angular sweep) 128 float angle = atan(rotated.y, rotated.x); 129 t = (angle + PI) / TAU; 130 } else if (u_shape == 2) { 131 // Square 132 t = max(abs(rotated.x), abs(rotated.y)); 133 } else { 134 // Burst (radial segments) 135 float angle = atan(rotated.y, rotated.x); 136 float seg = TAU / max(u_segments, 3.0); 137 float angular = abs(mod(angle + seg * 0.5, seg) - seg * 0.5); 138 float dist = length(rotated); 139 t = dist * (1.0 + angular * u_sharpness * 4.0); 140 } 141 142 // Normalize geometric shapes to roughly 0-1 range 143 t = t * 2.0; 144 } 145 146 // Subtle animation displacement when animated 147 if (u_speed > 0.0 && time > 0.0) { 148 t += snoise(uv * 2.0 + time * 0.3) * 0.02; 149 } 150 151 // Linear mode: allow t overflow for negative-space gradients. 152 // Radial/geometric: clamp to [0,1] as they don't support negative space. 153 if (u_simpleType != 0) { 154 t = clamp(t, 0.0, 1.0); 155 } 156 157 // Image-driven gradient map: luminance â t 158 float imgLum = imageLuminance(uv, aspect); 159 if (imgLum >= 0.0) { 160 t = mix(t, imgLum, u_imageIntensity); 161 } 162 163 // Mix sharpness: smooth vs hard edges for geometric 164 if (u_simpleType == 2 && u_sharpness > 0.5) { 165 float sharpFactor = (u_sharpness - 0.5) * 2.0; 166 float steps = mix(1.0, float(u_colorCount), sharpFactor); 167 t = floor(t * steps) / max(steps - 1.0, 1.0); 168 t = clamp(t, 0.0, 1.0); 169 } 170 171 vec3 color = mixColors(u_colors, u_colorPositions, u_colorCount, t); 172 color += grain(uv, time, u_grain); 173 174 // Blend math expects t in [0,1] â linear mode allows overflow for negative 175 // space in the base color, but blend falloff / layering would break with 176 // extreme t values, so we use a clamped copy for those computations. 177 float tBlend = clamp(t, 0.0, 1.0); 178 179 // Self-blend 180 if (u_blendMode > 0) { 181 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 182 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 183 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 184 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 185 bIntensity = applyBlendFalloff(bIntensity, tBlend, u_blendFalloff); 186 float tB = blendLayerT(uv, tBlend, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 187 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 188 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 189 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 190 float tB2 = blendLayerT(uv, tBlend, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 191 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 192 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 193 } 194 } 195 196 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 197} 198`,t=`#version 300 es 199precision highp float; 200 201in vec2 vUv; 202out vec4 fragColor; 203 204uniform float u_time; 205uniform float u_speed; 206uniform vec3 u_colors[12]; 207uniform float u_colorPositions[12]; 208uniform int u_colorCount; 209uniform float u_direction; 210uniform float u_grain; 211uniform vec2 u_resolution; 212 213// Blend uniforms 214uniform int u_blendMode; 215uniform float u_blendIntensity; 216uniform float u_blendOffset; 217uniform float u_blendRotation; 218uniform float u_blendScale; 219uniform int u_blendAnimRotation; 220uniform int u_blendAnimIntensity; 221uniform int u_blendAnimOffset; 222uniform float u_blendAnimSpeed; 223uniform float u_blendNoiseMask; 224uniform float u_blendNoiseScale; 225uniform float u_blendFalloff; 226uniform int u_blendDualLayer; 227uniform int u_blendMode2; 228uniform float u_blendIntensity2; 229uniform float u_blendOffset2; 230uniform float u_blendRotation2; 231uniform float u_blendScale2; 232 233uniform float u_frequency; 234uniform int u_octaves; 235uniform float u_amplitude; 236uniform float u_lacunarity; 237uniform float u_seed; 238 239// Domain warp uniforms (Inigo Quilez technique) 240uniform float u_domainWarp; // 0 = off, >0 = warp strength 241uniform int u_domainWarpDepth; // Number of nested warp iterations (1-3) 242uniform float u_domainWarpScale; // Scale multiplier for warp noise 243uniform float u_chromaticShift; // Per-channel color offset for prismatic effect 244 245__COMMON__ 246 247// Domain-warped FBM (Inigo Quilez "warping" technique) 248// Nested FBM: f(p + fbm(p + fbm(p))) â produces organic, liquid-like patterns 249float domainWarpFbm(vec2 p, float warpStr, int depth, float warpScale) { 250 // First warp layer 251 vec2 q = vec2( 252 fbm(p + vec2(0.0, 0.0), warpScale, u_octaves, u_amplitude, u_lacunarity), 253 fbm(p + vec2(5.2, 1.3), warpScale, u_octaves, u_amplitude, u_lacunarity) 254 ); 255 256 if (depth <= 1) { 257 return fbm(p + q * warpStr, 1.0, u_octaves, u_amplitude, u_lacunarity); 258 } 259
260 // Second warp layer â deeper nested warping 261 vec2 r = vec2( 262 fbm(p + q * warpStr + vec2(1.7, 9.2), warpScale, u_octaves, u_amplitude, u_lacunarity), 263 fbm(p + q * warpStr + vec2(8.3, 2.8), warpScale, u_octaves, u_amplitude, u_lacunarity) 264 ); 265 266 if (depth <= 2) { 267 return fbm(p + r * warpStr, 1.0, u_octaves, u_amplitude, u_lacunarity); 268 } 269 270 // Third warp layer â maximum depth for ultra-smooth liquid feel 271 vec2 s = vec2( 272 fbm(p + r * warpStr + vec2(3.1, 7.4), warpScale, u_octaves, u_amplitude, u_lacunarity), 273 fbm(p + r * warpStr + vec2(6.5, 4.1), warpScale, u_octaves, u_amplitude, u_lacunarity) 274 ); 275 276 return fbm(p + s * warpStr, 1.0, u_octaves, u_amplitude, u_lacunarity); 277} 278 279void main() { 280 vec2 uv = vUv; 281 float time = u_time * u_speed; 282 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 283 uv = applyMouseWarp(uv, aspect); 284 285 // Direction-based base gradient 286 float angle = radians(u_direction); 287 vec2 dir = vec2(cos(angle), sin(angle)); 288 float t = dot(uv - 0.5, dir) + 0.5; 289 290 // Noise displacement with time animation 291 vec2 noiseCoord = uv * u_frequency + vec2(u_seed * 0.1); 292 noiseCoord += vec2(time * 0.15, time * 0.1); 293 294 float n; 295 if (u_domainWarp > 0.0) { 296 // Domain-warped FBM â liquid reality effect 297 n = domainWarpFbm(noiseCoord, u_domainWarp * 4.0, u_domainWarpDepth, u_domainWarpScale); 298 } else { 299 // Standard FBM noise 300 n = fbm(noiseCoord, 1.0, u_octaves, u_amplitude, u_lacunarity); 301 } 302 303 // Mix direction gradient with noise 304 t += n * 0.35; 305 t = clamp(t, 0.0, 1.0); 306 307 // Image-driven gradient modulation 308 float imgLum = imageLuminance(uv, aspect); 309 if (imgLum >= 0.0) { 310 t = mix(t, imgLum, u_imageIntensity); 311 } 312 313 vec3 color; 314 if (u_domainWarp > 0.0 && u_chromaticShift > 0.0) { 315 // Chromatic aberration: offset each channel for prismatic liquid look 316 float shift = u_chromaticShift * 0.02; 317 vec2 coordR = noiseCoord + vec2(shift, 0.0); 318 vec2 coordB = noiseCoord - vec2(shift, 0.0); 319 float nR = domainWarpFbm(coordR, u_domainWarp * 4.0, u_domainWarpDepth, u_domainWarpScale); 320 float nB = domainWarpFbm(coordB, u_domainWarp * 4.0, u_domainWarpDepth, u_domainWarpScale); 321 float tR = clamp(dot(uv - 0.5, dir) + 0.5 + nR * 0.35, 0.0, 1.0); 322 float tB = clamp(dot(uv - 0.5, dir) + 0.5 + nB * 0.35, 0.0, 1.0); 323 vec3 colorCenter = mixColors(u_colors, u_colorPositions, u_colorCount, t); 324 vec3 colorR = mixColors(u_colors, u_colorPositions, u_colorCount, tR); 325 vec3 colorB = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 326 color = vec3(colorR.r, colorCenter.g, colorB.b); 327 } else { 328 color = mixColors(u_colors, u_colorPositions, u_colorCount, t); 329 } 330 331 // Add grain 332 color += grain(uv, time, u_grain); 333 334 // Self-blend 335 if (u_blendMode > 0) { 336 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 337 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 338 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 339 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 340 bIntensity = applyBlendFalloff(bIntensity, t, u_blendFalloff); 341 float tB = blendLayerT(uv, t, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 342 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 343 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 344 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 345 float tB2 = blendLayerT(uv, t, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 346 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 347 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 348 } 349 } 350 351 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 352} 353`;var i=e.i(780371);let n=`#version 300 es 354precision highp float; 355 356in vec2 vUv; 357out vec4 fragColor; 358 359uniform float u_time; 360uniform float u_speed; 361uniform vec3 u_colors[12]; 362uniform float u_colorPositions[12]; 363uniform int u_colorCount; 364uniform float u_direction; 365uniform float u_grain; 366uniform vec2 u_resolution; 367 368// Blend uniforms 369uniform int u_blendMode; 370uniform float u_blendIntensity; 371uniform float u_blendOffset; 372uniform float u_blendRotation; 373uniform float u_blendScale; 374uniform int u_blendAnimRotation; 375uniform int u_blendAnimIntensity; 376uniform int u_blendAnimOffset; 377uniform float u_blendAnimSpeed; 378uniform float u_blendNoiseMask; 379uniform float u_blendNoiseScale; 380uniform float u_blendFalloff; 381uniform int u_blendDualLayer; 382uniform int u_blendMode2; 383uniform float u_blendIntensity2; 384uniform float u_blendOffset2; 385uniform float u_blendRotation2; 386uniform float u_blendScale2; 387 388uniform float u_centerX; 389uniform float u_centerY; 390uniform float u_radius; 391uniform float u_falloff; 392uniform float u_distortion; 393uniform float u_noiseIntensity; 394 395__COMMON__ 396 397void main() { 398 vec2 uv = vUv; 399 float time = u_time * u_speed; 400 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 401 uv = applyMouseWarp(uv, aspect); 402 403 vec2 center = vec2(u_centerX, u_centerY); 404 vec2 p = uv - center; 405 p.x *= aspect; 406 407 // Noise distortion 408 float n = snoise(uv * 3.0 + time * 0.2) * u_distortion; 409 float n2 = snoise(uv * 6.0 - time * 0.15) * u_distortion * 0.5; 410 p += vec2(n, n2); 411 412 // Radial distance 413 float dist = length(p) / u_radius; 414 415 // Falloff curve 416 float t = pow(dist, 1.0 / max(u_falloff, 0.1)); 417 418 // Add noise variation 419 t += snoise(uv * 5.0 + time * 0.1) * u_noiseIntensity * 0.2; 420 t = clamp(t, 0.0, 1.0); 421 422 // Image-driven gradient modulation 423 float imgLum = imageLuminance(uv, aspect); 424 if (imgLum >= 0.0) { 425 t = mix(t, imgLum, u_imageIntensity); 426 } 427 428 vec3 color = mixColors(u_colors, u_colorPositions, u_colorCount, t); 429 430 // Grain 431 color += grain(uv, time, u_grain); 432 433 // Self-blend 434 if (u_blendMode > 0) { 435 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 436 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 437 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 438 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 439 bIntensity = applyBlendFalloff(bIntensity, t, u_blendFalloff); 440 float tB = blendLayerT(uv, t, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 441 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 442 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 443 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 444 float tB2 = blendLayerT(uv, t, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 445 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 446 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 447 } 448 } 449 450 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 451} 452`,l=`#version 300 es 453precision highp float; 454 455in vec2 vUv; 456out vec4 fragColor; 457 458uniform float u_time; 459uniform float u_speed; 460uniform vec3 u_colors[12]; 461uniform float u_colorPositions[12]; 462uniform int u_colorCount; 463uniform float u_direction; 464uniform float u_grain; 465uniform vec2 u_resolution; 466 467// Blend uniforms 468uniform int u_blendMode; 469uniform float u_blendIntensity; 470uniform float u_blendOffset; 471uniform float u_blendRotation; 472uniform float u_blendScale; 473uniform int u_blendAnimRotation; 474uniform int u_blendAnimIntensity; 475uniform int u_blendAnimOffset; 476uniform float u_blendAnimSpeed; 477uniform float u_blendNoiseMask; 478uniform float u_blendNoiseScale; 479uniform float u_blendFalloff; 480uniform int u_blendDualLayer; 481uniform int u_blendMode2; 482uniform float u_blendIntensity2; 483uniform float u_blendOffset2; 484uniform float u_blendRotation2; 485uniform float u_blendScale2; 486 487uniform int u_ditherTechnique; 488uniform int u_matrixSize; 489uniform int u_quantizationLevels; 490uniform float u_patternScale; 491uniform float u_waveSpeed; 492uniform float u_waveFrequency; 493uniform float u_warpIntensity; 494uniform float u_grainIntensity; 495 496__COMMON__ 497 498// ---- Hash for random / stochastic dithering ---- 499float hash21(vec2 p) { 500 p = fract(p * vec2(123.34, 456.21)); 501 p += dot(p, p + 45.32); 502 return fract(p.x * p.y); 503} 504 505// ---- Clustered-dot threshold ----
506// Radial distance within a grid cell creates round dot clusters 507float clusteredDot(vec2 p, float cellSize) { 508 vec2 cell = floor(p / cellSize); 509 vec2 local = fract(p / cellSize) - 0.5; 510 // Distance from cell center, normalized 0..1 511 float dist = length(local) * 2.0; 512 // Slight rotation per cell for visual variety 513 float angle = hash21(cell) * 6.283; 514 float s = sin(angle), c = cos(angle); 515 vec2 rotated = vec2(c * local.x - s * local.y, s * local.x + c * local.y); 516 dist = length(rotated) * 2.0; 517 return clamp(dist, 0.0, 1.0); 518} 519 520// ---- Blue noise approximation ---- 521// Multi-octave simplex noise produces smooth, non-repeating threshold 522float blueNoise(vec2 p) { 523 float n = 0.0; 524 n += snoise(p * 0.8) * 0.35; 525 n += snoise(p * 1.7 + 31.7) * 0.30; 526 n += snoise(p * 3.4 + 73.1) * 0.20; 527 n += snoise(p * 7.1 + 117.3) * 0.15; 528 return n * 0.5 + 0.5; // normalize to [0, 1] 529} 530 531// ---- Floyd-Steinberg approximation ---- 532// Fine blue noise + luminance-aware bias â smooth organic dithering 533float floydSteinbergApprox(vec2 p, float lum) { 534 // Fine-grained noise for smooth error-diffusion look 535 float n = snoise(p * 1.2) * 0.3 + snoise(p * 2.8 + 41.0) * 0.25 536 + snoise(p * 5.5 + 89.0) * 0.2 + snoise(p * 11.0 + 137.0) * 0.15; 537 n = n * 0.5 + 0.5; 538 // Luminance-aware bias: push dark areas darker, light areas lighter 539 float bias = (lum - 0.5) * 0.15; 540 return clamp(n + bias, 0.0, 1.0); 541} 542 543// ---- Atkinson approximation ---- 544// Coarser, higher contrast â preserves detail via partial error spread (75%) 545float atkinsonApprox(vec2 p, float lum) { 546 // Coarser noise pattern 547 float n = snoise(p * 0.9) * 0.4 + snoise(p * 2.1 + 53.0) * 0.35 548 + snoise(p * 4.0 + 97.0) * 0.25; 549 n = n * 0.5 + 0.5; 550 // Higher contrast threshold â sharper transitions 551 n = smoothstep(0.2, 0.8, n); 552 // Stronger luminance bias for detail preservation 553 float bias = (lum - 0.5) * 0.25; 554 return clamp(n + bias, 0.0, 1.0); 555} 556 557// ---- Jarvis-Judice-Ninke approximation ---- 558// Wide kernel averaging â softer, slightly blurred transitions 559float jarvisApprox(vec2 p) { 560 // Average noise over a wider area (5-tap kernel) 561 float n = 0.0; 562 n += snoise(p * 1.0) * 0.2; 563 n += snoise(p * 1.0 + vec2(1.5, 0.0)) * 0.15; 564 n += snoise(p * 1.0 + vec2(-1.5, 0.0)) * 0.15; 565 n += snoise(p * 1.0 + vec2(0.0, 1.5)) * 0.15; 566 n += snoise(p * 1.0 + vec2(0.0, -1.5)) * 0.15; 567 // Additional finer detail 568 n += snoise(p * 2.5 + 67.0) * 0.1; 569 n += snoise(p * 5.0 + 131.0) * 0.1; 570 return n * 0.5 + 0.5; 571} 572 573vec3 quantize(vec3 color, float levels) { 574 return floor(color * levels + 0.5) / levels; 575} 576 577void main() { 578 vec2 uv = vUv; 579 float time = u_time * u_speed * u_waveSpeed; 580 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 581 uv = applyMouseWarp(uv, aspect); 582 583 vec2 p = uv; 584 p.x *= aspect; 585 586 // Domain warping 587 float warp = snoise(p * 2.0 + time * 0.3); 588 p += warp * u_warpIntensity * 0.3; 589 590 // Wave distortion 591 float wave = sin(p.x * u_waveFrequency + time) * 0.1; 592 wave += cos(p.y * u_waveFrequency * 0.7 + time * 0.8) * 0.05; 593 594 // Base gradient 595 float angle = radians(u_direction); 596 vec2 dir = vec2(cos(angle), sin(angle)); 597 float t = dot(uv - 0.5 + vec2(wave), dir) + 0.5; 598 t += snoise(p * 3.0 + time * 0.2) * 0.2; 599 t = clamp(t, 0.0, 1.0); 600 601 // Image luminance drives dither pattern 602 float imgLum = imageLuminance(uv, aspect); 603 if (imgLum >= 0.0) { 604 t = mix(t, imgLum, u_imageIntensity); 605 } 606 607 vec3 color = mixColors(u_colors, u_colorPositions, u_colorCount, t); 608 609 // ---- Dithering ---- 610 vec2 pixelCoord = gl_FragCoord.xy / u_patternScale; 611 float levels = float(u_quantizationLevels); 612 float threshold; 613 vec3 dithered; 614 615 if (u_ditherTechnique == 0) { 616 // ---- Bayer ordered dithering ---- 617 if (u_matrixSize <= 2) { 618 threshold = bayer2(pixelCoord); 619 } else if (u_matrixSize <= 4) { 620 threshold = bayer4(pixelCoord); 621 } else { 622 threshold = bayer8(pixelCoord); 623 } 624 dithered = floor(color * levels + threshold) / levels; 625 626 } else if (u_ditherTechnique == 1) { 627 // ---- Blue noise dithering ---- 628 threshold = blueNoise(pixelCoord); 629 dithered = floor(color * levels + threshold) / levels; 630 631 } else if (u_ditherTechnique == 2) { 632 // ---- Clustered dot dithering ---- 633 float cellSize = max(u_patternScale * 4.0, 2.0); 634 threshold = clusteredDot(gl_FragCoord.xy, cellSize); 635 dithered = floor(color * levels + threshold) / levels; 636 637 } else if (u_ditherTechnique == 3) { 638 // ---- Floyd-Steinberg approximation ---- 639 float lum = sg_luminance(color); 640 threshold = floydSteinbergApprox(pixelCoord, lum); 641 dithered = floor(color * levels + threshold) / levels; 642 643 } else if (u_ditherTechnique == 4) { 644 // ---- Atkinson approximation ---- 645 float lum = sg_luminance(color); 646 threshold = atkinsonApprox(pixelCoord, lum); 647 // Atkinson uses ~75% error propagation: slightly fewer effective levels 648 float atkinsonLevels = max(levels * 0.75, 2.0); 649 dithered = floor(color * atkinsonLevels + threshold) / atkinsonLevels; 650 651 } else if (u_ditherTechnique == 5) { 652 // ---- Jarvis-Judice-Ninke approximation ---- 653 threshold = jarvisApprox(pixelCoord); 654 dithered = floor(color * levels + threshold) / levels; 655 656 } else { 657 // ---- Random (white noise) dithering ----
658 threshold = hash21(pixelCoord + fract(time * 0.1)); 659 dithered = floor(color * levels + threshold) / levels; 660 } 661 662 // Mix original and dithered based on grain 663 color = mix(color, dithered, 0.85 + u_grainIntensity * 0.15); 664 665 // Add subtle grain 666 color += grain(uv, time, u_grain); 667 668 // Self-blend 669 if (u_blendMode > 0) { 670 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 671 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 672 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 673 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 674 bIntensity = applyBlendFalloff(bIntensity, t, u_blendFalloff); 675 float tB = blendLayerT(uv, t, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 676 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 677 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 678 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 679 float tB2 = blendLayerT(uv, t, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 680 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 681 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 682 } 683 } 684 685 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 686} 687`,a=`#version 300 es 688precision highp float; 689 690in vec2 vUv; 691out vec4 fragColor; 692 693uniform float u_time; 694uniform float u_speed; 695uniform vec3 u_colors[12]; 696uniform float u_colorPositions[12]; 697uniform int u_colorCount; 698uniform float u_direction; 699uniform float u_grain; 700uniform vec2 u_resolution; 701 702// Blend uniforms 703uniform int u_blendMode; 704uniform float u_blendIntensity; 705uniform float u_blendOffset; 706uniform float u_blendRotation; 707uniform float u_blendScale; 708uniform int u_blendAnimRotation; 709uniform int u_blendAnimIntensity; 710uniform int u_blendAnimOffset; 711uniform float u_blendAnimSpeed; 712uniform float u_blendNoiseMask; 713uniform float u_blendNoiseScale; 714uniform float u_blendFalloff; 715uniform int u_blendDualLayer; 716uniform int u_blendMode2; 717uniform float u_blendIntensity2; 718uniform float u_blendOffset2; 719uniform float u_blendRotation2; 720uniform float u_blendScale2; 721 722uniform float u_dotSize; 723uniform float u_spacing; 724uniform float u_angle; 725uniform int u_shape; 726uniform float u_contrast; 727 728__COMMON__ 729 730float halftoneShape(vec2 p, int shape) { 731 if (shape == 1) { 732 // Square 733 vec2 d = abs(p); 734 return max(d.x, d.y); 735 } else if (shape == 2) { 736 // Diamond 737 return abs(p.x) + abs(p.y); 738 } 739 // Circle (default) 740 return length(p); 741} 742 743void main() { 744 vec2 uv = vUv; 745 float time = u_time * u_speed; 746 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 747 uv = applyMouseWarp(uv, aspect); 748 749 // Base gradient 750 float angle = radians(u_direction); 751 vec2 dir = vec2(cos(angle), sin(angle)); 752 float t = dot(uv - 0.5, dir) + 0.5; 753 t += snoise(uv * 3.0 + time * 0.15) * 0.15; 754 t = clamp(t, 0.0, 1.0); 755 756 vec3 baseColor = mixColors(u_colors, u_colorPositions, u_colorCount, t); 757 float lum = sg_luminance(baseColor); 758 759 // Image luminance drives dot size 760 float imgLum = imageLuminance(uv, aspect); 761 if (imgLum >= 0.0) { 762 lum = mix(lum, imgLum, u_imageIntensity); 763 } 764 765 // Halftone grid 766 float rotAngle = radians(u_angle); 767 mat2 rot = mat2(cos(rotAngle), -sin(rotAngle), sin(rotAngle), cos(rotAngle)); 768 769 vec2 pixelCoord = gl_FragCoord.xy; 770 vec2 rotated = rot * pixelCoord; 771 vec2 cell = floor(rotated / u_spacing); 772 vec2 cellCenter = (cell + 0.5) * u_spacing; 773 vec2 localPos = rotated - cellCenter; 774 775 // Dot size based on luminance 776 float dotRadius = u_dotSize * (1.0 - lum * u_contrast); 777 dotRadius = max(dotRadius, 0.2); 778 779 float dist = halftoneShape(localPos, u_shape); 780 // Analytic AA (fwidth) â crisp dot rims at any zoom instead of a fixed 1px ramp. 781 float dot = aaStep(dotRadius, dist); 782 783 // Color the dots 784 vec3 color = baseColor * dot; 785
786 // Image luminance maps to gradient position for dot color 787 if (imgLum >= 0.0) { 788 float imgT = mix(t, imgLum, u_imageIntensity); 789 vec3 imgColor = mixColors(u_colors, u_colorPositions, u_colorCount, imgT); 790 color = imgColor * dot; 791 } 792 793 // Grain 794 color += grain(uv, time, u_grain); 795 796 // Self-blend 797 if (u_blendMode > 0) { 798 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 799 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 800 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 801 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 802 bIntensity = applyBlendFalloff(bIntensity, t, u_blendFalloff); 803 float tB = blendLayerT(uv, t, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 804 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 805 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 806 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 807 float tB2 = blendLayerT(uv, t, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 808 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 809 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 810 } 811 } 812 813 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 814} 815`,r=`#version 300 es 816precision highp float; 817 818in vec2 vUv; 819out vec4 fragColor; 820 821uniform float u_time; 822uniform float u_speed; 823uniform vec3 u_colors[12]; 824uniform float u_colorPositions[12]; 825uniform int u_colorCount; 826uniform float u_direction; 827uniform float u_grain; 828uniform vec2 u_resolution; 829 830// Blend uniforms 831uniform int u_blendMode; 832uniform float u_blendIntensity; 833uniform float u_blendOffset; 834uniform float u_blendRotation; 835uniform float u_blendScale; 836uniform int u_blendAnimRotation; 837uniform int u_blendAnimIntensity; 838uniform int u_blendAnimOffset; 839uniform float u_blendAnimSpeed; 840uniform float u_blendNoiseMask; 841uniform float u_blendNoiseScale; 842uniform float u_blendFalloff; 843uniform int u_blendDualLayer; 844uniform int u_blendMode2; 845uniform float u_blendIntensity2; 846uniform float u_blendOffset2; 847uniform float u_blendRotation2; 848uniform float u_blendScale2; 849 850uniform float u_fontSize; 851uniform float u_density; 852uniform int u_invert; 853uniform int u_overlay; 854uniform int u_characterSet; 855 856__COMMON__ 857 858// Procedural character patterns â 5x5 grid encoded as floats 859// Each character is a 5x5 bitmap packed into bits 860float getCharPixel(int charIndex, vec2 pos) { 861 // Characters ordered by density: " .:-=+*#%@" 862 // Standard set (10 levels) 863 int patterns[10] = int[10]( 864 0, // space 865 0x4000, // . 866 0x4010040, // : 867 0xA8000, // - 868 0xA80A8, // = 869 0x4A904, // + 870 0x4AE04, // * 871 0xEA5AE, // # 872 0x155D57, // % 873 0x1F7FBE // @ 874 ); 875 876 int ix = int(pos.x); 877 int iy = int(pos.y); 878 if (ix < 0 || ix >= 5 || iy < 0 || iy >= 5) return 0.0; 879 880 int idx = min(charIndex, 9); 881 int bit = iy * 5 + ix; 882 return float((patterns[idx] >> bit) & 1); 883} 884 885void main() { 886 vec2 uv = vUv; 887 float time = u_time * u_speed; 888 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 889 uv = applyMouseWarp(uv, aspect); 890 891 // Base gradient 892 float angle = radians(u_direction); 893 vec2 dir = vec2(cos(angle), sin(angle)); 894 float t = dot(uv - 0.5, dir) + 0.5; 895 t += snoise(uv * 3.0 + time * 0.15) * 0.15; 896 t = clamp(t, 0.0, 1.0); 897 898 vec3 baseColor = mixColors(u_colors, u_colorPositions, u_colorCount, t); 899 900 // Cell grid 901 float cellSize = u_fontSize * u_density; 902 vec2 cell = floor(gl_FragCoord.xy / cellSize); 903 vec2 cellUV = fract(gl_FragCoord.xy / cellSize) * 5.0; 904 905 // Sample center of cell for luminance 906 vec2 cellCenter = (cell + 0.5) * cellSize / u_resolution; 907 float cellT = dot(cellCenter - 0.5, dir) + 0.5; 908 cellT += snoise(cellCenter * 3.0 + time * 0.15) * 0.15; 909 cellT = clamp(cellT, 0.0, 1.0); 910 vec3 cellColor = mixColors(u_colors, u_colorPositions, u_colorCount, cellT); 911 float lum = sg_luminance(cellColor); 912 913 // Image drives character selection and color 914 float imgLum = imageLuminance(cellCenter, aspect); 915 if (imgLum >= 0.0) { 916 lum = mix(lum, imgLum, u_imageIntensity); 917 } 918 919 if (u_invert == 1) lum = 1.0 - lum; 920 921 // Map luminance to character index (0-9) 922 int charIdx = int(lum * 9.0); 923 924 // Block set uses fewer levels 925 if (u_characterSet == 1) { 926 charIdx = int(lum * 4.0); 927 charIdx = charIdx * 2; // Skip to denser chars 928 } 929 // Minimal set 930 if (u_characterSet == 2) { 931 charIdx = lum > 0.5 ? 9 : (lum > 0.2 ? 4 : 0); 932 } 933 934 float pixel = getCharPixel(charIdx, cellUV); 935 936 vec3 color;
937 if (u_overlay == 1) { 938 // Overlay mode: ASCII pattern over the gradient 939 color = mix(baseColor * 0.3, baseColor, pixel); 940 } else { 941 // Full render mode: pure ASCII look 942 vec3 charColor = cellColor; 943 if (imgLum >= 0.0) { 944 charColor = mixColors(u_colors, u_colorPositions, u_colorCount, imgLum); 945 } 946 color = charColor * pixel; 947 } 948 949 // Grain 950 color += grain(uv, time, u_grain); 951 952 // Self-blend 953 if (u_blendMode > 0) { 954 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 955 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 956 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 957 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 958 bIntensity = applyBlendFalloff(bIntensity, t, u_blendFalloff); 959 float tB = blendLayerT(uv, t, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 960 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 961 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 962 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 963 float tB2 = blendLayerT(uv, t, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 964 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 965 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 966 } 967 } 968 969 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 970} 971`,s=`#version 300 es 972precision highp float; 973 974in vec2 vUv; 975out vec4 fragColor; 976 977uniform float u_time; 978uniform float u_speed; 979uniform vec3 u_colors[12]; 980uniform float u_colorPositions[12]; 981uniform int u_colorCount; 982uniform float u_direction; 983uniform float u_grain; 984uniform vec2 u_resolution; 985 986// Blend uniforms 987uniform int u_blendMode; 988uniform float u_blendIntensity; 989uniform float u_blendOffset; 990uniform float u_blendRotation; 991uniform float u_blendScale; 992uniform int u_blendAnimRotation; 993uniform int u_blendAnimIntensity; 994uniform int u_blendAnimOffset; 995uniform float u_blendAnimSpeed; 996uniform float u_blendNoiseMask; 997uniform float u_blendNoiseScale; 998uniform float u_blendFalloff; 999uniform int u_blendDualLayer; 1000uniform int u_blendMode2; 1001uniform float u_blendIntensity2; 1002uniform float u_blendOffset2; 1003uniform float u_blendRotation2; 1004uniform float u_blendScale2; 1005 1006uniform float u_warpIntensity; 1007uniform float u_smoothness; 1008uniform float u_distortion; 1009uniform float u_swirl; 1010 1011// Control points (up to 8) 1012uniform vec2 u_meshPoints[8]; 1013uniform int u_meshPointCount; 1014 1015__COMMON__ 1016 1017// Distortion â noise-based UV warp 1018vec2 applyDistortion(vec2 uv, float distortion, float t) { 1019 float n1 = snoise(uv * 3.0 + t * 0.2); 1020 float n2 = snoise(uv * 3.0 + vec2(5.2, 1.3) + t * 0.2); 1021 return uv + vec2(n1, n2) * distortion * 0.15; 1022} 1023 1024// Swirl â radial UV twist 1025vec2 applySwirl(vec2 uv, float swirl) { 1026 vec2 center = vec2(0.5); 1027 vec2 delta = uv - center; 1028 float dist = length(delta); 1029 float angle = swirl * 6.2832 * (1.0 - smoothstep(0.0, 0.5, dist)); 1030 float s = sin(angle), c = cos(angle); 1031 return center + vec2(c * delta.x - s * delta.y, s * delta.x + c * delta.y); 1032} 1033 1034void main() { 1035 vec2 uv = vUv; 1036 float time = u_time * u_speed; 1037 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 1038 uv = applyMouseWarp(uv, aspect); 1039 1040 // Apply distortion and swirl 1041 if (u_distortion > 0.0) uv = applyDistortion(uv, u_distortion, time); 1042 if (u_swirl > 0.0) uv = applySwirl(uv, u_swirl); 1043 1044 // Apply warp 1045 vec2 p = uv; 1046 float warp = snoise(p * 2.5 + time * 0.2); 1047 float warp2 = snoise(p * 4.0 - time * 0.15); 1048 p += vec2(warp, warp2) * u_warpIntensity * 0.15; 1049 1050 // Inverse Distance Weighting (IDW) interpolation 1051 float smoothExp = 2.0 + u_smoothness * 4.0; // Higher = smoother blending 1052 vec3 colorSum = vec3(0.0); 1053 float weightSum = 0.0; 1054 1055 int count = min(u_meshPointCount, u_colorCount); 1056 count = min(count, 8); 1057 1058 for (int i = 0; i < 8; i++) { 1059 if (i >= count) break; 1060 1061 vec2 point = u_meshPoints[i]; 1062 vec2 diff = p - point; 1063 diff.x *= aspect; 1064 float dist = length(diff); 1065 1066 // Avoid division by zero 1067 float weight = 1.0 / (pow(max(dist, 0.001), smoothExp)); 1068 1069 vec3 lin = srgbToLinear(u_colors[i]); 1070 vec3 blendColor = linearToOklab(lin); 1071 colorSum += blendColor * weight; 1072 weightSum += weight; 1073 } 1074 1075 vec3 blended = colorSum / max(weightSum, 0.001); 1076 vec3 color = oklabToLinear(blended); 1077 1078 // Image-driven gradient map: luminance picks color from gradient palette 1079 float imgLum = imageLuminance(uv, aspect); 1080 if (imgLum >= 0.0) { 1081 vec3 imgColor = mixColors(u_colors, u_colorPositions, u_colorCount, imgLum); 1082 color = mix(color, imgColor, u_imageIntensity); 1083 } 1084 1085 // Grain 1086 color += grain(uv, time, u_grain); 1087 1088 // Self-blend 1089 if (u_blendMode > 0) { 1090 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 1091 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 1092 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 1093 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 1094 bIntensity = applyBlendFalloff(bIntensity, uv.x, u_blendFalloff); 1095 float tB = blendLayerT(uv, 0.5, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 1096 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 1097 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 1098 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 1099 float tB2 = blendLayerT(uv, 0.5, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 1100 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 1101 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 1102 } 1103 } 1104 1105 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 1106} 1107`,u=`#version 300 es 1108precision highp float; 1109 1110in vec2 vUv; 1111out vec4 fragColor; 1112 1113uniform float u_time; 1114uniform float u_speed; 1115uniform vec3 u_colors[12]; 1116uniform float u_colorPositions[12]; 1117uniform int u_colorCount; 1118uniform float u_direction; 1119uniform float u_grain; 1120uniform vec2 u_resolution; 1121 1122// Blend uniforms 1123uniform int u_blendMode; 1124uniform float u_blendIntensity; 1125uniform float u_blendOffset; 1126uniform float u_blendRotation; 1127uniform float u_blendScale; 1128uniform int u_blendAnimRotation; 1129uniform int u_blendAnimIntensity; 1130uniform int u_blendAnimOffset; 1131uniform float u_blendAnimSpeed; 1132uniform float u_blendNoiseMask; 1133uniform float u_blendNoiseScale; 1134uniform float u_blendFalloff; 1135uniform int u_blendDualLayer; 1136uniform int u_blendMode2; 1137uniform float u_blendIntensity2; 1138uniform float u_blendOffset2; 1139uniform float u_blendRotation2; 1140uniform float u_blendScale2; 1141 1142uniform float u_nebulaScale; 1143uniform float u_nebulaIntensity; 1144uniform float u_starDensity; 1145uniform float u_starBrightness; 1146uniform float u_dustAmount; 1147uniform float u_warpStrength; 1148uniform float u_warpCenterX; 1149uniform float u_warpCenterY; 1150uniform float u_glowIntensity; 1151uniform int u_cosmicStyle; 1152 1153__COMMON__ 1154 1155float hash21(vec2 p) { 1156 p = fract(p * vec2(123.34, 456.21)); 1157 p += dot(p, p + 45.32); 1158 return fract(p.x * p.y); 1159} 1160 1161mat2 rot2(float a) { 1162 float s = sin(a); 1163 float c = cos(a); 1164 return mat2(c, -s, s, c); 1165} 1166 1167vec3 starField( 1168 vec2 uv, 1169 float time, 1170 float scale, 1171 float density, 1172 float brightness, 1173 float seed, 1174 float sparkle 1175) { 1176 density = clamp(density, 0.0, 0.99); 1177 float threshold = 1.0 - density; 1178 vec2 scaled = uv * scale; 1179 vec2 baseCell = floor(scaled); 1180 vec2 localUv = fract(scaled); 1181 vec3 acc = vec3(0.0); 1182 1183 for (int x = -1; x <= 1; x++) { 1184 for (int y = -1; y <= 1; y++) { 1185 vec2 cell = baseCell + vec2(float(x), float(y));
1186 float h = hash21(cell + seed); 1187 if (h < threshold) continue; 1188 1189 vec2 jitter = vec2( 1190 hash21(cell + 17.13 + seed), 1191 hash21(cell + 39.71 + seed) 1192 ); 1193 vec2 delta = (vec2(float(x), float(y)) + jitter) - localUv; 1194 float dist = length(delta); 1195 1196 float sizeRand = hash21(cell + 81.91 + seed); 1197 float size = mix(0.011, 0.0026, pow(sizeRand, 1.4)); 1198 float core = exp(-pow(dist / max(size, 0.0008), 2.6)); 1199 float halo = exp(-pow(dist / max(size * 5.2, 0.0015), 1.25)) * 0.38; 1200 float spike = exp(-abs(delta.x * delta.y) / (size * size * 3.4 + 0.0002)) * sparkle * 0.12; 1201 1202 float twinkleSpeed = 1.2 + hash21(cell + 5.41 + seed) * 4.6; 1203 float twinkle = 0.72 + 0.28 * sin(time * twinkleSpeed + h * 6.2831853); 1204 1205 float temp = hash21(cell + 23.58 + seed); 1206 vec3 coolStar = vec3(0.62, 0.76, 1.0); 1207 vec3 warmStar = vec3(1.0, 0.84, 0.62); 1208 vec3 tint = mix(coolStar, warmStar, temp); 1209 1210 float intensity = (core + halo + spike) * brightness * twinkle; 1211 acc += tint * intensity; 1212 } 1213 } 1214 1215 return acc; 1216} 1217 1218void main() { 1219 vec2 uv = vUv; 1220 float time = u_time * u_speed; 1221 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 1222 uv = applyMouseWarp(uv, aspect); 1223 1224 vec2 center = vec2(u_warpCenterX, u_warpCenterY); 1225 vec2 p = uv - center; 1226 p.x *= aspect; 1227 1228 float radius = length(p); 1229 float theta = atan(p.y, p.x); 1230 1231 // Style profile 1232 float nebulaGain = 1.0; 1233 float starGain = 1.0; 1234 float dustGain = 1.0; 1235 float glowGain = 1.0; 1236 float bandMix = 0.0; 1237 float spiralMix = 0.0; 1238 float clusterMix = 0.0; 1239 float supernovaMix = 0.0; 1240 float darkLaneBoost = 0.35; 1241 float swirlBoost = 0.35; 1242 1243 if (u_cosmicStyle == 1) { 1244 // Deep space 1245 nebulaGain = 0.48; 1246 starGain = 1.45; 1247 dustGain = 1.2; 1248 glowGain = 0.78; 1249 darkLaneBoost = 0.62; 1250 } else if (u_cosmicStyle == 2) { 1251 // Vortex 1252 nebulaGain = 1.18; 1253 starGain = 0.74; 1254 dustGain = 0.82; 1255 glowGain = 1.2; 1256 spiralMix = 0.9; 1257 swirlBoost = 1.15; 1258 } else if (u_cosmicStyle == 3) { 1259 // Milky Way 1260 nebulaGain = 0.95; 1261 starGain = 1.2; 1262 dustGain = 1.1; 1263 glowGain = 0.95; 1264 bandMix = 1.0; 1265 darkLaneBoost = 0.9; 1266 } else if (u_cosmicStyle == 4) { 1267 // Spiral Galaxy 1268 nebulaGain = 0.9; 1269 starGain = 1.05; 1270 dustGain = 0.9; 1271 glowGain = 1.05; 1272 spiralMix = 1.1; 1273 clusterMix = 0.45; 1274 swirlBoost = 0.85; 1275 } else if (u_cosmicStyle == 5) { 1276 // Emission Nebula 1277 nebulaGain = 1.36; 1278 starGain = 0.82; 1279 dustGain = 0.95; 1280 glowGain = 1.42; 1281 bandMix = 0.2; 1282 } else if (u_cosmicStyle == 6) { 1283 // Dark Nebula 1284 nebulaGain = 0.88; 1285 starGain = 0.95; 1286 dustGain = 1.65; 1287 glowGain = 0.82; 1288 darkLaneBoost = 1.35; 1289 bandMix = 0.35; 1290 } else if (u_cosmicStyle == 7) { 1291 // Star Cluster 1292 nebulaGain = 0.62; 1293 starGain = 1.75; 1294 dustGain = 0.68; 1295 glowGain = 1.1; 1296 clusterMix = 1.0; 1297 } else if (u_cosmicStyle == 8) { 1298 // Supernova 1299 nebulaGain = 1.15; 1300 starGain = 0.86; 1301 dustGain = 0.9; 1302 glowGain = 1.65; 1303 supernovaMix = 1.0; 1304 spiralMix = 0.24; 1305 swirlBoost = 0.66; 1306 clusterMix = 0.28; 1307 } 1308 1309 // Domain warp for volumetric structure. 1310 float swirl = u_warpStrength * (0.14 + swirlBoost) / (radius + 0.3); 1311 vec2 flowUv = rot2(swirl + time * (0.08 + 0.09 * swirlBoost)) * p; 1312 flowUv += vec2( 1313 snoise(p * 1.8 + vec2(time * 0.06, -time * 0.05)), 1314 snoise(p * 1.7 - vec2(time * 0.04, time * 0.03)) 1315 ) * u_warpStrength * 0.22; 1316 1317 float nA = fbm(flowUv * (u_nebulaScale * 1.1) + vec2(time * 0.05, -time * 0.04), 1.0, 5, 0.62, 2.0); 1318 float nB = fbm(flowUv * (u_nebulaScale * 2.5) - vec2(time * 0.03, time * 0.05), 1.0, 4, 0.5, 2.12); 1319 float nC = fbm(flowUv * (u_nebulaScale * 5.2) + vec2(-time * 0.02, time * 0.015), 1.0, 3, 0.48, 2.25); 1320 1321 nA = nA * 0.5 + 0.5; 1322 nB = nB * 0.5 + 0.5; 1323 nC = nC * 0.5 + 0.5; 1324 1325 float ridged = 1.0 - abs(nB * 2.0 - 1.0); 1326 float filament = smoothstep(0.24, 0.9, nA * 0.62 + ridged * 0.38); 1327 float dust = smoothstep(0.34, 0.94, nC); 1328 1329 // Pattern masks 1330 vec2 bandUv = rot2(radians(24.0)) * p; 1331 float milkyBand = exp(-pow(bandUv.y * 3.4, 2.0));
1332 float laneNoise = fbm(bandUv * 5.0 + vec2(time * 0.02, -time * 0.015), 1.0, 4, 0.55, 2.05) * 0.5 + 0.5; 1333 milkyBand *= mix(0.55, 1.25, smoothstep(0.28, 0.82, laneNoise)); 1334 1335 float spiralPhase = theta * 4.2 + log(radius + 1.15) * 11.0 - time * 0.55; 1336 float spiralArms = pow(max(cos(spiralPhase), 0.0), 2.6); 1337 float galaxyDisk = exp(-radius * 2.9); 1338 float spiralMask = spiralArms * galaxyDisk; 1339 1340 float clusterMask = exp(-pow(radius * 3.8, 2.0)); 1341 1342 float shellRadius = 0.24 + 0.03 * sin(time * 0.55); 1343 float supernovaShell = exp(-pow(abs(radius - shellRadius) / 0.065, 2.0)); 1344 float supernovaCore = exp(-radius * 7.5); 1345 float supernovaMask = supernovaCore * 0.85 + supernovaShell; 1346 1347 float structure = filament; 1348 structure += milkyBand * bandMix * 0.9; 1349 structure += spiralMask * spiralMix * 1.08; 1350 structure += clusterMask * clusterMix * 0.95; 1351 structure += supernovaMask * supernovaMix * 1.2; 1352 structure = clamp(structure, 0.0, 1.65); 1353 1354 vec2 dir = vec2(cos(radians(u_direction)), sin(radians(u_direction))); 1355 float t = dot(uv - 0.5, dir) + 0.5; 1356 t += (structure - 0.45) * (0.38 * u_nebulaIntensity + 0.14); 1357 t = clamp(t, 0.0, 1.0); 1358 1359 // Image-driven gradient modulation 1360 float imgLum = imageLuminance(uv, aspect); 1361 if (imgLum >= 0.0) { 1362 t = mix(t, imgLum, u_imageIntensity); 1363 } 1364 1365 vec3 base = mixColors(u_colors, u_colorPositions, u_colorCount, t); 1366 vec3 hot = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(t + 0.2, 0.0, 1.0)); 1367 vec3 cool = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(t - 0.16, 0.0, 1.0)); 1368 vec3 nebulaColor = mix(cool, hot, clamp(structure * 0.95 + milkyBand * 0.2, 0.0, 1.0)); 1369 vec3 emissionColor = mix(base, hot, 0.68); 1370 1371 vec3 color = vec3(0.0018, 0.0024, 0.0055); 1372 float bgVig = smoothstep(0.32, 1.1, radius); 1373 color *= 1.0 - bgVig * 0.58; 1374 1375 // Volumetric gas + style structures. 1376 float nebulaStrength = (0.2 + u_nebulaIntensity * 1.45) * nebulaGain; 1377 color += nebulaColor * filament * nebulaStrength; 1378 color += nebulaColor * dust * (0.24 + u_dustAmount * 0.54) * dustGain; 1379 color += emissionColor * milkyBand * bandMix * (0.14 + u_nebulaIntensity * 0.45); 1380 color += hot * spiralMask * spiralMix * (0.2 + u_glowIntensity * 0.55); 1381 color += mix(hot, vec3(1.0, 0.9, 0.7), 0.55) * supernovaMask * supernovaMix * (0.25 + u_glowIntensity * 1.05); 1382 1383 // Dark dust lanes for depth. 1384 float darkLane = smoothstep(0.45, 0.9, dust) * smoothstep(0.15, 0.88, filament); 1385 color *= 1.0 - darkLane * darkLaneBoost * (0.22 + u_dustAmount * 0.36); 1386 1387 // Pulsing emissive glow. 1388 float breathe = 0.7 + 0.3 * sin(time * 0.42 + radius * 3.8); 1389 color += nebulaColor * pow(clamp(structure, 0.0, 1.5), 1.3) * (u_glowIntensity * 0.72 * glowGain * breathe); 1390 1391 // Style-specific cores. 1392 if (u_cosmicStyle == 2) { 1393 float core = exp(-radius * 8.5); 1394 color += vec3(1.0, 0.88, 0.72) * core * (0.3 + u_glowIntensity * 1.25); 1395 } else if (u_cosmicStyle == 7) { 1396 float core = exp(-radius * 6.4); 1397 color += vec3(1.0, 0.95, 0.82) * core * (0.18 + u_starBrightness * 0.55); 1398 } 1399 1400 // Multi-layer star fields (reduced "dotty" artifacts, richer depth). 1401 vec2 starWarp = uv + vec2( 1402 snoise(uv * 6.4 + vec2(time * 0.05, -time * 0.04)), 1403 snoise(uv * 6.1 - vec2(time * 0.03, time * 0.02)) 1404 ) * (0.008 + u_warpStrength * 0.01); 1405 1406 float denseStars = mix(0.012, 0.11, u_starDensity); 1407 float sparseStars = denseStars * 0.42; 1408 float giantStars = denseStars * 0.12; 1409 1410 vec3 stars = starField(starWarp, time, mix(38.0, 165.0, u_starDensity), denseStars, u_starBrightness * 0.95, 11.7, 0.55); 1411 stars += starField(starWarp + vec2(0.12, -0.07), time * 1.23, mix(16.0, 68.0, u_starDensity), sparseStars, u_starBrightness * 0.72, 57.3, 1.0); 1412 stars += starField(starWarp + vec2(-0.19, 0.09), time * 0.86, mix(8.0, 26.0, u_starDensity), giantStars, u_starBrightness * 0.5, 101.4, 1.35); 1413 1414 float starMask = 1.0 + milkyBand * bandMix * 1.25 + clusterMask * clusterMix * 1.65; 1415 color += stars * starMask * starGain; 1416 1417 float vignette = smoothstep(0.36, 1.0, radius); 1418 float deepSpaceBoost = (u_cosmicStyle == 1 || u_cosmicStyle == 6) ? 0.12 : 0.0;
1419 color *= 1.0 - vignette * (0.6 + deepSpaceBoost); 1420 1421 color += grain(uv, time, u_grain * 0.72); 1422 1423 // Self-blend 1424 if (u_blendMode > 0) { 1425 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 1426 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 1427 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 1428 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 1429 bIntensity = applyBlendFalloff(bIntensity, uv.x, u_blendFalloff); 1430 float tB = blendLayerT(uv, 0.5, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 1431 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 1432 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 1433 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 1434 float tB2 = blendLayerT(uv, 0.5, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 1435 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 1436 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 1437 } 1438 } 1439 1440 fragColor = outputColor(color, gl_FragCoord.xy, 1.25); 1441} 1442`,f=`#version 300 es 1443precision highp float; 1444 1445in vec2 vUv; 1446out vec4 fragColor; 1447 1448uniform float u_time; 1449uniform float u_speed; 1450uniform vec3 u_colors[12]; 1451uniform float u_colorPositions[12]; 1452uniform int u_colorCount; 1453uniform float u_direction; 1454uniform float u_grain; 1455uniform vec2 u_resolution; 1456 1457// Blend uniforms 1458uniform int u_blendMode; 1459uniform float u_blendIntensity; 1460uniform float u_blendOffset; 1461uniform float u_blendRotation; 1462uniform float u_blendScale; 1463uniform int u_blendAnimRotation; 1464uniform int u_blendAnimIntensity; 1465uniform int u_blendAnimOffset; 1466uniform float u_blendAnimSpeed; 1467uniform float u_blendNoiseMask; 1468uniform float u_blendNoiseScale; 1469uniform float u_blendFalloff; 1470uniform int u_blendDualLayer; 1471uniform int u_blendMode2; 1472uniform float u_blendIntensity2; 1473uniform float u_blendOffset2; 1474uniform float u_blendRotation2; 1475uniform float u_blendScale2; 1476 1477uniform float u_scale; 1478uniform float u_elevation; 1479uniform float u_ridge; 1480uniform float u_terracing; 1481uniform float u_lightAzimuth; 1482uniform float u_lightElevation; 1483uniform float u_ambient; 1484uniform float u_specular; 1485uniform float u_fog; 1486uniform float u_parallax; 1487 1488__COMMON__ 1489 1490float terrainHeight(vec2 p, float time) { 1491 vec2 d = p * max(0.2, u_scale); 1492 float base = fbm(d + vec2(time * 0.05, -time * 0.04), 1.0, 5, 0.62, 2.02); 1493 float detail = fbm(d * 2.1 - vec2(time * 0.03, time * 0.02), 1.0, 4, 0.42, 2.18); 1494 float ridged = 1.0 - abs(detail); 1495 float h = base * 0.56 + ridged * (0.28 + u_ridge * 0.72); 1496 h = h * 0.5 + 0.5; 1497 1498 float terraces = mix(3.0, 18.0, u_terracing); 1499 float stepped = floor(h * terraces) / max(terraces, 1.0); 1500 h = mix(h, stepped, u_terracing * 0.85); 1501 return clamp(h, 0.0, 1.0); 1502} 1503 1504mat2 rot2(float a) { 1505 float s = sin(a); 1506 float c = cos(a); 1507 return mat2(c, -s, s, c); 1508} 1509 1510void main() { 1511 vec2 uv = vUv; 1512 float time = u_time * u_speed; 1513 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 1514 uv = applyMouseWarp(uv, aspect); 1515 vec2 p = uv - 0.5; 1516 p.x *= aspect; 1517 1518 vec2 depthUv = p; 1519 float depthPerspective = mix(0.7, 2.2, u_parallax); 1520 depthUv.x /= max(0.25, 1.0 + (uv.y - 0.2) * depthPerspective); 1521 depthUv += vec2(0.0, u_parallax * 0.12); 1522 depthUv = rot2(radians(u_direction * 0.18)) * depthUv; 1523 1524 float h = terrainHeight(depthUv, time) * (0.38 + u_elevation * 1.22); 1525 1526 float eps = 1.6 / max(min(u_resolution.x, u_resolution.y), 1.0); 1527 float hx = terrainHeight(depthUv + vec2(eps, 0.0), time); 1528 float hy = terrainHeight(depthUv + vec2(0.0, eps), time); 1529 vec3 n = normalize(vec3((h - hx) * 14.0, (h - hy) * 14.0, 1.0)); 1530 1531 float az = radians(u_lightAzimuth); 1532 float el = radians(clamp(u_lightElevation, 5.0, 85.0)); 1533 vec3 l = normalize(vec3(cos(el) * cos(az), sin(el), cos(el) * sin(az))); 1534 vec3 v = normalize(vec3(0.0, 0.0, 1.0)); 1535 vec3 hVec = normalize(l + v); 1536 1537 float diff = max(dot(n, l), 0.0); 1538 float spec = pow(max(dot(n, hVec), 0.0), mix(10.0, 120.0, u_specular)) * u_specular; 1539 float rim = pow(1.0 - max(dot(n, v), 0.0), 2.5) * (0.12 + u_specular * 0.25); 1540 1541 vec2 dir = vec2(cos(radians(u_direction)), sin(radians(u_direction))); 1542 float t = dot(uv - 0.5, dir) + 0.5; 1543 t += (h - 0.5) * (0.35 + u_elevation * 0.45); 1544 t += snoise(depthUv * 2.4 + vec2(time * 0.02, -time * 0.03)) * 0.06; 1545 t = clamp(t, 0.0, 1.0); 1546 1547 // Image-driven gradient integration 1548 float imgLum = imageLuminance(uv, aspect); 1549 if (imgLum >= 0.0) { 1550 t = mix(t, imgLum, u_imageIntensity); 1551 } 1552 1553 vec3 low = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(t - 0.22, 0.0, 1.0)); 1554 vec3 mid = mixColors(u_colors, u_colorPositions, u_colorCount, t); 1555 vec3 high = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(t + 0.18, 0.0, 1.0)); 1556 1557 vec3 color = mix(low, mid, smoothstep(0.12, 0.68, h)); 1558 color = mix(color, high, smoothstep(0.48, 1.05, h)); 1559 1560 float lightMix = mix(0.25, 1.28, diff); 1561 color *= mix(u_ambient * 0.55, u_ambient + lightMix * (1.15 - u_ambient), 0.88); 1562 color += high * spec * 0.85; 1563 color += mid * rim; 1564 1565 float fogDepth = smoothstep(0.12, 1.06, (uv.y * 0.85 + h * 0.35)); 1566 vec3 fogColor = mixColors(u_colors, u_colorPositions, u_colorCount, 0.12) * 0.35; 1567 color = mix(color, fogColor, fogDepth * u_fog * 0.8); 1568 1569 float vignette = smoothstep(0.36, 0.96, length((uv - 0.5) * vec2(1.1, 1.2)));
1570 color *= 1.0 - vignette * 0.55; 1571 1572 color += grain(uv, time, u_grain * 0.75); 1573 1574 // Self-blend 1575 if (u_blendMode > 0) { 1576 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 1577 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 1578 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 1579 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 1580 bIntensity = applyBlendFalloff(bIntensity, uv.x, u_blendFalloff); 1581 float tB = blendLayerT(uv, 0.5, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 1582 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 1583 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 1584 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 1585 float tB2 = blendLayerT(uv, 0.5, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 1586 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 1587 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 1588 } 1589 } 1590 1591 fragColor = outputColor(color, gl_FragCoord.xy, 1.1); 1592} 1593`,c=`#version 300 es 1594precision highp float; 1595 1596in vec2 vUv; 1597out vec4 fragColor; 1598 1599uniform float u_time; 1600uniform float u_speed; 1601uniform vec3 u_colors[12]; 1602uniform float u_colorPositions[12]; 1603uniform int u_colorCount; 1604uniform float u_direction; 1605uniform float u_grain; 1606uniform vec2 u_resolution; 1607 1608// Blend uniforms 1609uniform int u_blendMode; 1610uniform float u_blendIntensity; 1611uniform float u_blendOffset; 1612uniform float u_blendRotation; 1613uniform float u_blendScale; 1614uniform int u_blendAnimRotation; 1615uniform int u_blendAnimIntensity; 1616uniform int u_blendAnimOffset; 1617uniform float u_blendAnimSpeed; 1618uniform float u_blendNoiseMask; 1619uniform float u_blendNoiseScale; 1620uniform float u_blendFalloff; 1621uniform int u_blendDualLayer; 1622uniform int u_blendMode2; 1623uniform float u_blendIntensity2; 1624uniform float u_blendOffset2; 1625uniform float u_blendRotation2; 1626uniform float u_blendScale2; 1627 1628uniform float u_cellSize; 1629uniform float u_relief; 1630uniform float u_lineThickness; 1631uniform float u_perspective; 1632uniform float u_edgeSoftness; 1633uniform int u_isoPattern; 1634uniform float u_jitter; 1635uniform float u_glow; 1636 1637__COMMON__ 1638 1639mat2 rot2(float a) { 1640 float s = sin(a); 1641 float c = cos(a); 1642 return mat2(c, -s, s, c); 1643} 1644 1645void main() { 1646 vec2 uv = vUv; 1647 float time = u_time * u_speed; 1648 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 1649 uv = applyMouseWarp(uv, aspect); 1650 vec2 p = uv - 0.5; 1651 p.x *= aspect; 1652 1653 vec2 iso = vec2(p.x - p.y, (p.x + p.y) * 0.5); 1654 iso = rot2(radians(u_direction * 0.15)) * iso; 1655 1656 float perspectiveScale = mix(0.7, 1.65, u_perspective); 1657 iso.x *= mix(1.0, 0.68, uv.y) * perspectiveScale; 1658 1659 float jitter = snoise(iso * 2.0 + vec2(time * 0.2, -time * 0.15)) * u_jitter * 0.12; 1660 iso += vec2(jitter, -jitter * 0.55); 1661 1662 float cell = max(8.0, u_cellSize); 1663 vec2 g = iso * cell; 1664 vec2 id = floor(g); 1665 vec2 f = fract(g) - 0.5; 1666 1667 float hash = fract(sin(dot(id, vec2(127.1, 311.7))) * 43758.5453123); 1668 float cellDrift = snoise(id * 0.16 + vec2(time * 0.09, time * 0.06)); 1669 1670 float diamondDist = abs(f.x) + abs(f.y); 1671 float edgeWidth = mix(0.02, 0.16, u_edgeSoftness); 1672 float tileMask = 1.0 - smoothstep(0.5 - edgeWidth, 0.5 + edgeWidth, diamondDist); 1673 float hexDist = max(abs(f.y), abs(f.x) * 0.8660254 + abs(f.y) * 0.5); 1674 float hexMask = 1.0 - smoothstep(0.5 - edgeWidth, 0.5 + edgeWidth, hexDist); 1675 1676 float height = (0.3 + hash * 0.7 + cellDrift * 0.14) * u_relief; 1677 float steps = floor((hash + 0.15 + cellDrift * 0.2) * (2.0 + u_relief * 8.0)) / (2.0 + u_relief * 8.0); 1678 float prism = smoothstep(-0.45, 0.45, f.y) * (1.0 - abs(f.x) * 1.2); 1679 float weave = 0.5 + 0.5 * sin((id.x - id.y) * 0.8 + time * 0.7 + hash * 6.2831); 1680 float circuit = 1.0 - smoothstep( 1681 0.03, 1682 0.1, 1683 min( 1684 abs(fract((g.x + g.y) * 0.45) - 0.5), 1685 abs(fract((g.x - g.y) * 0.45) - 0.5) 1686 ) 1687 ); 1688 float skyline = floor((hash + cellDrift * 0.18) * (3.0 + u_relief * 10.0)) / (3.0 + u_relief * 10.0); 1689 1690 float cubeTop = smoothstep(0.0, 0.5, 0.5 - diamondDist); 1691 float topFace = cubeTop; 1692 float leftFace = (1.0 - smoothstep(-0.02, 0.02, f.x + f.y)) * (1.0 - topFace); 1693 float rightFace = (1.0 - smoothstep(-0.02, 0.02, f.x - f.y)) * (1.0 - topFace); 1694 1695 float shape = height; 1696 if (u_isoPattern == 1) { 1697 shape = mix(height, steps, 0.65); 1698 } else if (u_isoPattern == 2) { 1699 shape = mix(height, steps * 1.12, 0.9); 1700 } else if (u_isoPattern == 3) { 1701 shape = mix(height, prism * 1.05, 0.7); 1702 } else if (u_isoPattern == 4) { 1703 shape = mix(height, hexMask * (0.3 + steps * 0.9), 0.82); 1704 } else if (u_isoPattern == 5) { 1705 shape = mix(height, weave * 0.9 + prism * 0.25, 0.76); 1706 } else if (u_isoPattern == 6) {
1707 shape = mix(height, circuit * 1.04 + steps * 0.32, 0.84); 1708 } else if (u_isoPattern == 7) { 1709 shape = mix(height, skyline * (0.55 + u_relief * 0.75), 0.88); 1710 } 1711 1712 vec2 dir = vec2(cos(radians(u_direction)), sin(radians(u_direction))); 1713 float t = dot(uv - 0.5, dir) + 0.5; 1714 t += (shape - 0.5) * 0.35; 1715 t += cellDrift * 0.06; 1716 t = clamp(t, 0.0, 1.0); 1717 1718 // Image-driven gradient integration 1719 float imgLum = imageLuminance(uv, aspect); 1720 if (imgLum >= 0.0) { 1721 t = mix(t, imgLum, u_imageIntensity); 1722 } 1723 1724 vec3 base = mixColors(u_colors, u_colorPositions, u_colorCount, t); 1725 vec3 bright = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(t + 0.18, 0.0, 1.0)); 1726 vec3 dark = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(t - 0.2, 0.0, 1.0)); 1727 1728 vec3 color = base; 1729 1730 if (u_isoPattern == 1) { 1731 color = topFace * mix(base, bright, 0.34) 1732 + leftFace * mix(dark, base, 0.24) 1733 + rightFace * mix(base, bright, 0.16); 1734 } else if (u_isoPattern == 2) { 1735 float stair = fract((id.x + id.y) * 0.5 + hash); 1736 color = mix(dark, bright, stair); 1737 } else if (u_isoPattern == 3) { 1738 color = mix(dark, bright, clamp(prism + 0.25, 0.0, 1.0)); 1739 } else if (u_isoPattern == 4) { 1740 color = mix(dark, bright, clamp(hexMask * 0.7 + steps * 0.2, 0.0, 1.0)); 1741 } else if (u_isoPattern == 5) { 1742 color = mix(dark, bright, weave); 1743 color = mix(color, base, prism * 0.25); 1744 } else if (u_isoPattern == 6) { 1745 color = mix(dark, base, 0.62); 1746 color += bright * circuit * (0.25 + u_glow * 0.28); 1747 } else if (u_isoPattern == 7) { 1748 color = mix(dark, bright, skyline); 1749 color = mix(color, base, 0.35 + 0.35 * prism); 1750 } 1751 1752 float gridA = abs(fract(g.x + g.y) - 0.5); 1753 float gridB = abs(fract(g.x - g.y) - 0.5); 1754 float gridC = abs(fract(g.y * 2.0) - 0.5); 1755 float gridDist = min(min(gridA, gridB), gridC); 1756 float lineWidth = mix(0.035, 0.006, u_lineThickness); 1757 float aa = fwidth(gridDist) * 1.5 + 0.002; 1758 float line = 1.0 - smoothstep(lineWidth + aa, lineWidth + aa * 3.0, gridDist); 1759 1760 if (u_isoPattern == 4) { 1761 float hx = abs(fract((g.x + g.y * 0.5) * 0.5) - 0.5); 1762 float hy = abs(fract((g.x - g.y * 0.5) * 0.5) - 0.5); 1763 float hLine = 1.0 - smoothstep(lineWidth + aa, lineWidth + aa * 3.2, min(hx, hy)); 1764 line = max(line * 0.6, hLine); 1765 } else if (u_isoPattern == 5) { 1766 line = mix(line, weave, 0.35); 1767 } else if (u_isoPattern == 6) { 1768 line = max(line * 0.55, circuit); 1769 } else if (u_isoPattern == 7) { 1770 line = max(line * 0.5, smoothstep(0.45, 0.9, skyline) * 0.75); 1771 } 1772 1773 vec3 lineColor = mix(dark, bright, 0.55); 1774 color = mix(color, lineColor, line * (0.22 + u_lineThickness * 0.65)); 1775 1776 float patternMask = (u_isoPattern == 4) ? hexMask : tileMask; 1777 float glow = line * (0.08 + u_glow * 0.42) * patternMask; 1778 color += bright * glow; 1779 1780 float vignette = smoothstep(0.34, 0.96, length((uv - 0.5) * vec2(1.1, 1.18))); 1781 color *= 1.0 - vignette * 0.5; 1782 1783 color = mix(vec3(0.0), color, patternMask + (1.0 - patternMask) * 0.18); 1784 color += grain(uv, time, u_grain * 0.72); 1785 1786 // Self-blend 1787 if (u_blendMode > 0) { 1788 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 1789 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 1790 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 1791 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 1792 bIntensity = applyBlendFalloff(bIntensity, uv.x, u_blendFalloff); 1793 float tB = blendLayerT(uv, 0.5, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 1794 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 1795 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 1796 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 1797 float tB2 = blendLayerT(uv, 0.5, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 1798 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 1799 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 1800 } 1801 } 1802 1803 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 1804} 1805`,d=`#version 300 es 1806precision highp float; 1807 1808in vec2 vUv; 1809out vec4 fragColor; 1810 1811uniform float u_time; 1812uniform float u_speed; 1813uniform vec3 u_colors[12]; 1814uniform float u_colorPositions[12]; 1815uniform int u_colorCount; 1816uniform float u_direction; 1817uniform float u_grain; 1818uniform vec2 u_resolution; 1819 1820// Blend uniforms 1821uniform int u_blendMode; 1822uniform float u_blendIntensity; 1823uniform float u_blendOffset; 1824uniform float u_blendRotation; 1825uniform float u_blendScale; 1826uniform int u_blendAnimRotation; 1827uniform int u_blendAnimIntensity; 1828uniform int u_blendAnimOffset; 1829uniform float u_blendAnimSpeed; 1830uniform float u_blendNoiseMask; 1831uniform float u_blendNoiseScale; 1832uniform float u_blendFalloff; 1833uniform int u_blendDualLayer; 1834uniform int u_blendMode2; 1835uniform float u_blendIntensity2; 1836uniform float u_blendOffset2; 1837uniform float u_blendRotation2; 1838uniform float u_blendScale2; 1839 1840uniform float u_terrainScale; 1841uniform float u_relief; 1842uniform int u_hudPattern; 1843uniform float u_contourDensity; 1844uniform float u_gridStrength; 1845uniform float u_wireframe; 1846uniform float u_scanlineStrength; 1847uniform float u_fogDepth; 1848uniform float u_tilt; 1849uniform float u_horizon; 1850uniform float u_markerGlow; 1851uniform int u_terrainStyle; 1852uniform int u_qualityTier; 1853 1854__COMMON__ 1855 1856// âââ Hash helpers ââââââââââââââââââââââââââââââââââââââââââââ 1857float hash21(vec2 p) { 1858 p = fract(p * vec2(123.34, 456.21)); 1859 p += dot(p, p + 45.32); 1860 return fract(p.x * p.y); 1861} 1862 1863// âââ Terrain height functions per style ââââââââââââââââââââââ 1864 1865// Style 0: Mountains â ridged multi-fractal with domain warping 1866float terrainMountains(vec2 p, float time, float freq) { 1867 vec2 warp = vec2( 1868 snoise(p * freq * 0.4 + vec2(time * 0.015, 0.0)), 1869 snoise(p * freq * 0.4 + vec2(0.0, time * 0.012)) 1870 ); 1871 vec2 wp = p + warp * 0.35; 1872 float base = fbm(wp * freq + vec2(time * 0.02, -time * 0.015), 1.0, 5, 0.58, 2.05); 1873 float ridgeVal = 0.0; 1874 float ridgeFreq = freq * 1.8; 1875 float ridgeAmp = 0.5; 1876 vec2 rp = wp + vec2(time * 0.008, time * 0.006); 1877 for (int i = 0; i < 4; i++) { 1878 float n = 1.0 - abs(snoise(rp * ridgeFreq)); 1879 n = n * n; 1880 ridgeVal += n * ridgeAmp; 1881 ridgeFreq *= 2.1; 1882 ridgeAmp *= 0.48; 1883 rp *= 2.1; 1884 rp += vec2(1.7, 1.3); 1885 } 1886 return base * 0.5 + ridgeVal * 0.5; 1887} 1888 1889// Style 1: Dunes â smooth rolling shapes with wind-sculpted asymmetry 1890float terrainDunes(vec2 p, float time, float freq) { 1891 float windAngle = time * 0.005; 1892 vec2 windDir = vec2(cos(windAngle), sin(windAngle)); 1893 vec2 wp = p + windDir * time * 0.04; 1894 float dune1 = sin(dot(wp, vec2(0.8, 0.6)) * freq * 1.5 + snoise(wp * freq * 0.3) * 2.0); 1895 float dune2 = sin(dot(wp, vec2(0.3, 0.95)) * freq * 2.2 + snoise(wp * freq * 0.5 + 5.0) * 1.5); 1896 float ripple = snoise(wp * freq * 4.0 + vec2(time * 0.03)) * 0.15; 1897 float h = dune1 * 0.4 + dune2 * 0.3 + ripple; 1898 // Asymmetric windward shaping â sharpen one side 1899 h = h * 0.5 + 0.5; 1900 h = pow(h, 0.7 + 0.6 * smoothstep(-0.2, 0.3, dot(normalize(vec2(dune1, dune2)), windDir))); 1901 return h; 1902} 1903 1904// Style 2: Canyons â deep cuts with plateaus and sharp valleys 1905float terrainCanyons(vec2 p, float time, float freq) { 1906 vec2 wp = p + vec2(time * 0.015, -time * 0.01); 1907 float base = fbm(wp * freq * 0.6, 1.0, 4, 0.55, 2.1); 1908 // Plateau clamping â flatten the tops, keep deep cuts 1909 float plateau = smoothstep(0.3, 0.6, base); 1910 // Sharp canyon cracks 1911 float crack = abs(snoise(wp * freq * 1.2 + vec2(3.7))); 1912 crack = smoothstep(0.0, 0.15, crack); // sharp edge 1913 float detail = snoise(wp * freq * 3.0) * 0.1; 1914 float h = mix(base * 0.3, plateau * 0.8, 0.6) * crack + detail; 1915 // Terracing effect 1916 float terraced = floor(h * 6.0) / 6.0; 1917 h = mix(h, terraced, 0.4); 1918 return h; 1919} 1920 1921// Style 3: Volcanic â caldera craters with sharp rims and lava flows 1922float terrainVolcanic(vec2 p, float time, float freq) { 1923 vec2 wp = p + vec2(time * 0.01, time * 0.008); 1924 float base = fbm(wp * freq * 0.5, 1.0, 4, 0.6, 2.0); 1925 // Create crater shapes using distance from noise-positioned centers 1926 vec2 craterCenter = floor(wp * freq * 0.3) + 0.5; 1927 float craterR = length(fract(wp * freq * 0.3) - 0.5); 1928 float rim = smoothstep(0.25, 0.32, craterR) * smoothstep(0.45, 0.35, craterR); 1929 float caldera = smoothstep(0.22, 0.0, craterR) * 0.6; 1930 // Sharp volcanic ridges 1931 float ridge = 1.0 - abs(snoise(wp * freq * 1.5)); 1932 ridge = pow(ridge, 3.0) * 0.4; 1933 // Lava glow in low areas 1934 float h = base * 0.3 + rim * 0.7 - caldera + ridge; 1935 // Add heat shimmer displacement 1936 h += sin(p.x * freq * 8.0 + time * 2.0) * sin(p.y * freq * 8.0 + time * 1.7) * 0.02; 1937 return clamp(h, 0.0, 1.5); 1938} 1939 1940// Style 4: Ocean â animated wave surface with swells and chop 1941float terrainOcean(vec2 p, float time, float freq) { 1942 vec2 wp = p; 1943 // Large swells 1944 float swell1 = sin(dot(wp, vec2(0.7, 0.3)) * freq * 1.2 + time * 0.8) * 0.35; 1945 float swell2 = sin(dot(wp, vec2(-0.4, 0.9)) * freq * 0.9 + time * 0.6) * 0.25; 1946 float swell3 = sin(dot(wp, vec2(0.9, -0.5)) * freq * 1.6 + time * 1.1) * 0.15; 1947 // Wind chop â higher frequency detail 1948 float chop = snoise(wp * freq * 3.0 + vec2(time * 0.4, time * 0.3)) * 0.12; 1949 float chop2 = snoise(wp * freq * 6.0 + vec2(-time * 0.5, time * 0.6)) * 0.05; 1950 float h = swell1 + swell2 + swell3 + chop + chop2; 1951 h = h * 0.5 + 0.35; // bias up so water surface is visible 1952 return h; 1953} 1954 1955// Style 5: Glacial â smooth ice shelf with crevasse lines 1956float terrainGlacial(vec2 p, float time, float freq) { 1957 vec2 wp = p + vec2(time * 0.005, -time * 0.003); 1958 // Very smooth base â low octave, high persistence for gentle undulation 1959 float base = fbm(wp * freq * 0.4, 1.0, 3, 0.7, 1.8); 1960 base = base * base; // extra smoothing by squaring 1961 // Crevasse lines â sharp cracks in the ice 1962 float crv1 = abs(snoise(wp * freq * 1.0 + vec2(2.3, 4.1))); 1963 float crv2 = abs(snoise(wp * freq * 1.5 + vec2(7.1, 1.3))); 1964 float crevasse = min(crv1, crv2); 1965 crevasse = smoothstep(0.0, 0.08, crevasse); // sharp edges 1966 // Seracs â pressure ridges 1967 float ridge = pow(1.0 - abs(snoise(wp * freq * 0.7)), 4.0) * 0.3; 1968 float h = base * 0.6 + ridge; 1969 h *= crevasse; // cut crevasses into surface 1970 // Subtle ice crystal shimmer 1971 h += sin(p.x * freq * 20.0 + p.y * freq * 15.0) * 0.005; 1972 return h * 0.8 + 0.1; 1973} 1974 1975// âââ Dispatch to active terrain style ââââââââââââââââââââââââ 1976float terrainHeight(vec2 p) { 1977 float time = u_time * u_speed; 1978 float freq = 0.6 + u_terrainScale * 0.8; 1979 float h; 1980 if (u_terrainStyle == 1) { 1981 h = terrainDunes(p, time, freq); 1982 } else if (u_terrainStyle == 2) { 1983 h = terrainCanyons(p, time, freq); 1984 } else if (u_terrainStyle == 3) { 1985 h = terrainVolcanic(p, time, freq); 1986 } else if (u_terrainStyle == 4) { 1987 h = terrainOcean(p, time, freq); 1988 } else if (u_terrainStyle == 5) { 1989 h = terrainGlacial(p, time, freq); 1990 } else { 1991 h = terrainMountains(p, time, freq); 1992 } 1993 float amplitude = 0.2 + u_relief * 1.8; 1994 return h * amplitude; 1995} 1996 1997// âââ Normal via central differences ââââââââââââââââââââââââââ 1998vec3 terrainNormal(vec2 p, float eps) { 1999 float hc = terrainHeight(p);
2000 float hx = terrainHeight(p + vec2(eps, 0.0)); 2001 float hz = terrainHeight(p + vec2(0.0, eps)); 2002 return normalize(vec3(hc - hx, eps, hc - hz)); 2003} 2004 2005// âââ Ray-terrain intersection ââââââââââââââââââââââââââââââââ 2006// March a ray against the heightfield. Returns (distance, height) or (-1, 0) on miss. 2007vec2 rayMarchTerrain(vec3 ro, vec3 rd, int maxSteps, float maxDist) { 2008 float dt = maxDist / float(maxSteps); 2009 float t = 0.01; 2010 float lastH = 0.0; 2011 float lastY = ro.y; 2012 2013 for (int i = 0; i < 128; i++) { // loop ceiling â actual steps limited by maxSteps 2014 if (i >= maxSteps) break; 2015 vec3 p = ro + rd * t; 2016 float h = terrainHeight(p.xz); 2017 2018 if (p.y < h) { 2019 // Binary refinement â 6 steps 2020 float tA = t - dt; 2021 float tB = t; 2022 for (int j = 0; j < 6; j++) { 2023 float tM = (tA + tB) * 0.5; 2024 vec3 pm = ro + rd * tM; 2025 float hm = terrainHeight(pm.xz); 2026 if (pm.y < hm) { 2027 tB = tM; 2028 } else { 2029 tA = tM; 2030 } 2031 } 2032 t = (tA + tB) * 0.5; 2033 vec3 hitP = ro + rd * t; 2034 return vec2(t, terrainHeight(hitP.xz)); 2035 } 2036 2037 // Adaptive step size: step bigger when far above terrain 2038 float aboveGround = p.y - h; 2039 dt = max(0.004, min(aboveGround * 0.6, maxDist / float(maxSteps))); 2040 t += dt; 2041 2042 if (t > maxDist) break; 2043 lastH = h; 2044 lastY = p.y; 2045 } 2046 return vec2(-1.0, 0.0); 2047} 2048 2049// âââ Soft shadows ââââââââââââââââââââââââââââââââââââââââââââ 2050float softShadow(vec3 ro, vec3 lightDir, int steps, float maxDist, float k) { 2051 float res = 1.0; 2052 float t = 0.02; 2053 float dt = maxDist / float(steps); 2054 for (int i = 0; i < 32; i++) { 2055 if (i >= steps) break; 2056 vec3 p = ro + lightDir * t; 2057 float h = terrainHeight(p.xz); 2058 float d = p.y - h; 2059 if (d < 0.001) return 0.0; 2060 res = min(res, k * d / t); 2061 t += max(dt, d * 0.4); 2062 if (t > maxDist) break; 2063 } 2064 return clamp(res, 0.0, 1.0); 2065} 2066 2067// âââ Ambient occlusion ââââââââââââââââââââââââââââââââââââââ 2068float ambientOcclusion(vec3 pos, vec3 normal) { 2069 float ao = 0.0; 2070 float weight = 1.0; 2071 for (int i = 1; i <= 4; i++) { 2072 float dist = float(i) * 0.08; 2073 vec3 samplePos = pos + normal * dist; 2074 float h = terrainHeight(samplePos.xz); 2075 float diff = samplePos.y - h; 2076 ao += weight * clamp(diff / dist, 0.0, 1.0); 2077 weight *= 0.6; 2078 } 2079 return clamp(ao / 1.92, 0.0, 1.0); 2080} 2081 2082// âââ HUD Overlay Functions âââââââââââââââââââââââââââââââââââ 2083 2084// Pattern 0: Wiregrid â world-space grid lines on terrain 2085float hudWiregrid(vec2 worldPos, float dist) { 2086 float gridScale = mix(4.0, 30.0, u_gridStrength); 2087 vec2 gUV = worldPos * gridScale; 2088 float gx = abs(fract(gUV.x) - 0.5); 2089 float gy = abs(fract(gUV.y) - 0.5); 2090 float gxAA = fwidth(gUV.x) * 0.8 + 0.01; 2091 float gyAA = fwidth(gUV.y) * 0.8 + 0.01; 2092 float wireX = 1.0 - smoothstep(0.015 + gxAA, 0.06 + gxAA * 2.0, gx); 2093 float wireY = 1.0 - smoothstep(0.015 + gyAA, 0.06 + gyAA * 2.0, gy); 2094 float wire = max(wireX, wireY); 2095 // Fade with distance 2096 wire *= smoothstep(20.0, 2.0, dist); 2097 return wire * u_wireframe; 2098} 2099 2100// Pattern 1: Contours â height-based contour lines 2101float hudContours(float height) { 2102 float contourScale = mix(8.0, 80.0, u_contourDensity); 2103 float contourField = height * contourScale; 2104 float contour = abs(fract(contourField) - 0.5); 2105 float contourAA = fwidth(contourField) * 0.8 + 0.015; 2106 float contourLine = 1.0 - smoothstep(0.06 + contourAA, 0.14 + contourAA * 2.0, contour); 2107 return contourLine; 2108} 2109 2110// Pattern 2: Topography â major/minor contour lines with elevation bands 2111float hudTopography(float height, vec2 worldPos) { 2112 float contourScale = mix(6.0, 60.0, u_contourDensity); 2113 2114 // Minor contour lines 2115 float minorField = height * contourScale; 2116 float minorContour = abs(fract(minorField) - 0.5); 2117 float minorAA = fwidth(minorField) * 0.8 + 0.01; 2118 float minorLine = 1.0 - smoothstep(0.06 + minorAA, 0.15 + minorAA * 2.0, minorContour); 2119 2120 // Major contour lines (every 5th) 2121 float majorField = height * contourScale * 0.2;
2122 float majorContour = abs(fract(majorField) - 0.5); 2123 float majorAA = fwidth(majorField) * 0.8 + 0.01; 2124 float majorLine = 1.0 - smoothstep(0.04 + majorAA, 0.10 + majorAA * 2.0, majorContour); 2125 2126 return minorLine * 0.5 + majorLine * 1.2; 2127} 2128 2129// Pattern 3: Sonar â animated concentric rings with fading trail sweep 2130float hudSonar(vec2 worldPos, float time) { 2131 vec2 center = worldPos - vec2(0.0, 2.0); 2132 float r = length(center); 2133 float ringSpacing = mix(0.5, 2.5, u_contourDensity); 2134 2135 // Concentric rings expanding outward â clear line rings 2136 float ringField = (r - time * 0.4) / ringSpacing; 2137 float rings = abs(fract(ringField) - 0.5); 2138 float ringsAA = fwidth(ringField) * 0.8 + 0.01; 2139 float ringLine = 1.0 - smoothstep(0.04 + ringsAA, 0.10 + ringsAA * 2.0, rings); 2140 // Fade rings with distance 2141 ringLine *= smoothstep(15.0, 1.0, r); 2142 2143 // Sweep beam â wide angular fade, not a point 2144 float angle = atan(center.y, center.x); 2145 float sweepAngle = time * 1.2; 2146 float angleDiff = mod(angle - sweepAngle, 6.2831853); 2147 // Wide trailing glow arc (120 degrees = ~2.09 rad) 2148 float sweep = smoothstep(2.1, 0.0, angleDiff) * smoothstep(6.28, 5.0, angleDiff); 2149 sweep *= smoothstep(12.0, 0.5, r) * 0.4; 2150 2151 return ringLine * 0.8 + sweep; 2152} 2153 2154// Pattern 4: Ridgeflow â flow lines following terrain gradient 2155float hudRidgeflow(vec2 worldPos, float height, float time) { 2156 float eps = 0.05; 2157 float hx = terrainHeight(worldPos + vec2(eps, 0.0)); 2158 float hz = terrainHeight(worldPos + vec2(0.0, eps)); 2159 vec2 gradient = vec2(height - hx, height - hz) / eps; 2160 float gradLen = length(gradient); 2161 2162 // Flow line via directional pattern 2163 float flowField = dot(worldPos, normalize(gradient + vec2(0.001))) * mix(3.0, 20.0, u_contourDensity); 2164 flowField += time * 0.3; 2165 float flow = abs(fract(flowField) - 0.5); 2166 float flowAA = fwidth(flowField) * 0.8 + 0.01; 2167 float flowLine = 1.0 - smoothstep(0.06 + flowAA, 0.14 + flowAA * 2.0, flow); 2168 2169 // Stronger on steep slopes 2170 flowLine *= smoothstep(0.01, 0.15, gradLen); 2171 2172 // Dashed pattern 2173 float dash = smoothstep(0.45, 0.55, fract(flowField * 0.15 - time * 0.2)); 2174 flowLine *= dash; 2175 2176 return flowLine; 2177} 2178 2179void main() { 2180 vec2 uv = vUv; 2181 float time = u_time * u_speed; 2182 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 2183 uv = applyMouseWarp(uv, aspect); 2184 2185 // ââ Quality-adaptive step counts ââ 2186 int marchSteps = u_qualityTier == 0 ? 32 : u_qualityTier == 1 ? 48 : u_qualityTier == 2 ? 64 : 80; 2187 int shadowSteps = u_qualityTier == 0 ? 0 : u_qualityTier == 1 ? 4 : u_qualityTier == 2 ? 8 : 12; 2188 2189 // ââ Camera setup ââ 2190 float camHeight = 0.8 + u_horizon * 3.0; 2191 float camPitch = mix(-0.25, -0.85, u_tilt); 2192 2193 vec3 ro = vec3(time * 0.15, camHeight, time * 0.08); 2194 vec3 forward = normalize(vec3(0.0, camPitch, 1.0)); 2195 vec3 right = normalize(cross(forward, vec3(0.0, 1.0, 0.0))); 2196 vec3 up = cross(right, forward); 2197 2198 float fov = 1.2; 2199 vec2 screenUV = (uv - 0.5) * vec2(aspect, 1.0) * fov; 2200 vec3 rd = normalize(forward + screenUV.x * right + screenUV.y * up); 2201 2202 float maxDist = 25.0; 2203 2204 // ââ Raymarch terrain ââ 2205 vec2 hit = rayMarchTerrain(ro, rd, marchSteps, maxDist); 2206 2207 // ââ Sky color (above horizon / miss) ââ 2208 vec3 skyLow = mixColors(u_colors, u_colorPositions, u_colorCount, 0.0); 2209 vec3 skyHigh = mixColors(u_colors, u_colorPositions, u_colorCount, 0.15); 2210 vec3 skyColor = mix(skyLow, skyHigh, clamp(rd.y * 2.0 + 0.5, 0.0, 1.0)) * 0.15; 2211 2212 // Horizon glow in sky 2213 float horizonGlow = exp(-pow(rd.y * 8.0, 2.0)); 2214 vec3 glowColor = mixColors(u_colors, u_colorPositions, u_colorCount, 0.85); 2215 skyColor += glowColor * horizonGlow * (0.06 + u_markerGlow * 0.2); 2216 2217 vec3 color; 2218 float dist = maxDist; 2219 2220 if (hit.x < 0.0) { 2221 // No terrain hit â render sky 2222 color = skyColor; 2223 } else { 2224 dist = hit.x; 2225 vec3 hitPos = ro + rd * dist; 2226 float h = hit.y; 2227 2228 // ââ Normal computation ââ 2229 float normalEps = max(0.005, dist * 0.002); 2230 vec3 normal = terrainNormal(hitPos.xz, normalEps); 2231 2232 // ââ Lighting ââ 2233 float lightAngle = radians(u_direction); 2234 vec3 lightDir = normalize(vec3(cos(lightAngle) * 0.7, 0.55, sin(lightAngle) * 0.7)); 2235 2236 // Diffuse 2237 float diff = max(dot(normal, lightDir), 0.0); 2238 2239 // Specular (Blinn-Phong) 2240 vec3 viewDir = -rd; 2241 vec3 halfVec = normalize(lightDir + viewDir); 2242 float spec = pow(max(dot(normal, halfVec), 0.0), 64.0); 2243 2244 // Soft shadows 2245 float shadow = 1.0; 2246 if (shadowSteps > 0) { 2247 shadow = softShadow(hitPos + normal * 0.02, lightDir, shadowSteps, 6.0, 12.0); 2248 } 2249 2250 // Ambient occlusion 2251 float ao = ambientOcclusion(hitPos, normal); 2252 2253 // ââ Color from palette mapped to height + slope ââ 2254 float slope = 1.0 - normal.y; // 0 = flat, 1 = cliff 2255 float heightNorm = clamp(h / (0.2 + u_relief * 1.8), 0.0, 1.0); 2256 float colorT = heightNorm * 0.75 + slope * 0.25; 2257 colorT = clamp(colorT, 0.0, 1.0); 2258 2259 // Image-driven gradient integration 2260 float imgLum = imageLuminance(gl_FragCoord.xy / u_resolution.xy, aspect); 2261 if (imgLum >= 0.0) { 2262 colorT = mix(colorT, imgLum, u_imageIntensity); 2263 } 2264 2265 vec3 baseColor = mixColors(u_colors, u_colorPositions, u_colorCount, colorT); 2266 vec3 darkColor = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(colorT - 0.25, 0.0, 1.0)); 2267 vec3 lightColor = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(colorT + 0.2, 0.0, 1.0)); 2268 2269 // Compose lighting 2270 float ambient = 0.2; 2271 vec3 litColor = baseColor * (ambient + diff * shadow * 0.7); 2272 litColor += lightColor * spec * shadow * 0.35; 2273 litColor *= (0.5 + ao * 0.5); 2274 2275 // Rim/fresnel for edge highlights 2276 float fresnel = pow(1.0 - max(dot(normal, viewDir), 0.0), 3.0); 2277 litColor += lightColor * fresnel * 0.12; 2278 2279 color = litColor; 2280 2281 // ââ HUD Overlay ââ 2282 float hudValue = 0.0; 2283 vec3 hudColor = lightColor; 2284 2285 if (u_hudPattern == 0) {
2286 // Wiregrid 2287 hudValue = hudWiregrid(hitPos.xz, dist); 2288 } else if (u_hudPattern == 1) { 2289 // Contours 2290 hudValue = hudContours(h) * (0.3 + u_contourDensity * 0.7); 2291 } else if (u_hudPattern == 2) { 2292 // Topography 2293 hudValue = hudTopography(h, hitPos.xz) * (0.25 + u_contourDensity * 0.6); 2294 } else if (u_hudPattern == 3) { 2295 // Sonar 2296 hudValue = hudSonar(hitPos.xz, time) * (0.3 + u_gridStrength * 0.5); 2297 } else if (u_hudPattern == 4) { 2298 // Ridgeflow 2299 hudValue = hudRidgeflow(hitPos.xz, h, time) * (0.3 + u_gridStrength * 0.5); 2300 } 2301 2302 color += hudColor * hudValue * 0.2; 2303 2304 // Additional wireframe overlay (global, per gridStrength) 2305 if (u_hudPattern != 0) { 2306 float wireOverlay = hudWiregrid(hitPos.xz, dist) * 0.35; 2307 color += hudColor * wireOverlay * u_gridStrength; 2308 } 2309 2310 // ââ Fog ââ 2311 float fogFactor = 1.0 - exp(-dist * (0.03 + u_fogDepth * 0.12)); 2312 vec3 fogColor = mix(darkColor, vec3(0.02, 0.03, 0.05), 0.7); 2313 fogColor += glowColor * horizonGlow * (0.03 + u_markerGlow * 0.1); 2314 color = mix(color, fogColor, fogFactor); 2315 } 2316 2317 // ââ Horizon atmosphere band ââ 2318 // Replaces dot markers with an atmospheric glow band at the horizon 2319 // that pulses and shifts with the palette, controlled by u_markerGlow 2320 if (u_markerGlow > 0.01) { 2321 float horizBand = exp(-pow((uv.y - 0.35) * 6.0, 2.0)); 2322 float pulse = 0.7 + 0.3 * sin(time * 0.8); 2323 vec3 atmColor = mixColors(u_colors, u_colorPositions, u_colorCount, 0.7 + 0.15 * sin(time * 0.3)); 2324 color += atmColor * horizBand * u_markerGlow * pulse * 0.25; 2325 2326 // Subtle animated light streaks at horizon 2327 float streak1 = exp(-pow((uv.y - 0.33 + sin(uv.x * 4.0 + time * 0.5) * 0.03) * 14.0, 2.0)); 2328 float streak2 = exp(-pow((uv.y - 0.37 + sin(uv.x * 6.0 - time * 0.4) * 0.02) * 18.0, 2.0)); 2329 vec3 streakColor = mixColors(u_colors, u_colorPositions, u_colorCount, 0.9); 2330 color += streakColor * (streak1 + streak2) * u_markerGlow * 0.1; 2331 } 2332 2333 // ââ Scanlines ââ 2334 float scan = sin(uv.y * u_resolution.y * 0.9 + time * 3.0) * 0.5 + 0.5; 2335 float scanStrength = u_scanlineStrength * (u_hudPattern == 3 ? 1.2 : 1.0); 2336 color *= mix(1.0, 0.82 + scan * 0.18, clamp(scanStrength, 0.0, 1.0)); 2337 2338 // ââ Vignette ââ 2339 float vignette = smoothstep(0.35, 0.97, length((uv - 0.5) * vec2(1.12, 1.18))); 2340 color *= 1.0 - vignette * 0.55; 2341 2342 // ââ Grain (only when explicitly set, no default noise for terrain) ââ 2343 if (u_grain > 0.001) { 2344 color += grain(uv, time, u_grain); 2345 } 2346 2347 // ââ Self-blend ââ 2348 if (u_blendMode > 0) { 2349 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 2350 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 2351 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 2352 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 2353 bIntensity = applyBlendFalloff(bIntensity, uv.x, u_blendFalloff); 2354 float tB = blendLayerT(uv, 0.5, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 2355 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 2356 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 2357 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 2358 float tB2 = blendLayerT(uv, 0.5, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 2359 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 2360 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 2361 } 2362 } 2363 2364 fragColor = outputColor(color, gl_FragCoord.xy, 1.15); 2365} 2366`,m=`#version 300 es 2367precision highp float; 2368 2369in vec2 vUv; 2370out vec4 fragColor; 2371 2372uniform float u_time; 2373uniform float u_speed; 2374uniform vec3 u_colors[12]; 2375uniform float u_colorPositions[12]; 2376uniform int u_colorCount; 2377uniform float u_direction; 2378uniform float u_grain; 2379uniform vec2 u_resolution; 2380 2381// Blend uniforms 2382uniform int u_blendMode; 2383uniform float u_blendIntensity; 2384uniform float u_blendOffset; 2385uniform float u_blendRotation; 2386uniform float u_blendScale; 2387uniform int u_blendAnimRotation; 2388uniform int u_blendAnimIntensity; 2389uniform int u_blendAnimOffset; 2390uniform float u_blendAnimSpeed; 2391uniform float u_blendNoiseMask; 2392uniform float u_blendNoiseScale; 2393uniform float u_blendFalloff; 2394uniform int u_blendDualLayer; 2395uniform int u_blendMode2; 2396uniform float u_blendIntensity2; 2397uniform float u_blendOffset2; 2398uniform float u_blendRotation2; 2399uniform float u_blendScale2; 2400 2401uniform float u_beamWidth; 2402uniform float u_beamSoftness; 2403uniform float u_beamIntensity; 2404uniform float u_beamCount; 2405uniform float u_beamSpread; 2406uniform float u_secondaryIntensity; 2407uniform int u_pattern; 2408uniform float u_patternDrift; 2409uniform float u_glow; 2410uniform float u_drift; 2411uniform float u_vignette; 2412uniform float u_falloff; 2413uniform float u_halo; 2414 2415__COMMON__ 2416 2417float lineDistance(vec2 p, vec2 dir) { 2418 return dot(p, vec2(-dir.y, dir.x)); 2419} 2420 2421mat2 rot2(float a) { 2422 float s = sin(a); 2423 float c = cos(a); 2424 return mat2(c, -s, s, c); 2425} 2426 2427void main() { 2428 vec2 uv = vUv; 2429 float time = u_time * u_speed; 2430 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 2431 uv = applyMouseWarp(uv, aspect); 2432 2433 vec2 p = uv - 0.5; 2434 p.x *= aspect; 2435 2436 float angle = radians(u_direction); 2437 vec2 dir = normalize(vec2(cos(angle), sin(angle))); 2438 vec2 ortho = vec2(-dir.y, dir.x); 2439 2440 // Base domain warp to avoid static/flat beams. 2441 float driftNoise = snoise(p * 2.7 + vec2(time * 0.18, -time * 0.13)); 2442 float driftWave = sin(dot(p, ortho) * 9.0 + time * 0.7); 2443 vec2 warped = p + ortho * driftNoise * u_drift * 0.06 + dir * driftWave * u_drift * 0.025; 2444 2445 float coreWidth = 0.002 + u_beamWidth * 0.045; 2446 float softWidth = coreWidth + 0.02 + u_beamSoftness * 0.2; 2447 float spreadPx = (0.02 + u_beamSpread * 0.32) * (0.75 + u_beamWidth * 0.6); 2448 2449 int beamCount = int(clamp(floor(u_beamCount + 0.5), 1.0, 6.0)); 2450 vec3 color = vec3(0.0); 2451 float envelope = 0.0; 2452 float mainCore = 0.0; 2453 float phase = time * (0.35 + u_patternDrift * 1.35); 2454 2455 for (int i = 0; i < 6; i++) { 2456 if (i >= beamCount) break; 2457 2458 float fi = float(i); 2459 float centered = fi - float(beamCount - 1) * 0.5; 2460 float norm = (beamCount > 1) ? centered / max(float(beamCount - 1), 1.0) : 0.0; 2461 2462 float angleOffset = 0.0; 2463 float lateral = centered * spreadPx; 2464 float axial = 0.0; 2465 2466 if (u_pattern == 1) { 2467 // Parallel stack 2468 lateral += sin(phase + centered * 1.9) * (0.01 + 0.06 * u_patternDrift); 2469 } else if (u_pattern == 2) { 2470 // Cross-light composition 2471 float signV = centered == 0.0 ? (mod(fi, 2.0) == 0.0 ? -1.0 : 1.0) : sign(centered); 2472 angleOffset = signV * mix(0.08, 0.72, u_beamSpread) * (0.35 + abs(norm)); 2473 lateral *= 0.55; 2474 } else if (u_pattern == 3) { 2475 // Fan spread 2476 angleOffset = norm * mix(0.08, 0.9, u_beamSpread); 2477 lateral *= 0.62; 2478 } else if (u_pattern == 4) { 2479 // Interference / moire beam weave
2480 angleOffset = sin(phase * 0.55 + norm * 9.0) * (0.08 + 0.35 * u_beamSpread); 2481 lateral += sin((dot(warped, ortho) + norm * 2.8) * 6.0 + phase * 1.8) * (0.025 + 0.14 * u_beamSpread); 2482 axial += cos((dot(warped, dir) + norm * 3.4) * 4.2 + phase * 1.2) * 0.04 * u_patternDrift; 2483 } 2484 2485 vec2 beamDir = normalize(rot2(angleOffset) * dir); 2486 vec2 beamOrtho = vec2(-beamDir.y, beamDir.x); 2487 vec2 q = warped + beamOrtho * lateral + beamDir * axial; 2488 2489 float d = lineDistance(q, beamDir); 2490 float along = dot(q, beamDir); 2491 float core = exp(-pow(abs(d) / coreWidth, 1.35)); 2492 float soft = exp(-pow(abs(d) / softWidth, 1.05)); 2493 float halo = exp(-pow(abs(d) / (softWidth * 2.8 + 0.02), 0.9)); 2494 2495 float alongMaskA = smoothstep(-0.98, -0.18, along); 2496 float alongMaskB = 1.0 - smoothstep(0.32, 1.02, along); 2497 float alongMask = clamp(alongMaskA * alongMaskB, 0.0, 1.0); 2498 2499 float tBase = clamp(along * 0.5 + 0.5 + soft * 0.22 - halo * 0.1 + norm * 0.05, 0.0, 1.0); 2500 vec3 base = mixColors(u_colors, u_colorPositions, u_colorCount, tBase); 2501 vec3 warm = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(tBase + 0.16, 0.0, 1.0)); 2502 vec3 cool = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(tBase - 0.14, 0.0, 1.0)); 2503 2504 float weight = (i == 0) ? 1.0 : u_secondaryIntensity * exp(-abs(centered) * 0.42); 2505 float coreEnergy = core * (0.6 + 2.0 * u_beamIntensity); 2506 float softEnergy = soft * (0.48 + 0.7 * u_glow) * alongMask; 2507 float haloEnergy = halo * (0.15 + 0.48 * u_halo); 2508 2509 color += cool * haloEnergy * u_falloff * weight; 2510 color += base * softEnergy * weight; 2511 color += warm * coreEnergy * weight; 2512 color += vec3(1.0, 0.95, 0.88) * core * (0.18 + 0.95 * u_halo) * weight; 2513 2514 float lobeA = exp(-pow(abs(d - softWidth * 1.65) / (softWidth * 1.55 + 0.01), 2.0)); 2515 float lobeB = exp(-pow(abs(d + softWidth * 1.35) / (softWidth * 1.65 + 0.01), 2.0)); 2516 color += base * (lobeA * 0.13 + lobeB * 0.11) * u_glow * weight; 2517 2518 envelope += soft * alongMask * weight; 2519 mainCore = max(mainCore, core * weight); 2520 } 2521 2522 // Image-driven beam energy modulation 2523 float imgMask = imageLuminance(uv, aspect); 2524 if (imgMask >= 0.0) { 2525 color *= mix(1.0, imgMask, u_imageIntensity); 2526 } 2527 2528 float patternHighlight = smoothstep(0.22, 1.1, envelope); 2529 vec3 warmEdge = mixColors(u_colors, u_colorPositions, u_colorCount, 0.86); 2530 vec3 coolEdge = mixColors(u_colors, u_colorPositions, u_colorCount, 0.18); 2531 2532 // Corner halation and ambient haze. 2533 float cornerA = exp(-length((uv - vec2(0.18, 0.24)) * vec2(1.4, 1.0)) * 4.0); 2534 float cornerB = exp(-length((uv - vec2(0.82, 0.78)) * vec2(1.3, 1.0)) * 4.5); 2535 float haze = exp(-length(p * vec2(1.1, 0.9)) * 2.0); 2536 color += warmEdge * cornerA * (0.08 + 0.2 * patternHighlight) * u_glow; 2537 color += coolEdge * cornerB * (0.07 + 0.16 * patternHighlight) * u_glow; 2538 color += mix(coolEdge, warmEdge, 0.5) * haze * (0.04 + 0.14 * u_glow); 2539 color += vec3(1.0, 0.96, 0.9) * mainCore * (0.06 + 0.28 * u_halo); 2540 2541 // Strong vignette to keep a cinematic frame. 2542 float r = length((uv - 0.5) * vec2(1.15, 1.2)); 2543 float vignette = smoothstep(0.35, 0.95, r); 2544 color *= mix(1.0, 1.0 - 0.86 * vignette, u_vignette); 2545 2546 color += grain(uv, time, u_grain * (0.75 + 0.15 * patternHighlight)); 2547 2548 // Self-blend 2549 if (u_blendMode > 0) { 2550 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 2551 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 2552 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 2553 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 2554 bIntensity = applyBlendFalloff(bIntensity, uv.x, u_blendFalloff); 2555 float tB = blendLayerT(uv, 0.5, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 2556 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 2557 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 2558 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 2559 float tB2 = blendLayerT(uv, 0.5, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 2560 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 2561 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 2562 } 2563 } 2564 2565 fragColor = outputColor(color, gl_FragCoord.xy, 1.2); 2566} 2567`,_=`#version 300 es 2568precision highp float; 2569 2570in vec2 vUv; 2571out vec4 fragColor; 2572 2573/* -- Uniforms -------------------------------------------------- */ 2574uniform float u_time; 2575uniform float u_speed; 2576uniform float u_grain; 2577uniform vec2 u_resolution; 2578 2579// 4 anchor colors (sRGB, sorted dark -> light on CPU) 2580uniform vec3 u_colorA; // darkest -- base / trough shadows 2581uniform vec3 u_colorB; // dark-mid -- primary fill 2582uniform vec3 u_colorC; // light-mid-- accent color 2583uniform vec3 u_colorD; // lightest -- glow, rim, specular 2584 2585// Glass / flute controls 2586uniform float u_density; 2587uniform float u_ridgeAngle; 2588uniform float u_distortion; 2589uniform float u_blur; 2590uniform float u_dispersion; 2591uniform float u_gain; 2592uniform float u_vignette; 2593uniform float u_tone; 2594uniform float u_specIntensity; 2595uniform float u_ridgeShape;
2595 // 0=sine, 1=chevron, 2=square, 3=sawtooth 2596uniform float u_waviness; // 0 = perfectly straight, 2+ = wavy 2597uniform float u_transmission; // base brightness (glass transparency) 2598uniform float u_extraDistort; // extra refraction offset strength 2599uniform float u_noiseScale; // FBM noise frequency in background 2600uniform float u_animSpeed; // animation speed multiplier 2601uniform float u_surfaceRough; // surface grain / specular spread 2602uniform float u_envBoost; // glow / accent brightness 2603 2604/* -- Hash / noise / FBM ---------------------------------------- */ 2605 2606float hash12(vec2 p) { 2607 vec3 p3 = fract(vec3(p.xyx) * 0.1031); 2608 p3 += dot(p3, p3.yzx + 33.33); 2609 return fract((p3.x + p3.y) * p3.z); 2610} 2611 2612float noise(vec2 p) { 2613 vec2 i = floor(p); 2614 vec2 f = fract(p); 2615 float a = hash12(i); 2616 float b = hash12(i + vec2(1.0, 0.0)); 2617 float c = hash12(i + vec2(0.0, 1.0)); 2618 float d = hash12(i + vec2(1.0, 1.0)); 2619 vec2 u = f * f * (3.0 - 2.0 * f); 2620 return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y; 2621} 2622 2623float fbm(vec2 p) { 2624 float v = 0.0; 2625 float a = 0.5; 2626 for (int i = 0; i < 6; i++) { 2627 v += a * noise(p); 2628 p = p * 2.02 + vec2(11.7, 4.9); 2629 a *= 0.52; 2630 } 2631 return v; 2632} 2633
2634/* -- Scene color: FBM-warped 4-color field --------------------- */ 2635 2636vec3 sceneColor(vec2 uv) { 2637 float t = u_time * u_speed * 0.1 * u_animSpeed; 2638 float aspect = u_resolution.x / u_resolution.y; 2639 2640 vec2 p = uv; 2641 vec2 warp = vec2( 2642 fbm(p * 3.3 * u_noiseScale + vec2(t, -t * 0.55)), 2643 fbm(p * 3.1 * u_noiseScale + vec2(-t * 0.65, t * 0.7)) 2644 ); 2645 p += (warp - 0.5) * 0.44; 2646 2647 float n0 = fbm(p * 2.4 * u_noiseScale + vec2(t * 0.4, 0.0)); 2648 float n1 = fbm(p * 5.2 * u_noiseScale - vec2(0.0, t * 0.3)); 2649 float blend = smoothstep(0.1, 0.95, n0 * 0.7 + n1 * 0.5); 2650 2651 vec3 darkBase = u_colorA * 0.08; 2652 vec3 richB = u_colorB * 1.25; 2653 2654 vec3 col = mix(darkBase, richB, blend); 2655 col = mix(col, u_colorC * 1.15, smoothstep(0.25, 0.85, n1)); 2656 2657 float radial = length((p - 0.5) * vec2(aspect, 1.0)); 2658 float glow = pow(max(0.0, 1.0 - radial * 1.1), 2.0); 2659 col += u_colorD * glow * 0.45 * u_envBoost; 2660 2661 float beams = pow(max(0.0, sin((p.x * 1.2 + p.y * 0.9 + t * 0.9) * 6.28318)), 5.0); 2662 col += u_colorC * beams * 0.12 * u_envBoost; 2663 2664 return col; 2665} 2666 2667/* -- Main ------------------------------------------------------ */ 2668 2669void main() { 2670 vec2 uv = vUv; 2671 float aspect = u_resolution.x / u_resolution.y; 2672 2673 // 1. Rotate coordinates for diagonal flutes 2674 vec2 centered = (uv - 0.5) * vec2(aspect, 1.0); 2675 float ca = cos(u_ridgeAngle); 2676 float sa = sin(u_ridgeAngle); 2677 vec2 rot = vec2( 2678 ca * centered.x - sa * centered.y, 2679 sa * centered.x + ca * centered.y 2680 ); 2681 2682 // 2. Flute wave: shape x waviness 2683 float t = u_time * u_speed; 2684 float fractal = fbm(vec2(rot.x * 0.85, rot.y * 2.6 + t * 0.15)); 2685 float phase = rot.x * u_density * 6.2831853 + (fractal - 0.5) * u_waviness; 2686 2687 // Wave shape selection 2688 float rawWave, rawSlope; 2689 2690 if (u_ridgeShape < 0.5) { 2691 // Sine: classic smooth curves 2692 rawWave = sin(phase); 2693 rawSlope = cos(phase); 2694 } else if (u_ridgeShape < 1.5) { 2695 // Chevron: triangle wave -- sharp V-shaped ridges
2696 float triP = mod(phase / 6.2831853 + 0.25, 1.0); 2697 rawWave = 4.0 * abs(triP - 0.5) - 1.0; 2698 rawSlope = mix(4.0, -4.0, step(0.5, triP)); 2699 } else if (u_ridgeShape < 2.5) { 2700 // Square: flat ridges with hard clean edges 2701 rawWave = clamp(sin(phase) * 8.0, -1.0, 1.0); 2702 float edgeMask = max(0.0, 1.0 - rawWave * rawWave); 2703 rawSlope = cos(phase) * 8.0 * edgeMask; 2704 } else { 2705 // Sawtooth: Fourier series (7 harmonics) â one sharp edge per period 2706 rawWave = sin(phase) - sin(2.0*phase)/2.0 2707 + sin(3.0*phase)/3.0 - sin(4.0*phase)/4.0 2708 + sin(5.0*phase)/5.0 - sin(6.0*phase)/6.0 2709 + sin(7.0*phase)/7.0; 2710 rawWave *= 0.64; // 2/pi normalize to ~[-1,1] 2711 rawSlope = cos(phase) - cos(2.0*phase) 2712 + cos(3.0*phase) - cos(4.0*phase) 2713 + cos(5.0*phase) - cos(6.0*phase) 2714 + cos(7.0*phase); 2715 rawSlope *= 0.64; 2716 } 2717 2718 float sharpK = max(1.0, 10.0 / max(u_density, 1.0)); 2719 float wave = clamp(rawWave * sharpK, -1.0, 1.0); 2720 float slope = clamp(rawSlope * min(sharpK, 2.5), -1.0, 1.0); 2721 2722 // 3. Refraction + 9-tap anisotropic blur + dispersion 2723 vec2 axis = normalize(vec2(ca / aspect, sa)); 2724 vec2 tangent = normalize(vec2(-sa / aspect, ca)); 2725 2726 float wobble = sin(rot.y * 17.0 + t * 0.45 + fractal * 8.0) * 0.2 * min(u_waviness, 1.0); 2727 vec2 refractOffset = axis * (wave * u_distortion * 0.08 * (1.0 + u_extraDistort * 3.0) + wobble * 0.0025); 2728 2729 vec3 refracted = vec3(0.0); 2730 float total = 0.0; 2731 2732 float blurDensityScale = clamp(u_density / 8.0, 0.15, 1.0); 2733 float chromaDensityScale = clamp(u_density / 6.0, 0.25, 1.0); 2734 vec2 chroma = axis * (u_dispersion / u_resolution.y) * chromaDensityScale; 2735 2736 for (int i = -4; i <= 4; i++) { 2737 float fi = float(i); 2738 float w = 1.0 - abs(fi) / 5.4; 2739 vec2 blurStep = tangent * fi * (u_blur / u_resolution.y) * 0.82 * blurDensityScale; 2740 vec2 suv = uv + refractOffset + blurStep; 2741 2742 vec3 cr = sceneColor(suv + chroma); 2743 vec3 cg = sceneColor(suv); 2744 vec3 cb = sceneColor(suv - chroma); 2745 refracted += vec3(cr.r, cg.g, cb.b) * w; 2746 total += w; 2747 } 2748 refracted /= max(total, 0.0001); 2749 2750 // 4. Glass lighting 2751 vec3 N = normalize(vec3(-slope * u_distortion * 5.0, (fractal - 0.5) * 0.8, 1.0)); 2752 vec3 L1 = normalize(vec3(-0.55, 0.4, 1.0)); 2753 vec3 L2 = normalize(vec3(0.66, -0.25, 1.0)); 2754 float diff = max(dot(N, L1), 0.0); 2755 float specPow1 = max(10.0, 48.0 - u_surfaceRough * 40.0); 2756 float specPow2 = max(16.0, 72.0 - u_surfaceRough * 55.0); 2757 float spec = pow(max(dot(N, L1), 0.0), specPow1) + pow(max(dot(N, L2), 0.0), specPow2) * 0.9; 2758 2759 float glassThickness = clamp(u_tone * 10.0, 0.0, 1.0); 2760 float crestExp = mix(24.0, 6.0, glassThickness); 2761 float crest = pow(1.0 - abs(wave), crestExp); 2762 float brightRim = pow(max(0.0, slope), 10.0) * mix(0.6, 1.0, glassThickness); 2763 float troughCoeff = mix(0.35, 0.65, glassThickness); 2764 float troughShadow = pow(abs(wave), 1.7) * troughCoeff; 2765 2766 vec3 color = refracted; 2767 color *= (0.4 + u_transmission * 0.25) + diff * 0.5; 2768 color += spec * (u_colorD * 0.6 + vec3(0.62)) * u_specIntensity; 2769 color += crest * vec3(1.0) * 0.28; 2770 color += brightRim * u_colorD * 0.32; 2771 color -= troughShadow * 1.15; 2772 2773 // 5. Polish: grain, vignette, tone, gain, gamma 2774 float grain = (hash12(gl_FragCoord.xy + vec2(t * 120.0)) - 0.5) * (0.085 + u_grain * 0.12 + u_surfaceRough * 0.08); 2775 color += grain; 2776 2777 float vig = smoothstep(1.3, 0.18, length((uv - 0.5) * vec2(aspect, 1.0))); 2778 color *= mix(0.35, 1.18, pow(vig, u_vignette)); 2779 2780 float luma = dot(color, vec3(0.299, 0.587, 0.114)); 2781 color = mix(color, vec3(luma), u_tone); 2782 color *= u_gain; 2783 color = pow(max(color, vec3(0.0)), vec3(0.95)); 2784 2785 fragColor = vec4(color, 1.0); 2786} 2787`,p=`#version 300 es 2788precision highp float; 2789 2790in vec2 vUv; 2791out vec4 fragColor; 2792 2793/* -- Standard color uniforms ----------------------------------- */ 2794uniform float u_time; 2795uniform float u_speed; 2796uniform float u_direction; 2797uniform float u_grain; 2798uniform vec2 u_resolution; 2799uniform vec3 u_colors[12]; 2800uniform float u_colorPositions[12]; 2801uniform int u_colorCount; 2802 2803/* -- Fractal glass uniforms ------------------------------------ */ 2804uniform float u_ridgeCount; // number of ridges (4-60) 2805uniform int u_ridgeShape;
2805 // 0=sine, 1=chevron, 2=square, 3=sawtooth 2806uniform int u_ridgePattern; // 0=lines, 1=waves, 2=zigzag 2807uniform int u_ridgeOrientation; // 0=vertical, 1=horizontal 2808uniform float u_ridgeDepth; // 0-1, strength of ridge effect 2809uniform float u_transmission; // base brightness 2810uniform float u_thickness; // glass thickness â lighting depth 2811uniform float u_chromaticAberration;// color separation 2812uniform float u_clearcoat; // specular intensity 2813uniform float u_ior; // index of refraction 2814uniform float u_roughness; // surface roughness (blurs highlights) 2815 2816__COMMON__ 2817 2818void main() { 2819 vec2 uv = vUv; 2820 float aspect = u_resolution.x / u_resolution.y; 2821 2822 /* 1. Ridge angle from orientation */ 2823 float ridgeAngle = u_ridgeOrientation == 0 ? -0.85 : -0.85 + 1.5708; 2824 2825 /* 2. Rotate coordinates for diagonal flutes */ 2826 vec2 centered = (uv - 0.5) * vec2(aspect, 1.0); 2827 float ca = cos(ridgeAngle); 2828 float sa = sin(ridgeAngle); 2829 vec2 rot = vec2( 2830 ca * centered.x - sa * centered.y, 2831 sa * centered.x + ca * centered.y 2832 ); 2833 2834 /* 3. Pattern-based waviness (cheap deterministic, no FBM) */ 2835 float waveOffset = 0.0; 2836 if (u_ridgePattern == 1) { 2837 /* waves: sinusoidal cross-coordinate offset */ 2838 waveOffset = sin(rot.y * 5.0) * 0.08; 2839 } else if (u_ridgePattern == 2) { 2840 /* zigzag: triangle cross-coordinate offset */ 2841 waveOffset = (abs(fract(rot.y * 3.0) - 0.5) - 0.25) * 0.24; 2842 } 2843 float phase = (rot.x + waveOffset) * u_ridgeCount * 6.2831853; 2844 2845 /* 4. Wave shape selection */ 2846 float rawWave, rawSlope; 2847 2848 if (u_ridgeShape == 0) { 2849 /* Sine */ 2850 rawWave = sin(phase); 2851 rawSlope = cos(phase); 2852 } else if (u_ridgeShape == 1) { 2853 /* Chevron (triangle wave) */
2854 float triP = mod(phase / 6.2831853 + 0.25, 1.0); 2855 rawWave = 4.0 * abs(triP - 0.5) - 1.0; 2856 rawSlope = mix(4.0, -4.0, step(0.5, triP)); 2857 } else if (u_ridgeShape == 2) { 2858 /* Square */ 2859 rawWave = clamp(sin(phase) * 8.0, -1.0, 1.0); 2860 float edgeMask = max(0.0, 1.0 - rawWave * rawWave); 2861 rawSlope = cos(phase) * 8.0 * edgeMask; 2862 } else { 2863 /* Sawtooth (Fourier 7 harmonics) */ 2864 rawWave = sin(phase) - sin(2.0*phase)/2.0 2865 + sin(3.0*phase)/3.0 - sin(4.0*phase)/4.0 2866 + sin(5.0*phase)/5.0 - sin(6.0*phase)/6.0 2867 + sin(7.0*phase)/7.0; 2868 rawWave *= 0.64; 2869 rawSlope = cos(phase) - cos(2.0*phase) 2870 + cos(3.0*phase) - cos(4.0*phase) 2871 + cos(5.0*phase) - cos(6.0*phase) 2872 + cos(7.0*phase); 2873 rawSlope *= 0.64; 2874 } 2875 2876 /* 5. Sharpen + clamp */ 2877 float sharpK = max(1.0, 10.0 / max(u_ridgeCount, 1.0)); 2878 float wave = clamp(rawWave * sharpK, -1.0, 1.0); 2879 float slope = clamp(rawSlope * min(sharpK, 2.5), -1.0, 1.0); 2880 2881 /* 6. Refraction offset (simplified single-tap per channel) */ 2882 vec2 axis = normalize(vec2(ca / aspect, sa)); 2883 float refrStrength = u_ridgeDepth * 0.06 * max(u_ior - 1.0, 0.1); 2884 vec2 refractOffset = axis * wave * refrStrength; 2885 2886 /* 7. Sample gradient with chromatic aberration (3 taps: R, G, B) */ 2887 float gAngle = radians(u_direction); 2888 vec2 gdir = vec2(cos(gAngle), sin(gAngle)); 2889 vec2 chroma = axis * u_chromaticAberration * 0.015; 2890 2891 float tR = dot((uv + refractOffset + chroma) - 0.5, gdir) + 0.5; 2892 float tG = dot((uv + refractOffset) - 0.5, gdir) + 0.5; 2893 float tB = dot((uv + refractOffset - chroma) - 0.5, gdir) + 0.5; 2894 2895 vec3 colR = mixColors(u_colors, u_colorPositions, u_colorCount, fract(tR)); 2896 vec3 colG = mixColors(u_colors, u_colorPositions, u_colorCount, fract(tG)); 2897 vec3 colB = mixColors(u_colors, u_colorPositions, u_colorCount, fract(tB)); 2898 vec3 color = vec3(colR.r, colG.g, colB.b); 2899 2900 /* 8. Glass lighting */ 2901 float glassThickness = clamp(u_thickness * 2.0, 0.0, 1.0); 2902 float crestExp = mix(24.0, 6.0, glassThickness); 2903 float crest = pow(1.0 - abs(wave), crestExp); 2904 float brightRim = pow(max(0.0, slope), 10.0) * mix(0.6, 1.0, glassThickness); 2905 float troughCoeff = mix(0.35, 0.65, glassThickness); 2906 float troughShadow = pow(abs(wave), 1.7) * troughCoeff; 2907 2908 /* Diffuse + specular */ 2909 float diff = max(slope * 0.5 + 0.5, 0.0); 2910 float specPow = max(8.0, 48.0 - u_roughness * 40.0); 2911 float spec = pow(max(slope, 0.0), specPow) * u_clearcoat; 2912 2913 color *= (0.4 + u_transmission * 0.25) + diff * 0.3; 2914 color += spec * vec3(0.8) * 0.5; 2915 color += crest * vec3(1.0) * 0.2; 2916 color += brightRim * vec3(1.0) * 0.25; 2917 color -= troughShadow * 0.8; 2918 2919 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 2920} 2921`;e.s(["FRACTAL_GLASS_FRAGMENT",0,_,"FRACTAL_GLASS_THUMBNAIL_FRAGMENT",0,p,"RIDGE_ORIENTATION_MAP",0,{vertical:-.85,horizontal:-.85+Math.PI/2},"RIDGE_PATTERN_MAP",0,{lines:.3,waves:2.4,zigzag:1.5},"RIDGE_SHAPE_MAP",0,{sine:0,chevron:1,square:2,sawtooth:3}],293457);let v=`#version 300 es 2922precision highp float; 2923 2924in vec2 vUv; 2925out vec4 fragColor; 2926 2927uniform float u_time; 2928uniform float u_speed; 2929uniform vec3 u_colors[12]; 2930uniform float u_colorPositions[12]; 2931uniform int u_colorCount; 2932uniform float u_direction; 2933uniform float u_grain; 2934uniform vec2 u_resolution; 2935 2936// Blend uniforms 2937uniform int u_blendMode; 2938uniform float u_blendIntensity; 2939uniform float u_blendOffset; 2940uniform float u_blendRotation; 2941uniform float u_blendScale; 2942uniform int u_blendAnimRotation; 2943uniform int u_blendAnimIntensity; 2944uniform int u_blendAnimOffset; 2945uniform float u_blendAnimSpeed; 2946uniform float u_blendNoiseMask; 2947uniform float u_blendNoiseScale; 2948uniform float u_blendFalloff; 2949uniform int u_blendDualLayer; 2950uniform int u_blendMode2; 2951uniform float u_blendIntensity2; 2952uniform float u_blendOffset2; 2953uniform float u_blendRotation2; 2954uniform float u_blendScale2; 2955 2956// Mode-specific uniforms 2957uniform int u_surfaceShape; 2958uniform float u_shapeScale; 2959uniform float u_roundness; 2960uniform float u_twist; 2961uniform float u_cameraDistance; 2962uniform float u_cameraPitch; 2963uniform float u_cameraYaw; 2964uniform float u_cameraFov; 2965uniform int u_autoRotate; 2966uniform float u_autoRotateSpeed; 2967uniform int u_gradientMapping; 2968uniform float u_gradientScale; 2969uniform float u_diffuse; 2970uniform float u_specularStrength; 2971uniform float u_specularPower; 2972uniform float u_fresnel; 2973uniform float u_lightX; 2974uniform float u_lightY; 2975uniform float u_lightZ; 2976uniform float u_ambient; 2977uniform float u_shadowSoftness; 2978uniform float u_aoStrength; 2979uniform float u_aoRadius; 2980uniform float u_bgGradient; 2981uniform float u_bgBlur; 2982uniform float u_reflectivity; 2983uniform int u_csgOp; 2984uniform int u_csgShape; 2985uniform float u_csgBlend; 2986uniform int u_transparentBg; 2987 2988// Quality tier: 0=low, 1=medium, 2=high, 3=ultra 2989uniform int u_qualityTier; 2990 2991// PBR Material uniforms 2992uniform float u_pbrMetallic; 2993uniform float u_pbrRoughness; 2994uniform float u_pbrAnisotropy; 2995 2996// HDRI environment map 2997uniform samplerCube u_envMap; 2998uniform int u_useEnvMap; 2999uniform float u_envIntensity; 3000uniform float u_envRotation; 3001 3002// Enhanced point lights (up to 4) 3003uniform vec3 u_pointLights[4]; 3004uniform vec3 u_pointLightColors[4]; 3005uniform int u_numPointLights; 3006 3007__COMMON__ 3008 3009// ---- Rotation helpers ---- 3010mat3 rotX(float a) { 3011 float s = sin(a), c = cos(a); 3012 return mat3(1.0, 0.0, 0.0, 0.0, c, -s, 0.0, s, c); 3013} 3014mat3 rotY(float a) { 3015 float s = sin(a), c = cos(a); 3016 return mat3(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); 3017} 3018mat2 rot2(float a) { 3019 float s = sin(a), c = cos(a); 3020 return mat2(c, -s, s, c); 3021} 3022 3023// ---- SDF primitives ---- 3024float sdSphere(vec3 p) { 3025 return length(p) - 1.0; 3026} 3027 3028float sdTorus(vec3 p) { 3029 vec2 q = vec2(length(p.xz) - 0.6, p.y); 3030 return length(q) - 0.4; 3031} 3032 3033float sdBox(vec3 p, vec3 b) { 3034 vec3 q = abs(p) - b; 3035 return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0); 3036} 3037 3038float sdCube(vec3 p) {
3039 return sdBox(p, vec3(0.8)) - u_roundness * 0.2; 3040} 3041 3042float sdOctahedron(vec3 p) { 3043 p = abs(p); 3044 float m = p.x + p.y + p.z - 1.0; 3045 vec3 q; 3046 if (3.0 * p.x < m) q = p.xyz; 3047 else if (3.0 * p.y < m) q = p.yzx; 3048 else if (3.0 * p.z < m) q = p.zxy; 3049 else return m * 0.57735027; 3050 float k = clamp(0.5 * (q.z - q.y + 1.0), 0.0, 1.0); 3051 return length(vec3(q.x, q.y - 1.0 + k, q.z - k)); 3052} 3053 3054float sdCylinder(vec3 p) { 3055 vec2 d = abs(vec2(length(p.xz), p.y)) - vec2(0.6, 1.0); 3056 return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - u_roundness * 0.1; 3057} 3058 3059float sdCone(vec3 p) { 3060 float q = length(p.xz); 3061 return max(dot(vec2(0.6, 0.8), vec2(q, -p.y)), p.y - 1.0); 3062} 3063 3064float sdCapsule(vec3 p) { 3065 p.y -= clamp(p.y, -0.8, 0.8); 3066 return length(p) - 0.5; 3067} 3068 3069float sdKnot(vec3 p) { 3070 // Trefoil knot approximation via closest distance to parametric curve 3071 float bestD = 1e10; 3072 for (int i = 0; i < 48; i++) { 3073 float t = float(i) / 48.0 * 6.28318; 3074 float r = 0.6 + 0.3 * cos(3.0 * t); 3075 vec3 c = vec3(r * cos(2.0 * t), 0.3 * sin(3.0 * t), r * sin(2.0 * t)); 3076 bestD = min(bestD, length(p - c)); 3077 } 3078 return bestD - 0.15; 3079} 3080 3081float sdMobius(vec3 p) { 3082 // Mobius strip approximation 3083 float a = atan(p.z, p.x); 3084 float r = length(p.xz) - 0.7; 3085 float ha = a * 0.5; 3086 float cosHa = cos(ha), sinHa = sin(ha); 3087 float y2 = p.y * cosHa - r * sinHa; 3088 float r2 = p.y * sinHa + r * cosHa; 3089 return length(vec2(r2, y2)) - 0.15; 3090} 3091 3092float sdStar(vec3 p) { 3093 // Extruded 5-pointed star 3094 float d2 = abs(p.y) - 0.3; 3095 vec2 q = p.xz; 3096 float a = atan(q.y, q.x); 3097 float r = length(q); 3098 float star = r - 0.6 + 0.3 * cos(5.0 * a); 3099 return max(star, d2) - u_roundness * 0.05; 3100} 3101 3102float sdHeart(vec3 p) { 3103 p.y -= 0.2; 3104 p *= 1.2; 3105 float x2 = p.x * p.x; 3106 float y = p.y; 3107 float z2 = p.z * p.z; 3108 float cube = x2 + 2.25 * y * y + z2 - 1.0; 3109 return (cube * cube * cube - (x2 + 0.075 * z2) * y * y * y) * 0.5; 3110} 3111 3112float sdGyroid(vec3 p) { 3113 p *= 3.14159; 3114 return (sin(p.x) * cos(p.y) + sin(p.y) * cos(p.z) + sin(p.z) * cos(p.x)) / 3.14159 * 0.35; 3115} 3116 3117// ---- Smooth CSG operators (needed by SDF helpers below) ---- 3118float smin(float a, float b, float k) { 3119 float h = clamp(0.5 + 0.5 * (b - a) / max(k, 0.001), 0.0, 1.0); 3120 return mix(b, a, h) - k * h * (1.0 - h); 3121} 3122 3123float smax(float a, float b, float k) { 3124 return -smin(-a, -b, k); 3125} 3126 3127// ---- Diamond / faceted gem ---- 3128float sdDiamond(vec3 p) { 3129 // Octahedron variant: top pyramid (short) + bottom pyramid (tall) 3130 float top = (abs(p.x) + abs(p.z)) * 0.707 + p.y * 0.8 - 0.5; 3131 float bottom = (abs(p.x) + abs(p.z)) * 0.707 - p.y * 0.5 - 0.7; 3132 return max(top, bottom) - u_roundness * 0.05; 3133} 3134 3135// ---- Teardrop / water drop ---- 3136float sdTeardrop(vec3 p) { 3137 vec3 q = p; 3138 q.y -= 0.2; 3139 float body = length(q) - 0.7; 3140 float tip = length(vec3(q.x * 0.5, q.y - 0.7, q.z * 0.5)) - 0.15; 3141 return smin(body, tip, 0.4); 3142} 3143 3144// ---- Double helix / DNA ---- 3145float sdHelix(vec3 p) { 3146 float bestD = 1e10; 3147 for (int i = 0; i < 64; i++) { 3148 float t = float(i) / 64.0 * 12.566; // 2 full turns 3149 float h = t / 6.283 - 1.0; 3150 vec3 c1 = vec3(0.5 * cos(t), h, 0.5 * sin(t)); 3151 vec3 c2 = vec3(0.5 * cos(t + 3.14159), h, 0.5 * sin(t + 3.14159)); 3152 bestD = min(bestD, min(length(p - c1), length(p - c2))); 3153 } 3154 return bestD - 0.09 - u_roundness * 0.04; 3155} 3156 3157// ---- Pyramid (square base) ---- 3158float sdPyramid(vec3 p) { 3159 float h = 1.2; 3160 vec3 q = abs(p); 3161 float base = max(q.x, q.z) - 0.8 + p.y * 0.65; 3162 float cap = p.y - h * 0.5; 3163 float floor_ = -p.y - h * 0.3; 3164 return max(max(base, cap), floor_) - u_roundness * 0.05; 3165} 3166 3167// ---- Helical spring / coil ---- 3168float sdSpring(vec3 p) { 3169 float bestD = 1e10; 3170 for (int i = 0; i < 48; i++) { 3171 float t = float(i) / 48.0 * 18.8496; // 3 coils 3172 float h = t / 6.28318 * 0.4 - 0.9; 3173 vec3 c = vec3(0.5 * cos(t), h, 0.5 * sin(t)); 3174 bestD = min(bestD, length(p - c)); 3175 } 3176 return bestD - 0.1 - u_roundness * 0.04; 3177} 3178 3179// ---- (3,2) torus knot ---- 3180float sdTorusKnot(vec3 p) { 3181 float bestD = 1e10; 3182 for (int i = 0; i < 64; i++) { 3183 float t = float(i) / 64.0 * 6.28318; 3184 float r = 0.6 + 0.25 * cos(3.0 * t); 3185 vec3 c = vec3(r * cos(2.0 * t), 0.25 * sin(3.0 * t), r * sin(2.0 * t)); 3186 bestD = min(bestD, length(p - c)); 3187 }
3188 return bestD - 0.1 - u_roundness * 0.03; 3189} 3190 3191// ---- Nautilus shell (logarithmic spiral) ---- 3192float sdShell(vec3 p) { 3193 float bestD = 1e10; 3194 for (int i = 0; i < 64; i++) { 3195 float t = float(i) / 64.0 * 9.4248; // 1.5 turns 3196 float growthRate = exp(0.18 * t); 3197 float r = 0.08 * growthRate; 3198 float cr = max(r * 0.35, 0.04); 3199 vec3 c = vec3(r * cos(t), t * 0.06 - 0.4, r * sin(t)); 3200 bestD = min(bestD, length(p - c) - cr); 3201 } 3202 return bestD; 3203} 3204 3205// ---- 3D cross ---- 3206float sdCross(vec3 p) { 3207 vec3 q = abs(p); 3208 float dx = max(q.y, q.z) - 0.3; 3209 float dy = max(q.x, q.z) - 0.3; 3210 float dz = max(q.x, q.y) - 0.3; 3211 float d = min(min( 3212 max(dx, q.x - 1.0), 3213 max(dy, q.y - 1.0)), 3214 max(dz, q.z - 1.0)); 3215 return d - u_roundness * 0.08; 3216} 3217 3218// ---- Shape dispatcher ---- 3219float evalShape(vec3 p, int shape) { 3220 // Apply twist 3221 if (abs(u_twist) > 0.001) { 3222 p.xz = rot2(p.y * u_twist) * p.xz; 3223 } 3224 p /= max(u_shapeScale, 0.01); 3225 3226 float d; 3227 if (shape == 0) d = sdSphere(p); 3228 else if (shape == 1) d = sdTorus(p); 3229 else if (shape == 2) d = sdCube(p); 3230 else if (shape == 3) d = sdOctahedron(p); 3231 else if (shape == 4) d = sdCylinder(p); 3232 else if (shape == 5) d = sdCone(p); 3233 else if (shape == 6) d = sdCapsule(p); 3234 else if (shape == 7) d = sdKnot(p); 3235 else if (shape == 8) d = sdMobius(p); 3236 else if (shape == 9) d = sdHeart(p); 3237 else if (shape == 10) d = sdStar(p); 3238 else if (shape == 11) d = sdGyroid(p); 3239 else if (shape == 12) d = sdDiamond(p); 3240 else if (shape == 13) d = sdTeardrop(p); 3241 else if (shape == 14) d = sdHelix(p); 3242 else if (shape == 15) d = sdPyramid(p); 3243 else if (shape == 16) d = sdSpring(p); 3244 else if (shape == 17) d = sdTorusKnot(p); 3245 else if (shape == 18) d = sdShell(p); 3246 else d = sdCross(p); 3247 3248 return d * u_shapeScale; 3249} 3250 3251// ---- Scene SDF ---- 3252float sceneSDF(vec3 p) { 3253 float d1 = evalShape(p, u_surfaceShape); 3254 3255 if (u_csgOp > 0) { 3256 float d2 = evalShape(p, u_csgShape); 3257 float k = u_csgBlend; 3258 if (u_csgOp == 1) d1 = smin(d1, d2, k); // union 3259 else if (u_csgOp == 2) d1 = smax(d1, -d2, k); // subtract 3260 else if (u_csgOp == 3) d1 = smax(d1, d2, k); // intersect 3261 } 3262 3263 return d1; 3264} 3265 3266// ---- Normal via central differences ---- 3267vec3 calcNormal(vec3 p) { 3268 const float h = 0.001; 3269 vec2 e = vec2(h, 0.0); 3270 return normalize(vec3( 3271 sceneSDF(p + e.xyy) - sceneSDF(p - e.xyy), 3272 sceneSDF(p + e.yxy) - sceneSDF(p - e.yxy), 3273 sceneSDF(p + e.yyx) - sceneSDF(p - e.yyx) 3274 )); 3275} 3276 3277// ---- Soft shadows (quality-adaptive) ---- 3278float softShadow(vec3 ro, vec3 rd, float tMin, float tMax) { 3279 float res = 1.0; 3280 float t = tMin; 3281 float k = u_shadowSoftness; 3282 int maxSteps = u_qualityTier == 0 ? 8 : u_qualityTier == 1 ? 16 : u_qualityTier == 2 ? 24 : 32; 3283 for (int i = 0; i < 32; i++) { 3284 if (i >= maxSteps || t >= tMax) break; 3285 float d = sceneSDF(ro + rd * t); 3286 if (d < 0.001) return 0.0; 3287 res = min(res, k * d / t); 3288 t += clamp(d, 0.02, 0.2); 3289 } 3290 return clamp(res, 0.0, 1.0); 3291} 3292 3293// ---- Ambient occlusion (quality-adaptive) ---- 3294float calcAO(vec3 p, vec3 n) { 3295 float occ = 0.0; 3296 float w = 1.0; 3297 int aoSamples = u_qualityTier == 0 ? 2 : u_qualityTier == 1 ? 3 : u_qualityTier == 2 ? 4 : 5; 3298 for (int i = 0; i < 5; i++) { 3299 if (i >= aoSamples) break; 3300 float dist = u_aoRadius * (1.0 + float(i)); 3301 float d = sceneSDF(p + n * dist); 3302 occ += (dist - d) * w; 3303 w *= 0.5; 3304 } 3305 return clamp(1.0 - u_aoStrength * occ * 3.0, 0.0, 1.0); 3306} 3307 3308// ---- PBR Functions (Cook-Torrance BRDF, ported from metallic-3d) ---- 3309#define PI 3.14159265359 3310 3311// GGX Normal Distribution Function 3312float D_GGX(float NdotH, float roughness) { 3313 float a = roughness * roughness; 3314 float a2 = a * a; 3315 float NdotH2 = NdotH * NdotH; 3316 float denom = NdotH2 * (a2 - 1.0) + 1.0; 3317 return a2 / (PI * denom * denom + 0.0001); 3318} 3319 3320// Anisotropic GGX (Burley/Disney) 3321float D_GGX_Aniso(float NdotH, float TdotH, float BdotH, float ax, float ay) { 3322 float a2 = ax * ay; 3323 vec3 v = vec3(ay * TdotH, ax * BdotH, a2 * NdotH); 3324 float v2 = dot(v, v); 3325 float w2 = a2 / max(v2, 1e-7); 3326 return a2 * w2 * w2 / PI; 3327} 3328 3329// Smith GGX Geometry (height-correlated) 3330float G_Smith(float NdotV, float NdotL, float roughness) { 3331 float a = roughness * roughness; 3332 float a2 = a * a;
3333 float ggxV = NdotL * sqrt(NdotV * NdotV * (1.0 - a2) + a2); 3334 float ggxL = NdotV * sqrt(NdotL * NdotL * (1.0 - a2) + a2); 3335 return 0.5 / max(ggxV + ggxL, 0.001); 3336} 3337 3338// Schlick Fresnel with vec3 F0 (metals have colored F0) 3339vec3 F_Schlick(float cosTheta, vec3 F0) { 3340 return F0 + (vec3(1.0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); 3341} 3342 3343// Procedural environment map for PBR reflections 3344vec3 proceduralEnv(vec3 dir, float roughness) { 3345 // Apply environment rotation around Y axis 3346 float rotAngle = u_envRotation * 3.14159 / 180.0; 3347 float cr = cos(rotAngle), sr = sin(rotAngle); 3348 dir = vec3(cr * dir.x + sr * dir.z, dir.y, -sr * dir.x + cr * dir.z); 3349 3350 // Use real HDRI cubemap when available 3351 if (u_useEnvMap == 1) { 3352 vec3 hdriColor = texture(u_envMap, dir).rgb; 3353 // Poor-man's roughness blur: sample nearby directions and average 3354 vec3 blurred = texture(u_envMap, normalize(dir + vec3(0.2, 0.1, -0.15))).rgb; 3355 blurred += texture(u_envMap, normalize(dir + vec3(-0.15, 0.2, 0.1))).rgb; 3356 blurred += texture(u_envMap, normalize(dir + vec3(0.1, -0.15, 0.2))).rgb; 3357 blurred *= 0.333; 3358 vec3 env = mix(hdriColor, blurred, roughness * 0.7); 3359 return env * u_envIntensity; 3360 } 3361 3362 float yFactor = dir.y * 0.5 + 0.5; 3363 3364 // Sky gradient 3365 vec3 sky = mix(vec3(0.01, 0.01, 0.02), vec3(0.4, 0.5, 0.7), pow(yFactor, 0.6)); 3366 3367 // Ground 3368 vec3 ground = mix(vec3(0.02, 0.02, 0.03), vec3(0.1, 0.08, 0.06), max(-dir.y, 0.0)); 3369 3370 // Horizon glow 3371 float horizon = pow(1.0 - abs(dir.y), 12.0) * 0.6; 3372 3373 // Sun highlight (sharp for low roughness, soft for high) 3374 vec3 sunDir = normalize(vec3(u_lightX, u_lightY, u_lightZ)); 3375 float sunDot = max(dot(dir, sunDir), 0.0); 3376 float sunPow = mix(512.0, 4.0, roughness); 3377 float sunSpec = pow(sunDot, sunPow); 3378 vec3 sunColor = vec3(1.0, 0.95, 0.85) * sunSpec * mix(3.0, 0.5, roughness); 3379 3380 // Secondary light (rim fill from opposite side) 3381 vec3 rimDir = normalize(vec3(-u_lightX, u_lightY * 0.5, -u_lightZ)); 3382 float rimDot = max(dot(dir, rimDir), 0.0); 3383 float rimSpec = pow(rimDot, mix(128.0, 4.0, roughness)) * 0.3; 3384 3385 vec3 env = mix(ground, sky, step(0.0, dir.y)); 3386 env += horizon; 3387 env += sunColor; 3388 env += vec3(0.7, 0.8, 1.0) * rimSpec; 3389 3390 // Soften based on roughness (blur approximation) 3391 env = mix(env, vec3(dot(env, vec3(0.2126, 0.7152, 0.0722))), roughness * 0.5); 3392 3393 return env; 3394} 3395 3396// ---- Gradient mapping ---- 3397float gradientT(vec3 p, vec3 n, vec3 viewDir, float rayDist) { 3398 float t; 3399 if (u_gradientMapping == 0) { 3400 // Position: map along world Y 3401 t = p.y * 0.5 + 0.5; 3402 } else if (u_gradientMapping == 1) { 3403 // Normal: dot with up 3404 t = dot(n, vec3(0.0, 1.0, 0.0)) * 0.5 + 0.5; 3405 } else if (u_gradientMapping == 2) { 3406 // Fresnel 3407 t = 1.0 - abs(dot(n, viewDir)); 3408 } else if (u_gradientMapping == 3) { 3409 // UV: spherical theta/phi 3410 float theta = atan(p.z, p.x) / 6.28318 + 0.5; 3411 float phi = asin(clamp(p.y / max(length(p), 0.001), -1.0, 1.0)) / 3.14159 + 0.5; 3412 t = mix(theta, phi, 0.5); 3413 } else if (u_gradientMapping == 4) { 3414 // Distance from camera 3415 t = rayDist / 10.0; 3416 } else { 3417 // Metallic: iridescent color shift from specular + fresnel + environment 3418 vec3 l = normalize(vec3(u_lightX, u_lightY, u_lightZ) - p); 3419 vec3 h = normalize(l + viewDir); 3420 float spec = pow(max(dot(n, h), 0.0), 32.0); 3421 float fres = pow(1.0 - max(dot(n, viewDir), 0.0), 3.0); 3422 vec3 refl = reflect(-viewDir, n); 3423 float env = refl.y * 0.5 + 0.5; 3424 t = mix(mix(fres, spec, 0.4), env, 0.3); 3425 } 3426 return clamp(t * u_gradientScale, 0.0, 1.0); 3427} 3428 3429void main() { 3430 float time = u_time * u_speed; 3431 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 3432 3433 // Camera setup 3434 float yaw = radians(u_cameraYaw); 3435 float pitch = radians(u_cameraPitch); 3436 if (u_autoRotate > 0) { 3437 yaw += time * u_autoRotateSpeed * 0.5; 3438 } 3439 3440 vec3 camPos = vec3( 3441 u_cameraDistance * cos(pitch) * sin(yaw), 3442 u_cameraDistance * sin(pitch), 3443 u_cameraDistance * cos(pitch) * cos(yaw) 3444 ); 3445 vec3 target = vec3(0.0); 3446 vec3 forward = normalize(target - camPos); 3447 vec3 worldUp = vec3(0.0, 1.0, 0.0); 3448 vec3 right = normalize(cross(forward, worldUp)); 3449 vec3 up = cross(right, forward); 3450 3451 // Ray direction from UV + FOV 3452 float fovScale = tan(radians(u_cameraFov) * 0.5); 3453 vec2 warpedUv = applyMouseWarp(vUv, aspect); 3454 vec2 screenUV = (warpedUv - 0.5) * 2.0; 3455 screenUV.x *= aspect; 3456 vec3 rd = normalize(forward + screenUV.x * fovScale * right + screenUV.y * fovScale * up); 3457 3458 // Ray march (quality-adaptive steps) 3459 int maxSteps = u_qualityTier == 0 ? 40 : u_qualityTier == 1 ? 60 : u_qualityTier == 2 ? 80 : 100; 3460 float t = 0.0; 3461 float d; 3462 bool hit = false;
3463 for (int i = 0; i < 100; i++) { 3464 if (i >= maxSteps) break; 3465 vec3 p = camPos + rd * t; 3466 d = sceneSDF(p); 3467 if (d < 0.001) { hit = true; break; } 3468 if (t > 20.0) break; 3469 t += d; 3470 } 3471 3472 vec3 color; 3473 3474 if (hit) { 3475 vec3 p = camPos + rd * t; 3476 vec3 n = calcNormal(p); 3477 vec3 viewDir = -rd; 3478 3479 // Light direction 3480 vec3 lightPos = vec3(u_lightX, u_lightY, u_lightZ); 3481 vec3 l = normalize(lightPos - p); 3482 vec3 h = normalize(l + viewDir); 3483 3484 // Gradient color from mapping 3485 float gT = gradientT(p, n, viewDir, t); 3486 3487 // Image-driven gradient integration 3488 float imgLum = imageLuminance(gl_FragCoord.xy / u_resolution.xy, aspect); 3489 if (imgLum >= 0.0) { 3490 gT = mix(gT, imgLum, u_imageIntensity); 3491 } 3492 3493 vec3 albedo = mixColors(u_colors, u_colorPositions, u_colorCount, gT); 3494 3495 // Soft shadows 3496 float shadow = softShadow(p + n * 0.01, l, 0.02, 10.0); 3497 3498 // Ambient occlusion 3499 float ao = calcAO(p, n); 3500 3501 if (u_pbrMetallic > 0.001) { 3502 // ---- Cook-Torrance PBR lighting path ---- 3503 float NdotV = max(dot(n, viewDir), 0.001); 3504 float NdotL = max(dot(n, l), 0.0); 3505 float NdotH = max(dot(n, h), 0.0); 3506 float VdotH = max(dot(h, viewDir), 0.0); 3507 3508 float roughness = max(u_pbrRoughness, 0.04); 3509 vec3 F0 = mix(vec3(0.04), albedo, u_pbrMetallic); 3510 3511 // Normal Distribution 3512 float D; 3513 if (u_pbrAnisotropy > 0.001) { 3514 vec3 T = normalize(cross(n, abs(n.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0))); 3515 vec3 B = cross(n, T); 3516 float anisAspect = sqrt(1.0 - 0.9 * u_pbrAnisotropy); 3517 float ax = roughness / anisAspect; 3518 float ay = roughness * anisAspect; 3519 float TdotH = dot(T, h); 3520 float BdotH = dot(B, h); 3521 D = D_GGX_Aniso(NdotH, TdotH, BdotH, ax, ay); 3522 } else { 3523 D = D_GGX(NdotH, roughness); 3524 } 3525 3526 // Geometry 3527 float G = G_Smith(NdotV, NdotL, roughness); 3528 3529 // Fresnel 3530 vec3 F = F_Schlick(VdotH, F0); 3531 3532 // Specular BRDF 3533 vec3 specular = (D * G) * F; 3534 3535 // Energy conservation 3536 vec3 kD = (vec3(1.0) - F) * (1.0 - u_pbrMetallic); 3537 vec3 diffusePBR = kD * albedo / PI; 3538 3539 // Direct lighting (primary directional) 3540 vec3 Lo = (diffusePBR + specular) * NdotL * shadow; 3541 3542 // ---- Point light contributions ---- 3543 for (int pl = 0; pl < 4; pl++) { 3544 if (pl >= u_numPointLights) break; 3545 vec3 plDir = u_pointLights[pl] - p; 3546 float plDist = length(plDir); 3547 plDir /= plDist; 3548 float plAtten = 1.0 / (1.0 + plDist * plDist * 0.1); 3549 3550 // Shadow ray from point light 3551 float plShadow = softShadow(p + n * 0.01, plDir, 0.02, plDist); 3552 3553 float plNdotL = max(dot(n, plDir), 0.0); 3554 vec3 plH = normalize(plDir + viewDir); 3555 float plNdotH = max(dot(n, plH), 0.0); 3556 float plVdotH = max(dot(plH, viewDir), 0.0); 3557 3558 float plD = D_GGX(plNdotH, roughness); 3559 float plG = G_Smith(NdotV, plNdotL, roughness); 3560 vec3 plF = F_Schlick(plVdotH, F0); 3561 vec3 plSpec = (plD * plG) * plF; 3562 vec3 plKd = (vec3(1.0) - plF) * (1.0 - u_pbrMetallic); 3563 3564 Lo += (plKd * albedo / PI + plSpec) * plNdotL * plAtten * u_pointLightColors[pl] * plShadow; 3565 } 3566 3567 // Environment reflections 3568 vec3 reflDir = reflect(-viewDir, n); 3569 vec3 envSpec = proceduralEnv(reflDir, roughness); 3570 vec3 envF = F_Schlick(NdotV, F0); 3571 vec3 envReflection = envSpec * envF; 3572 3573 // Diffuse IBL 3574 vec3 envDiffuse = proceduralEnv(n, 1.0) * kD * albedo; 3575 3576 // Combine 3577 vec3 ambientPBR = albedo * u_ambient * ao; 3578 color = ambientPBR + Lo + (envReflection + envDiffuse) * ao; 3579 } else { 3580 // ---- Classic Blinn-Phong lighting path ---- 3581 float diff = max(dot(n, l), 0.0) * u_diffuse; 3582 float spec = pow(max(dot(n, h), 0.0), u_specularPower) * u_specularStrength; 3583 float fres = u_fresnel * pow(1.0 - max(dot(n, viewDir), 0.0), 5.0); 3584 3585 // Combine lighting 3586 vec3 ambient = albedo * u_ambient; 3587 vec3 diffCol = albedo * diff * shadow; 3588 vec3 specCol = vec3(spec) * shadow; 3589 vec3 fresnelCol = mix(albedo, vec3(1.0), 0.5) * fres; 3590 3591 // ---- Point light contributions (Blinn-Phong) ---- 3592 for (int pl = 0; pl < 4; pl++) { 3593 if (pl >= u_numPointLights) break; 3594 vec3 plDir = u_pointLights[pl] - p; 3595 float plDist = length(plDir); 3596 plDir /= plDist; 3597 float plAtten = 1.0 / (1.0 + plDist * plDist * 0.1); 3598 float plShadow = softShadow(p + n * 0.01, plDir, 0.02, plDist); 3599 float plDiff = max(dot(n, plDir), 0.0) * u_diffuse; 3600 vec3 plH = normalize(plDir + viewDir); 3601 float plSpec = pow(max(dot(n, plH), 0.0), u_specularPower) * u_specularStrength; 3602 diffCol += albedo * plDiff * plAtten * u_pointLightColors[pl] * plShadow; 3603 specCol += vec3(plSpec) * plAtten * u_pointLightColors[pl] * plShadow; 3604 } 3605 3606 // Reflectivity: blend in a reflection-like highlight using the environment 3607 vec3 reflDir = reflect(-viewDir, n); 3608 float envRefl = max(dot(reflDir, vec3(0.0, 1.0, 0.0)) * 0.5 + 0.5, 0.0
3608); 3609 vec3 reflCol = mixColors(u_colors, u_colorPositions, u_colorCount, envRefl) * u_reflectivity * fres; 3610 3611 color = (ambient + diffCol + specCol + fresnelCol + reflCol) * ao; 3612 } 3613 3614 // Grain â only inside shape 3615 color += grain(vUv, time, u_grain * 0.75); 3616 3617 // Self-blend â only inside shape 3618 if (u_blendMode > 0) { 3619 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 3620 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 3621 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 3622 bIntensity = noiseModulatedIntensity(bIntensity, vUv, time, u_blendNoiseMask, u_blendNoiseScale); 3623 bIntensity = applyBlendFalloff(bIntensity, vUv.x, u_blendFalloff); 3624 float tB = blendLayerT(vUv, 0.5, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 3625 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 3626 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 3627 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 3628 float tB2 = blendLayerT(vUv, 0.5, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 3629 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 3630 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 3631 } 3632 } 3633 3634 fragColor = outputColor(color, gl_FragCoord.xy, 1.1); 3635 } else { 3636 // Background â transparent for export, dark for viewport 3637 if (u_transparentBg == 1) { 3638 fragColor = vec4(0.0); 3639 } else { 3640 float vignette = 1.0 - 0.3 * length(vUv - 0.5); 3641 vec3 bgColor = vec3(0.03 * u_bgGradient * vignette); 3642 fragColor = outputColor(bgColor, gl_FragCoord.xy, 1.1); 3643 } 3644 } 3645} 3646`,b=`#version 300 es 3647precision highp float; 3648 3649in vec2 vUv; 3650out vec4 fragColor; 3651 3652uniform float u_time; 3653uniform float u_speed; 3654uniform vec3 u_colors[12]; 3655uniform float u_colorPositions[12]; 3656uniform int u_colorCount; 3657uniform float u_direction; 3658uniform float u_grain; 3659uniform vec2 u_resolution; 3660 3661// Blend uniforms 3662uniform int u_blendMode; 3663uniform float u_blendIntensity; 3664uniform float u_blendOffset; 3665uniform float u_blendRotation; 3666uniform float u_blendScale; 3667uniform int u_blendAnimRotation; 3668uniform int u_blendAnimIntensity; 3669uniform int u_blendAnimOffset; 3670uniform float u_blendAnimSpeed; 3671uniform float u_blendNoiseMask; 3672uniform float u_blendNoiseScale; 3673uniform float u_blendFalloff; 3674uniform int u_blendDualLayer; 3675uniform int u_blendMode2; 3676uniform float u_blendIntensity2; 3677uniform float u_blendOffset2; 3678uniform float u_blendRotation2; 3679uniform float u_blendScale2; 3680 3681// Shape / camera / CSG uniforms (shared with surfaces3d) 3682uniform int u_surfaceShape; 3683uniform float u_shapeScale; 3684uniform float u_roundness; 3685uniform float u_twist; 3686uniform float u_cameraDistance; 3687uniform float u_cameraPitch; 3688uniform float u_cameraYaw; 3689uniform float u_cameraFov; 3690uniform int u_autoRotate; 3691uniform float u_autoRotateSpeed; 3692 3693// PBR Material 3694uniform float u_metallic; 3695uniform float u_roughness; 3696uniform float u_anisotropy; 3697uniform float u_anisotropyAngle; 3698 3699// Coating 3700uniform float u_iridescence; 3701uniform float u_iridescenceIOR; 3702uniform float u_clearcoat; 3703uniform float u_clearcoatRoughness; 3704 3705// Environment 3706uniform float u_envIntensity; 3707uniform float u_envRotation; 3708uniform samplerCube u_envMap; 3709uniform int u_useEnvMap; 3710 3711// Lighting 3712uniform float u_lightX; 3713uniform float u_lightY; 3714uniform float u_lightZ; 3715uniform float u_ambient; 3716uniform float u_shadowSoftness; 3717uniform float u_aoStrength; 3718uniform float u_aoRadius; 3719 3720// Background 3721uniform float u_bgGradient; 3722uniform int u_transparentBg; 3723 3724// Flow (curl noise animation) 3725uniform float u_flowIntensity; 3726uniform float u_flowSpeed; 3727uniform float u_flowScale; 3728 3729// CSG 3730uniform int u_csgOp; 3731uniform int u_csgShape; 3732 3733// Quality tier: 0=low, 1=medium, 2=high, 3=ultra 3734uniform int u_qualityTier; 3735uniform float u_csgBlend; 3736 3737__COMMON__ 3738 3739// ---- Rotation helpers ---- 3740mat3 rotX(float a) { 3741 float s = sin(a), c = cos(a); 3742 return mat3(1.0, 0.0, 0.0, 0.0, c, -s, 0.0, s, c); 3743} 3744mat3 rotY(float a) { 3745 float s = sin(a), c = cos(a); 3746 return mat3(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); 3747} 3748mat2 rot2(float a) { 3749 float s = sin(a), c = cos(a); 3750 return mat2(c, -s, s, c); 3751} 3752 3753// ---- SDF primitives ---- 3754float sdSphere(vec3 p) { 3755 return length(p) - 1.0; 3756} 3757 3758float sdTorus(vec3 p) { 3759 vec2 q = vec2(length(p.xz) - 0.6, p.y); 3760 return length(q) - 0.4; 3761} 3762 3763float sdBox(vec3 p, vec3 b) { 3764 vec3 q = abs(p) - b; 3765 return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0); 3766} 3767 3768float sdCube(vec3 p) {
3769 return sdBox(p, vec3(0.8)) - u_roundness * 0.2; 3770} 3771 3772float sdOctahedron(vec3 p) { 3773 p = abs(p); 3774 float m = p.x + p.y + p.z - 1.0; 3775 vec3 q; 3776 if (3.0 * p.x < m) q = p.xyz; 3777 else if (3.0 * p.y < m) q = p.yzx; 3778 else if (3.0 * p.z < m) q = p.zxy; 3779 else return m * 0.57735027; 3780 float k = clamp(0.5 * (q.z - q.y + 1.0), 0.0, 1.0); 3781 return length(vec3(q.x, q.y - 1.0 + k, q.z - k)); 3782} 3783 3784float sdCylinder(vec3 p) { 3785 vec2 d = abs(vec2(length(p.xz), p.y)) - vec2(0.6, 1.0); 3786 return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - u_roundness * 0.1; 3787} 3788 3789float sdCone(vec3 p) { 3790 float q = length(p.xz); 3791 return max(dot(vec2(0.6, 0.8), vec2(q, -p.y)), p.y - 1.0); 3792} 3793 3794float sdCapsule(vec3 p) { 3795 p.y -= clamp(p.y, -0.8, 0.8); 3796 return length(p) - 0.5; 3797} 3798 3799float sdKnot(vec3 p) { 3800 // Trefoil knot approximation via closest distance to parametric curve 3801 float bestD = 1e10; 3802 for (int i = 0; i < 48; i++) { 3803 float t = float(i) / 48.0 * 6.28318; 3804 float r = 0.6 + 0.3 * cos(3.0 * t); 3805 vec3 c = vec3(r * cos(2.0 * t), 0.3 * sin(3.0 * t), r * sin(2.0 * t)); 3806 bestD = min(bestD, length(p - c)); 3807 } 3808 return bestD - 0.15; 3809} 3810 3811float sdMobius(vec3 p) { 3812 // Mobius strip approximation 3813 float a = atan(p.z, p.x); 3814 float r = length(p.xz) - 0.7; 3815 float ha = a * 0.5; 3816 float cosHa = cos(ha), sinHa = sin(ha); 3817 float y2 = p.y * cosHa - r * sinHa; 3818 float r2 = p.y * sinHa + r * cosHa; 3819 return length(vec2(r2, y2)) - 0.15; 3820} 3821 3822float sdStar(vec3 p) { 3823 // Extruded 5-pointed star 3824 float d2 = abs(p.y) - 0.3; 3825 vec2 q = p.xz; 3826 float a = atan(q.y, q.x); 3827 float r = length(q); 3828 float star = r - 0.6 + 0.3 * cos(5.0 * a); 3829 return max(star, d2) - u_roundness * 0.05; 3830} 3831 3832float sdHeart(vec3 p) { 3833 p.y -= 0.2; 3834 p *= 1.2; 3835 float x2 = p.x * p.x; 3836 float y = p.y; 3837 float z2 = p.z * p.z; 3838 float cube = x2 + 2.25 * y * y + z2 - 1.0; 3839 return (cube * cube * cube - (x2 + 0.075 * z2) * y * y * y) * 0.5; 3840} 3841 3842float sdGyroid(vec3 p) { 3843 p *= 3.14159; 3844 return (sin(p.x) * cos(p.y) + sin(p.y) * cos(p.z) + sin(p.z) * cos(p.x)) / 3.14159 * 0.35; 3845} 3846 3847// ---- Smooth CSG operators ---- 3848float smin(float a, float b, float k) { 3849 float h = clamp(0.5 + 0.5 * (b - a) / max(k, 0.001), 0.0, 1.0); 3850 return mix(b, a, h) - k * h * (1.0 - h); 3851} 3852 3853float smax(float a, float b, float k) { 3854 return -smin(-a, -b, k); 3855} 3856 3857// ---- Diamond / faceted gem ---- 3858float sdDiamond(vec3 p) { 3859 float top = (abs(p.x) + abs(p.z)) * 0.707 + p.y * 0.8 - 0.5; 3860 float bottom = (abs(p.x) + abs(p.z)) * 0.707 - p.y * 0.5 - 0.7; 3861 return max(top, bottom) - u_roundness * 0.05; 3862} 3863 3864// ---- Teardrop / water drop ---- 3865float sdTeardrop(vec3 p) { 3866 vec3 q = p; 3867 q.y -= 0.2; 3868 float body = length(q) - 0.7; 3869 float tip = length(vec3(q.x * 0.5, q.y - 0.7, q.z * 0.5)) - 0.15; 3870 return smin(body, tip, 0.4); 3871} 3872 3873// ---- Double helix / DNA ---- 3874float sdHelix(vec3 p) { 3875 float bestD = 1e10; 3876 for (int i = 0; i < 64; i++) { 3877 float t = float(i) / 64.0 * 12.566; // 2 full turns 3878 float h = t / 6.283 - 1.0; 3879 vec3 c1 = vec3(0.5 * cos(t), h, 0.5 * sin(t)); 3880 vec3 c2 = vec3(0.5 * cos(t + 3.14159), h, 0.5 * sin(t + 3.14159)); 3881 bestD = min(bestD, min(length(p - c1), length(p - c2))); 3882 } 3883 return bestD - 0.09 - u_roundness * 0.04; 3884} 3885 3886// ---- Pyramid (square base) ---- 3887float sdPyramid(vec3 p) { 3888 float h = 1.2; 3889 vec3 q = abs(p); 3890 float base = max(q.x, q.z) - 0.8 + p.y * 0.65; 3891 float cap = p.y - h * 0.5; 3892 float floor_ = -p.y - h * 0.3; 3893 return max(max(base, cap), floor_) - u_roundness * 0.05; 3894} 3895 3896// ---- Helical spring / coil ---- 3897float sdSpring(vec3 p) { 3898 float bestD = 1e10; 3899 for (int i = 0; i < 48; i++) { 3900 float t = float(i) / 48.0 * 18.8496; // 3 coils 3901 float h = t / 6.28318 * 0.4 - 0.9; 3902 vec3 c = vec3(0.5 * cos(t), h, 0.5 * sin(t)); 3903 bestD = min(bestD, length(p - c)); 3904 } 3905 return bestD - 0.1 - u_roundness * 0.04; 3906} 3907 3908// ---- (3,2) torus knot ---- 3909float sdTorusKnot(vec3 p) { 3910 float bestD = 1e10; 3911 for (int i = 0; i < 64; i++) { 3912 float t = float(i) / 64.0 * 6.28318; 3913 float r = 0.6 + 0.25 * cos(3.0 * t); 3914 vec3 c = vec3(r * cos(2.0 * t), 0.25 * sin(3.0 * t), r * sin(2.0 * t)); 3915 bestD = min(bestD, length(p - c)); 3916 }
3917 return bestD - 0.1 - u_roundness * 0.03; 3918} 3919 3920// ---- Nautilus shell (logarithmic spiral) ---- 3921float sdShell(vec3 p) { 3922 float bestD = 1e10; 3923 for (int i = 0; i < 64; i++) { 3924 float t = float(i) / 64.0 * 9.4248; // 1.5 turns 3925 float growthRate = exp(0.18 * t); 3926 float r = 0.08 * growthRate; 3927 float cr = max(r * 0.35, 0.04); 3928 vec3 c = vec3(r * cos(t), t * 0.06 - 0.4, r * sin(t)); 3929 bestD = min(bestD, length(p - c) - cr); 3930 } 3931 return bestD; 3932} 3933 3934// ---- 3D cross ---- 3935float sdCross(vec3 p) { 3936 vec3 q = abs(p); 3937 float dx = max(q.y, q.z) - 0.3; 3938 float dy = max(q.x, q.z) - 0.3; 3939 float dz = max(q.x, q.y) - 0.3; 3940 float d = min(min( 3941 max(dx, q.x - 1.0), 3942 max(dy, q.y - 1.0)), 3943 max(dz, q.z - 1.0)); 3944 return d - u_roundness * 0.08; 3945} 3946 3947// ---- Shape dispatcher ---- 3948float evalShape(vec3 p, int shape) { 3949 // Apply twist 3950 if (abs(u_twist) > 0.001) { 3951 p.xz = rot2(p.y * u_twist) * p.xz; 3952 } 3953 p /= max(u_shapeScale, 0.01); 3954 3955 float d; 3956 if (shape == 0) d = sdSphere(p); 3957 else if (shape == 1) d = sdTorus(p); 3958 else if (shape == 2) d = sdCube(p); 3959 else if (shape == 3) d = sdOctahedron(p); 3960 else if (shape == 4) d = sdCylinder(p); 3961 else if (shape == 5) d = sdCone(p); 3962 else if (shape == 6) d = sdCapsule(p); 3963 else if (shape == 7) d = sdKnot(p); 3964 else if (shape == 8) d = sdMobius(p); 3965 else if (shape == 9) d = sdHeart(p); 3966 else if (shape == 10) d = sdStar(p); 3967 else if (shape == 11) d = sdGyroid(p); 3968 else if (shape == 12) d = sdDiamond(p); 3969 else if (shape == 13) d = sdTeardrop(p); 3970 else if (shape == 14) d = sdHelix(p); 3971 else if (shape == 15) d = sdPyramid(p); 3972 else if (shape == 16) d = sdSpring(p); 3973 else if (shape == 17) d = sdTorusKnot(p); 3974 else if (shape == 18) d = sdShell(p); 3975 else d = sdCross(p); 3976 3977 return d * u_shapeScale; 3978} 3979 3980// ---- Scene SDF ---- 3981float sceneSDF(vec3 p) { 3982 float d1 = evalShape(p, u_surfaceShape); 3983 3984 if (u_csgOp > 0) { 3985 float d2 = evalShape(p, u_csgShape); 3986 float k = u_csgBlend; 3987 if (u_csgOp == 1) d1 = smin(d1, d2, k); // union 3988 else if (u_csgOp == 2) d1 = smax(d1, -d2, k); // subtract 3989 else if (u_csgOp == 3) d1 = smax(d1, d2, k); // intersect 3990 } 3991 3992 return d1; 3993} 3994 3995// ---- Normal via central differences ---- 3996vec3 calcNormal(vec3 p) { 3997 const float h = 0.001; 3998 vec2 e = vec2(h, 0.0); 3999 return normalize(vec3( 4000 sceneSDF(p + e.xyy) - sceneSDF(p - e.xyy), 4001 sceneSDF(p + e.yxy) - sceneSDF(p - e.yxy), 4002 sceneSDF(p + e.yyx) - sceneSDF(p - e.yyx) 4003 )); 4004} 4005 4006// ---- Soft shadows (quality-adaptive) ---- 4007float softShadow(vec3 ro, vec3 rd, float tMin, float tMax) { 4008 float res = 1.0; 4009 float t = tMin; 4010 float k = u_shadowSoftness; 4011 int maxSteps = u_qualityTier == 0 ? 8 : u_qualityTier == 1 ? 16 : u_qualityTier == 2 ? 24 : 32; 4012 for (int i = 0; i < 32; i++) { 4013 if (i >= maxSteps || t >= tMax) break; 4014 float d = sceneSDF(ro + rd * t); 4015 if (d < 0.001) return 0.0; 4016 res = min(res, k * d / t); 4017 t += clamp(d, 0.02, 0.2); 4018 } 4019 return clamp(res, 0.0, 1.0); 4020} 4021 4022// ---- Ambient occlusion (quality-adaptive) ---- 4023float calcAO(vec3 p, vec3 n) { 4024 float occ = 0.0; 4025 float w = 1.0; 4026 int aoSamples = u_qualityTier == 0 ? 2 : u_qualityTier == 1 ? 3 : u_qualityTier == 2 ? 4 : 5; 4027 for (int i = 0; i < 5; i++) { 4028 if (i >= aoSamples) break; 4029 float dist = u_aoRadius * (1.0 + float(i)); 4030 float d = sceneSDF(p + n * dist); 4031 occ += (dist - d) * w; 4032 w *= 0.5; 4033 } 4034 return clamp(1.0 - u_aoStrength * occ * 3.0, 0.0, 1.0); 4035} 4036 4037// ---- Simplex 3D noise (Ashima / Stefan Gustavson) ---- 4038vec4 mod289_4(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } 4039vec3 mod289_3n(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } 4040vec4 permute4(vec4 x) { return mod289_4(((x * 34.0) + 1.0) * x); } 4041vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } 4042 4043float snoise(vec3 v) { 4044 const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); 4045 const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); 4046 vec3 i = floor(v + dot(v, C.yyy)); 4047 vec3 x0 = v - i + dot(i, C.xxx); 4048 vec3 g = step(x0.yzx, x0.xyz); 4049 vec3 l = 1.0 - g; 4050 vec3 i1 = min(g.xyz, l.zxy); 4051 vec3 i2 = max(g.xyz, l.zxy); 4052 vec3 x1 = x0 - i1 + C.xxx; 4053 vec3 x2 = x0 - i2 + C.yyy; 4054 vec3 x3 = x0 - D.yyy; 4055 i = mod289_3n(i); 4056 vec4 p = permute4(permute4(permute4( 4057 i.z + vec4(0.0, i1.z, i2.z, 1.0)) 4058 + i.y + vec4(0.0, i1.y, i2.y, 1.0)) 4059 + i.x + vec4(0.0, i1.x, i2.x, 1.0)); 4060 float n_ = 0.142857142857; 4061 vec3 ns = n_ * D.wyz - D.xzx; 4062 vec4 j = p - 49.0 * floor(p * ns.z * ns.z); 4063 vec4 x_ = floor(j * ns.z); 4064 vec4 y_ = floor(j - 7.0 * x_); 4065 vec4 x = x_ * ns.x + ns.yyyy; 4066 vec4 y = y_ * ns.x + ns.yyyy; 4067 vec4 h = 1.0 - abs(x) - abs(y); 4068 vec4 b0 = vec4(x.xy, y.xy); 4069 vec4 b1 = vec4(x.zw, y.zw); 4070 vec4 s0 = floor(b0) * 2.0 + 1.0; 4071 vec4 s1 = floor(b1) * 2.0 + 1.0; 4072 vec4 sh = -step(h, vec4(0.0)); 4073 vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; 4074 vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; 4075 vec3 p0 = vec3(a0.xy, h.x); 4076 vec3 p1 = vec3(a0.zw, h.y); 4077 vec3 p2 = vec3(a1.xy, h.z); 4078 vec3 p3 = vec3(a1.zw, h.w); 4079 vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2,p2), dot(p3,p3))); 4080 p0 *= norm.x; p1 *= norm.y; p2 *= norm.z; p3 *= norm.w; 4081 vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); 4082 m = m * m; 4083 return 42.0 * dot(m * m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3))); 4084} 4085 4086// ---- Curl noise flow field ---- 4087vec3 curlNoise(vec3 p) { 4088 const float e = 0.001; 4089 vec3 dx = vec3(e, 0.0, 0.0); 4090 vec3 dy = vec3(0.0, e, 0.0); 4091 vec3 dz = vec3(0.0, 0.0, e); 4092 4093 float x = snoise(p + dy) - snoise(p - dy) 4094 - snoise(p + dz) + snoise(p - dz); 4095 float y = snoise(p + dz) - snoise(p - dz) 4096 - snoise(p + dx) + snoise(p - dx); 4097 float z = snoise(p + dx) - snoise(p - dx) 4098 - snoise(p + dy) + snoise(p - dy); 4099 4100 return vec3(x, y, z) / (2.0 * e); 4101} 4102
4103vec3 perturbNormal(vec3 n, vec3 p, float time) { 4104 vec3 flow = curlNoise(p * u_flowScale + time * u_flowSpeed * 0.1); 4105 float strength = u_flowIntensity; 4106 4107 // Build tangent frame 4108 vec3 tangent = normalize(cross(n, vec3(0.0, 1.0, 0.0))); 4109 if (length(tangent) < 0.001) tangent = normalize(cross(n, vec3(1.0, 0.0, 0.0))); 4110 vec3 bitangent = cross(n, tangent); 4111 4112 // Perturb normal along tangent plane 4113 n += (tangent * flow.x + bitangent * flow.y) * strength; 4114 return normalize(n); 4115} 4116 4117// ---- PBR Functions ---- 4118#define PI 3.14159265359 4119 4120// GGX Normal Distribution Function 4121float D_GGX(float NdotH, float roughness) { 4122 float a = roughness * roughness; 4123 float a2 = a * a; 4124 float NdotH2 = NdotH * NdotH; 4125 float denom = NdotH2 * (a2 - 1.0) + 1.0; 4126 return a2 / (PI * denom * denom + 0.0001); 4127} 4128 4129// Anisotropic GGX (Burley/Disney) 4130float D_GGX_Aniso(float NdotH, float TdotH, float BdotH, float ax, float ay) { 4131 float a2 = ax * ay; 4132 vec3 v = vec3(ay * TdotH, ax * BdotH, a2 * NdotH); 4133 float v2 = dot(v, v); 4134 float w2 = a2 / max(v2, 1e-7); 4135 return a2 * w2 * w2 / PI; 4136} 4137 4138// Smith GGX Geometry (height-correlated) 4139float G_Smith(float NdotV, float NdotL, float roughness) { 4140 float a = roughness * roughness; 4141 float a2 = a * a; 4142 float ggxV = NdotL * sqrt(NdotV * NdotV * (1.0 - a2) + a2); 4143 float ggxL = NdotV * sqrt(NdotL * NdotL * (1.0 - a2) + a2); 4144 return 0.5 / max(ggxV + ggxL, 0.001); 4145} 4146 4147// Schlick Fresnel with vec3 F0 (metals have colored F0) 4148vec3 F_Schlick(float cosTheta, vec3 F0) { 4149 return F0 + (vec3(1.0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); 4150} 4151 4152// Energy compensation for multiscatter GGX (Kulla-Conty 2017) 4153float E_GGX(float NdotV, float roughness) { 4154 float a = roughness; 4155 float t = 1.0 - NdotV; 4156 return 1.0 - 1.259 * a * t - 0.233 * a * a - 0.0391 * t * t 4157 + 0.423 * a * t * t + 0.137 * a * a * t; 4158} 4159 4160vec3 multiscatterCompensation(vec3 F0, float NdotV, float NdotL, float roughness) { 4161 float Eo = E_GGX(NdotV, roughness); 4162 float Ei = E_GGX(NdotL, roughness); 4163 vec3 Favg = F0 + (1.0 - F0) / 21.0; 4164 vec3 fms = (1.0 - Eo) * (1.0 - Ei) / (PI * (1.0 - Favg * (1.0 - Eo))); 4165 return fms * Favg; 4166} 4167 4168// Thin-film iridescence (simplified interference) 4169vec3 thinFilmIridescence(float cosTheta, float ior, float thickness) { 4170 float delta = 2.0 * ior * thickness * cosTheta; 4171 vec3 wavelengths = vec3(650.0, 510.0, 475.0); // R, G, B 4172 vec3 phase = 2.0 * PI * delta / wavelengths; 4173 return 0.5 + 0.5 * cos(phase); 4174} 4175 4176// Procedural environment map â multi-light studio HDRI approximation 4177// Falls back to procedural when HDRI cubemap is not available 4178vec3 proceduralEnv(vec3 dir, float roughness) { 4179 // Apply environment rotation 4180 float rotRad = radians(u_envRotation); 4181 dir.xz = mat2(cos(rotRad), -sin(rotRad), sin(rotRad), cos(rotRad)) * dir.xz; 4182 4183 // Use real HDRI cubemap when available 4184 if (u_useEnvMap == 1) { 4185 // Sample HDRI at multiple LODs to approximate roughness blur 4186 // textureCube LOD 0 = sharp, higher LODs = blurrier (mipmapped) 4187 vec3 hdriColor = texture(u_envMap, dir).rgb; 4188 // Approximate roughness blur by blending with a heavily averaged sample 4189 vec3 blurred = texture(u_envMap, normalize(dir + vec3(0.2, 0.1, -0.15))).rgb; 4190 blurred += texture(u_envMap, normalize(dir + vec3(-0.15, 0.2, 0.1))).rgb; 4191 blurred += texture(u_envMap, normalize(dir + vec3(0.1, -0.15, 0.2))).rgb; 4192 blurred *= 0.333; 4193 vec3 env = mix(hdriColor, blurred, roughness * 0.7); 4194 return env * u_envIntensity; 4195 } 4196 4197 // Fallback: procedural studio setup with 3 area lights + ambient dome 4198 4199 // Key light (large soft area light, upper-right) 4200 vec3 keyDir = normalize(vec3(1.0, 2.0, 0.5)); 4201 float keyAngle = max(dot(dir, keyDir), 0.0); 4202 float keySize = mix(0.3, 0.95, roughness); 4203 vec3 keyLight = vec3(1.2, 1.15, 1.1) * smoothstep(1.0 - keySize, 1.0, keyAngle); 4204 4205 // Fill light (medium area light, left) 4206 vec3 fillDir = normalize(vec3(-1.5, 0.5, 1.0)); 4207 float fillAngle = max(dot(dir, fillDir), 0.0); 4208 float fillSize = mix(0.2, 0.8, roughness); 4209 vec3 fillLight = vec3(0.4, 0.45, 0.55) * smoothstep(1.0 - fillSize, 1.0, fillAngle); 4210 4211 // Rim/back light (narrow, behind) 4212 vec3 rimDir = normalize(vec3(0.0, 0.3, -1.5)); 4213 float rimAngle = max(dot(dir, rimDir), 0.0); 4214 float rimSize = mix(0.05, 0.4, roughness); 4215 vec3 rimLight = vec3(0.8, 0.85, 1.0) * smoothstep(1.0 - rimSize, 1.0, rimAngle); 4216 4217 // Ambient dome (gradient from dark floor to bright ceiling) 4218 float skyGrad = dir.y * 0.5 + 0.5; 4219 vec3 dome = mix(vec3(0.02, 0.02, 0.03), vec3(0.15, 0.15, 0.18), skyGrad); 4220 4221 // Ground plane reflection (dark with slight warm tint) 4222 vec3 ground = vec3(0.03, 0.025, 0.02) * max(-dir.y, 0.0); 4223 4224 vec3 env = dome + keyLight + fillLight + rimLight + ground; 4225 4226 // Roughness blur (smooth out detail for rough surfaces) 4227 env = mix(env, vec3(dot(env, vec3(0.333))), roughness * 0.4); 4228 4229 return env * u_envIntensity; 4230} 4231 4232void main() { 4233 float time = u_time * u_speed; 4234 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 4235 4236 // Camera setup 4237 float yaw = radians(u_cameraYaw); 4238 float pitch = radians(u_cameraPitch); 4239 if (u_autoRotate > 0) { 4240 yaw += time * u_autoRotateSpeed * 0.5; 4241 } 4242 4243 vec3 camPos = vec3( 4244 u_cameraDistance * cos(pitch) * sin(yaw), 4245 u_cameraDistance * sin(pitch), 4246 u_cameraDistance * cos(pitch) * cos(yaw) 4247 ); 4248 vec3 target = vec3(0.0); 4249 vec3 forward = normalize(target - camPos); 4250 vec3 worldUp = vec3(0.0, 1.0, 0.0); 4251 vec3 right = normalize(cross(forward, worldUp)); 4252 vec3 up = cross(right, forward); 4253 4254 // Ray direction from UV + FOV 4255 float fovScale = tan(radians(u_cameraFov) * 0.5); 4256 vec2 warpedUv = applyMouseWarp(vUv, aspect); 4257 vec2 screenUV = (warpedUv - 0.5) * 2.0; 4258 screenUV.x *= aspect; 4259 vec3 rd = normalize(forward + screenUV.x * fovScale * right + screenUV.y * fovScale * up); 4260 4261 // Ray march (quality-adaptive steps) 4262 int maxSteps = u_qualityTier == 0 ? 40 : u_qualityTier == 1 ? 60 : u_qualityTier == 2 ? 80 : 100; 4263 float t = 0.0; 4264 float d; 4265 bool hit = false;
4266 for (int i = 0; i < 100; i++) { 4267 if (i >= maxSteps) break; 4268 vec3 p = camPos + rd * t; 4269 d = sceneSDF(p); 4270 if (d < 0.001) { hit = true; break; } 4271 if (t > 20.0) break; 4272 t += d; 4273 } 4274 4275 vec3 color; 4276 4277 if (hit) { 4278 vec3 p = camPos + rd * t; 4279 vec3 n = calcNormal(p); 4280 if (u_flowIntensity > 0.001) { 4281 n = perturbNormal(n, p, time); 4282 } 4283 vec3 viewDir = -rd; 4284 4285 // Light direction 4286 vec3 lightPos = vec3(u_lightX, u_lightY, u_lightZ); 4287 vec3 l = normalize(lightPos - p); 4288 vec3 h = normalize(l + viewDir); 4289 4290 // Dot products 4291 float NdotV = max(dot(n, viewDir), 0.001); 4292 float NdotL = max(dot(n, l), 0.0); 4293 float NdotH = max(dot(n, h), 0.0); 4294 float VdotH = max(dot(h, viewDir), 0.0); 4295 4296 // Gradient color -> albedo 4297 float gT = clamp(dot(n, viewDir) * 0.5 + p.y * 0.3 + 0.5, 0.0, 1.0); 4298 4299 // Image-driven gradient integration 4300 float imgLum = imageLuminance(gl_FragCoord.xy / u_resolution.xy, aspect); 4301 if (imgLum >= 0.0) { 4302 gT = mix(gT, imgLum, u_imageIntensity); 4303 } 4304 4305 vec3 albedo = mixColors(u_colors, u_colorPositions, u_colorCount, gT); 4306 4307 // PBR material 4308 float roughness = max(u_roughness, 0.04); 4309 vec3 F0 = mix(vec3(0.04), albedo, u_metallic); 4310 4311 // Tangent frame for anisotropy 4312 vec3 T = normalize(cross(n, abs(n.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0))); 4313 vec3 B = cross(n, T); 4314 4315 // Rotate tangent by anisotropy angle 4316 if (u_anisotropy > 0.001) { 4317 float aa = radians(u_anisotropyAngle); 4318 float cosA = cos(aa), sinA = sin(aa); 4319 vec3 T2 = T * cosA + B * sinA; 4320 B = -T * sinA + B * cosA; 4321 T = T2; 4322 } 4323 4324 // Normal Distribution 4325 float D; 4326 if (u_anisotropy > 0.001) { 4327 float anisAspect = sqrt(1.0 - 0.9 * u_anisotropy); 4328 float ax = roughness / anisAspect; 4329 float ay = roughness * anisAspect; 4330 float TdotH = dot(T, h); 4331 float BdotH = dot(B, h); 4332 D = D_GGX_Aniso(NdotH, TdotH, BdotH, ax, ay); 4333 } else { 4334 D = D_GGX(NdotH, roughness); 4335 } 4336 4337 // Geometry 4338 float G = G_Smith(NdotV, NdotL, roughness); 4339 4340 // Fresnel 4341 vec3 F = F_Schlick(VdotH, F0); 4342 4343 // Specular BRDF (denominator baked into G_Smith) 4344 vec3 singleScatter = (D * G) * F; 4345 vec3 multiScatter = multiscatterCompensation(F0, NdotV, NdotL, roughness); 4346 vec3 specular = singleScatter + multiScatter; 4347 4348 // Energy conservation 4349 vec3 kD = (vec3(1.0) - F) * (1.0 - u_metallic); 4350 vec3 diffuse = kD * albedo / PI; 4351 4352 // Shadows & AO 4353 float shadow = softShadow(p + n * 0.01, l, 0.02, 10.0); 4354 float ao = calcAO(p, n); 4355 4356 // Direct lighting 4357 vec3 Lo = (diffuse + specular) * NdotL * vec3(1.0) * shadow; 4358 4359 // Environment reflections 4360 vec3 reflDir = reflect(-viewDir, n); 4361 vec3 envSpec = proceduralEnv(reflDir, roughness); 4362 vec3 envF = F_Schlick(NdotV, F0); 4363 vec3 envReflection = envSpec * envF; 4364 4365 // Diffuse IBL 4366 vec3 envDiffuse = proceduralEnv(n, 1.0) * kD * albedo; 4367 4368 // Iridescence 4369 if (u_iridescence > 0.001) { 4370 float thickness = 400.0 + 300.0 * (1.0 - NdotV); 4371 vec3 iriColor = thinFilmIridescence(NdotV, u_iridescenceIOR, thickness); 4372 envReflection = mix(envReflection, envReflection * iriColor * 2.0, u_iridescence); 4373 Lo = mix(Lo, Lo * iriColor, u_iridescence * 0.5); 4374 } 4375 4376 // Clearcoat 4377 if (u_clearcoat > 0.001) { 4378 float ccRough = max(u_clearcoatRoughness, 0.04); 4379 float Dc = D_GGX(NdotH, ccRough); 4380 float Gc = G_Smith(NdotV, NdotL, ccRough); 4381 float Fc = 0.04 + 0.96 * pow(1.0 - VdotH, 5.0); 4382 vec3 ccSpec = vec3(Dc * Gc * Fc); 4383 Lo += ccSpec * u_clearcoat * NdotL * shadow; 4384 envReflection += proceduralEnv(reflDir, ccRough) * Fc * u_clearcoat; 4385 } 4386 4387 // Combine 4388 vec3 ambient = albedo * u_ambient * ao; 4389 color = ambient + Lo + (envReflection + envDiffuse) * ao; 4390 4391 // Grain â only inside shape 4392 color += grain(vUv, time, u_grain * 0.75); 4393 4394 // Self-blend â only inside shape 4395 if (u_blendMode > 0) { 4396 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 4397 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 4398 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 4399 bIntensity = noiseModulatedIntensity(bIntensity, vUv, time, u_blendNoiseMask, u_blendNoiseScale); 4400 bIntensity = applyBlendFalloff(bIntensity, vUv.x, u_blendFalloff);
4401 float tB = blendLayerT(vUv, 0.5, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 4402 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 4403 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 4404 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 4405 float tB2 = blendLayerT(vUv, 0.5, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 4406 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 4407 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 4408 } 4409 } 4410 4411 fragColor = outputColor(color, gl_FragCoord.xy, 1.1); 4412 } else { 4413 // Background â transparent for export, dark for viewport 4414 if (u_transparentBg == 1) { 4415 fragColor = vec4(0.0); 4416 } else { 4417 float vignette = 1.0 - 0.3 * length(vUv - 0.5); 4418 vec3 bgColor = vec3(0.03 * u_bgGradient * vignette); 4419 fragColor = outputColor(bgColor, gl_FragCoord.xy, 1.1); 4420 } 4421 } 4422} 4423`,g=`#version 300 es 4424precision highp float; 4425 4426in vec2 vUv; 4427out vec4 fragColor; 4428 4429uniform float u_time; 4430uniform float u_speed; 4431uniform vec3 u_colors[12]; 4432uniform float u_colorPositions[12]; 4433uniform int u_colorCount; 4434uniform float u_direction; 4435uniform float u_grain; 4436uniform vec2 u_resolution; 4437 4438// Blend uniforms 4439uniform int u_blendMode; 4440uniform float u_blendIntensity; 4441uniform float u_blendOffset; 4442uniform float u_blendRotation; 4443uniform float u_blendScale; 4444uniform int u_blendAnimRotation; 4445uniform int u_blendAnimIntensity; 4446uniform int u_blendAnimOffset; 4447uniform float u_blendAnimSpeed; 4448uniform float u_blendNoiseMask; 4449uniform float u_blendNoiseScale; 4450uniform float u_blendFalloff; 4451uniform int u_blendDualLayer; 4452uniform int u_blendMode2; 4453uniform float u_blendIntensity2; 4454uniform float u_blendOffset2; 4455uniform float u_blendRotation2; 4456uniform float u_blendScale2; 4457 4458// Mode-specific uniforms 4459uniform int u_reactiveStyle; 4460uniform int u_fftSize; 4461uniform float u_bassSensitivity; 4462uniform float u_midSensitivity; 4463uniform float u_trebleSensitivity; 4464uniform float u_smoothing; 4465uniform float u_reactiveScale; 4466uniform float u_reactiveSpeed; 4467uniform float u_colorReactivity; 4468 4469// Band isolation uniforms 4470uniform int u_bassTarget; // 0=scale, 1=warp, 2=color, 3=brightness, 4=speed 4471uniform int u_midTarget; 4472uniform int u_trebleTarget; 4473uniform float u_bassSmoothing; 4474uniform float u_trebleSmoothing; 4475 4476// Audio feature uniforms (bound by canvas, not from state) 4477uniform float u_bass; 4478uniform float u_mid; 4479uniform float u_treble; 4480uniform float u_energy; 4481uniform float u_peak; 4482uniform float u_beat; 4483uniform sampler2D u_spectrum; 4484 4485__COMMON__ 4486 4487// --- Helpers --- 4488 4489// Simple hash for value noise 4490float arHash(vec2 p) { 4491 return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); 4492} 4493 4494// Value noise 2D 4495float arNoise(vec2 p) { 4496 vec2 i = floor(p); 4497 vec2 f = fract(p); 4498 f = f * f * (3.0 - 2.0 * f); 4499 return mix( 4500 mix(arHash(i), arHash(i + vec2(1.0, 0.0)), f.x), 4501 mix(arHash(i + vec2(0.0, 1.0)), arHash(i + vec2(1.0, 1.0)), f.x), 4502 f.y 4503 ); 4504} 4505 4506// FBM using value noise (separate from common.glsl simplex fbm) 4507float arFbm(vec2 p, int octaves) { 4508 float sum = 0.0; 4509 float amp = 0.5; 4510 for (int i = 0; i < 8; i++) { 4511 if (i >= octaves) break; 4512 sum += amp * arNoise(p); 4513 p *= 2.0; 4514 amp *= 0.5; 4515 } 4516 return sum; 4517} 4518 4519// Spectrum texture lookup (128x1 R32F on TEXTURE1) 4520// Returns 0.0 when no audio source is connected (texture is zeroed) 4521float getSpectrum(float freq) { 4522 return texture(u_spectrum, vec2(clamp(freq, 0.0, 1.0), 0.5)).r; 4523} 4524 4525// ---- Band-driven visual property helpers ---- 4526// Each band (bass/mid/treble) can target a visual property (scale/warp/color/brightness/speed). 4527// These helpers accumulate contributions from all bands that target a given property. 4528 4529float getScaleDriver(float bass, float mid, float treble) { 4530 float v = 0.0; 4531 if (u_bassTarget == 0) v += bass; 4532 if (u_midTarget == 0) v += mid; 4533 if (u_trebleTarget == 0) v += treble; 4534 return v; 4535} 4536 4537float getWarpDriver(float bass, float mid, float treble) { 4538 float v = 0.0; 4539 if (u_bassTarget == 1) v += bass; 4540 if (u_midTarget == 1) v += mid; 4541 if (u_trebleTarget == 1) v += treble; 4542 return v; 4543} 4544 4545float getColorDriver(float bass, float mid, float treble) { 4546 float v = 0.0; 4547 if (u_bassTarget == 2) v += bass; 4548 if (u_midTarget == 2) v += mid; 4549 if (u_trebleTarget == 2) v += treble; 4550 return v; 4551} 4552 4553float getBrightnessDriver(float bass, float mid, float treble) { 4554 float v = 0.0; 4555 if (u_bassTarget == 3) v += bass; 4556 if (u_midTarget == 3) v += mid; 4557 if (u_trebleTarget == 3) v += treble; 4558 return v; 4559} 4560 4561float getSpeedDriver(float bass, float mid, float treble) { 4562 float v = 0.0; 4563 if (u_bassTarget == 4) v += bass; 4564 if (u_midTarget == 4) v += mid; 4565 if (u_trebleTarget == 4) v += treble; 4566 return v; 4567} 4568 4569void main() { 4570 vec2 uv = vUv; 4571 float t = u_time * u_speed * u_reactiveSpeed; 4572 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 4573 uv = applyMouseWarp(uv, aspect); 4574 4575 // Scale audio features by sensitivity 4576 float bass = u_bass * u_bassSensitivity; 4577 float mid = u_mid * u_midSensitivity; 4578 float treble = u_treble * u_trebleSensitivity; 4579 float energy = u_energy; 4580 float peak = u_peak; 4581 float beat = u_beat; 4582 4583 // Band isolation: compute visual property drivers from band targets 4584 float scaleDriver = getScaleDriver(bass, mid, treble); 4585 float warpDriver = getWarpDriver(bass, mid, treble); 4586 float colorDriver = getColorDriver(bass, mid, treble); 4587 float brightnessDriver = getBrightnessDriver(bass, mid, treble); 4588 float speedDriver = getSpeedDriver(bass, mid, treble); 4589 4590 vec3 color = vec3(0.0); 4591 float colorPos = 0.0; 4592 4593 if (u_reactiveStyle == 0) { 4594 // ========== PULSE ========== 4595 // Radial gradient that expands/contracts with bass. Colors shift with 4596 // mid/treble. Beats trigger a bright flash overlay. 4597 4598 vec2 center = vec2(0.5); 4599 vec2 p = (uv - center) * vec2(aspect, 1.0); 4600 float dist = length(p); 4601 4602 // Pulsing radius driven by bass 4603 float radius = (0.2 + scaleDriver * 0.4) * u_reactiveScale; 4604 4605 // Soft radial falloff 4606 float pulse = smoothstep(radius, radius * 0.3, dist); 4607 4608 // Concentric rings that expand outward on beats 4609 float ringPhase = dist * 20.0 - t * 3.0 - beat * 6.28318; 4610 float rings = sin(ringPhase) * 0.5 + 0.5; 4611 rings *= smoothstep(1.0, 0.0, dist); 4612 4613 // Color position: distance-based + audio modulation 4614 colorPos = dist / max(u_reactiveScale, 0.01) + energy * u_colorReactivity * 0.5; 4615 colorPos = fract(colorPos + t * 0.1 + colorDriver * 0.2); 4616 4617 color = mixColors(u_colors, u_colorPositions, u_colorCount, colorPos); 4618 color *= pulse + rings * 0.3; 4619 4620 // Beat flash: bright white burst 4621 color += vec3(beat * 0.3 * peak); 4622 4623 // Treble shimmer on outer edge 4624 float shimmer = arNoise(p * 12.0 + t * 2.0) * treble * 0.15; 4625 color += mixColors(u_colors, u_colorPositions, u_colorCount, fract(colorPos + 0.3)) * shimmer * smoothstep(0.0, 0.5, dist); 4626 4627 } else if (u_reactiveStyle == 1) { 4628 // ========== WAVEFORM ========== 4629 // Horizontal waveform visualization. Multiple layered waves respond to 4630 // different frequency bands. Glow-line aesthetic. 4631 4632 vec2 p = (uv - 0.5) * vec2(aspect, 1.0); 4633 4634 // Three frequency-band waves layered 4635 float wave1 = sin(p.x * 8.0 + t * 2.0) * scaleDriver * 0.15 * u_reactiveScale; 4636 float wave2 = sin(p.x * 15.0 - t * 3.0) * warpDriver * 0.1 * u_reactiveScale; 4637 float wave3 = sin(p.x * 25.0 + t * 5.0) * treble * 0.06 * u_reactiveScale; 4638 4639 // Composite waveform 4640 float waveY = wave1 + wave2 + wave3; 4641 float dist = abs(p.y - waveY); 4642 4643 // Glow lines: bright core with soft falloff 4644 float glow = 0.008 / (dist + 0.008); 4645 // Secondary traces for each band 4646 glow += 0.003 / (abs(p.y - wave1) + 0.003) * 0.5; 4647 glow += 0.002 / (abs(p.y - wave2 * 1.5) + 0.002) * 0.3; 4648 glow += 0.0015 / (abs(p.y + wave3 * 0.8) + 0.0015) * 0.2; 4649 4650 colorPos = fract(uv.x + energy * u_colorReactivity * 0.3 + t * 0.05); 4651 color = mixColors(u_colors, u_colorPositions, u_colorCount, colorPos); 4652 color *= glow; 4653 4654 // Beat brightens the whole field 4655 color += vec3(beat * 0.15); 4656 4657 // Subtle background tint so it is not pure black 4658 vec3 bgTint = mixColors(u_colors, u_colorPositions, u_colorCount, uv.y) * 0.03; 4659 color += bgTint; 4660 4661 } else if (u_reactiveStyle == 2) { 4662 // ========== SPECTRUM ========== 4663 // Vertical bars representing FFT bins. Classic audio visualizer look 4664 // with gradient-colored bars and top-glow caps. 4665 4666 float binCount = max(float(u_fftSize) / 2.0, 1.0); 4667 // Limit visible bars to keep it readable 4668 float visibleBars = min(binCount, 128.0); 4669 float barWidth = 1.0 / visibleBars; 4670 float barIndex = floor(uv.x / barWidth); 4671 float freq = barIndex / visibleBars; 4672 4673 // Read spectrum and apply per-band sensitivity 4674 float specVal = getSpectrum(freq); 4675 float bandMul = freq < 0.15 ? u_bassSensitivity 4676 : (freq < 0.5 ? u_midSensitivity : u_trebleSensitivity); 4677 specVal *= bandMul * u_reactiveScale; 4678 4679 // Bar height mask (bars grow upward from bottom) 4680 float barHeight = clamp(specVal, 0.0, 1.0); 4681 float barMask = step(1.0 - uv.y, barHeight); 4682 4683 // Gradient color along frequency axis 4684 colorPos = fract(freq + energy * u_colorReactivity * 0.2); 4685 color = mixColors(u_colors, u_colorPositions, u_colorCount, colorPos); 4686
4687 // Smooth bar edges for anti-aliased look 4688 float barLocal = fract(uv.x / barWidth); 4689 float edgeFade = smoothstep(0.0, 0.15, barLocal) * smoothstep(1.0, 0.85, barLocal); 4690 4691 color *= barMask * edgeFade; 4692 4693 // Glowing cap at the top of each bar 4694 float topDist = abs((1.0 - uv.y) - barHeight); 4695 float topGlow = 0.005 / (topDist + 0.005); 4696 vec3 capColor = mixColors(u_colors, u_colorPositions, u_colorCount, freq); 4697 color += capColor * topGlow * 0.3 * step(0.001, barHeight); 4698 4699 // Beat pulse 4700 color += vec3(beat * 0.1); 4701 4702 // Height-based brightness: brighter at the top of bars 4703 color *= 0.7 + 0.3 * (1.0 - uv.y); 4704 4705 } else if (u_reactiveStyle == 3) { 4706 // ========== NEBULA ========== 4707 // Fractal noise nebula that breathes and swirls with audio energy. 4708 // Bass drives scale, treble drives detail, beats create bright bursts. 4709 4710 vec2 p = (uv - 0.5) * 3.0 * u_reactiveScale; 4711 float scale = 2.0 + scaleDriver * 2.0; 4712 4713 // Domain warp driven by energy 4714 vec2 warp = vec2( 4715 arFbm(p * scale + vec2(t * 0.3, 0.0), 5), 4716 arFbm(p * scale + vec2(0.0, t * 0.3), 5) 4717 ) * (0.5 + warpDriver * 1.0 + energy * 0.5); 4718 4719 // Treble adds extra octaves of detail 4720 int detailOctaves = 4 + int(treble * 3.0); 4721 float n = arFbm(p * scale + warp + vec2(t * 0.2), detailOctaves); 4722 n = n * 0.5 + 0.5; // remap 0-1 4723 4724 // Audio modulation of the field 4725 n += scaleDriver * 0.2 - treble * 0.1; 4726 n += beat * 0.15; 4727 n = clamp(n, 0.0, 1.0); 4728 4729 // Ridged variant for filament structures 4730 float ridged = 1.0 - abs(arFbm(p * scale * 1.5 + warp * 0.7, 4) * 2.0 - 1.0); 4731 ridged = pow(ridged, 1.5) * mid * 0.3; 4732 4733 colorPos = fract(n + ridged * 0.2 + energy * u_colorReactivity * 0.3); 4734 color = mixColors(u_colors, u_colorPositions, u_colorCount, colorPos); 4735 4736 // Brightness: base level + energy boost + beat burst 4737 float brightness = 0.5 + brightnessDriver * 0.3 + energy * 0.3 + beat * 0.3; 4738 color *= brightness; 4739 4740 // Add hot emission near ridges 4741 vec3 hotColor = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(colorPos + 0.25, 0.0, 1.0)); 4742 color += hotColor * ridged * 0.4; 4743 4744 } else if (u_reactiveStyle == 4) { 4745 // ========== RINGS ========== 4746 // Concentric rings pulse outward with beats. Ring spacing and thickness 4747 // react to bass/mid. Colors cycle with energy. 4748 4749 vec2 center = vec2(0.5); 4750 vec2 p = (uv - center) * vec2(aspect, 1.0); 4751 float dist = length(p); 4752 4753 // Ring geometry driven by audio 4754 float ringSpacing = 0.08 + scaleDriver * 0.06; 4755 float ringWidth = 0.02 + warpDriver * 0.02; 4756 4757 // Multiple expanding rings 4758 float rings = 0.0; 4759 for (int i = 0; i < 8; i++) { 4760 float r = float(i) * ringSpacing + fract(t * 0.5) * ringSpacing; 4761 float d = abs(dist - r); 4762 rings += ringWidth / (d + ringWidth); 4763 } 4764 rings = min(rings, 3.0) / 3.0; 4765 4766 // Beat creates a bright expanding ring burst 4767 float beatRing = beat * 2.0 / (abs(dist - fract(t * 0.8) * 0.5) + 0.05); 4768 beatRing = min(beatRing, 2.0); 4769 4770 // Treble adds a fine interference pattern 4771 float interference = sin(dist * 60.0 - t * 8.0) * 0.5 + 0.5; 4772 interference *= treble * 0.15; 4773 4774 colorPos = fract(dist / max(u_reactiveScale, 0.01) + energy * u_colorReactivity + t * 0.1); 4775 color = mixColors(u_colors, u_colorPositions, u_colorCount, colorPos); 4776 color *= rings + beatRing * 0.2 + interference; 4777 4778 // Center glow 4779 float centerGlow = exp(-dist * 4.0) * (0.3 + energy * 0.4); 4780 vec3 glowColor = mixColors(u_colors, u_colorPositions, u_colorCount, fract(colorPos + 0.5)); 4781 color += glowColor * centerGlow; 4782 4783 } else if (u_reactiveStyle == 5) { 4784 // ========== LIQUID ========== 4785 // Fluid simulation-like distortion. Energy drives flow speed, bass warps 4786 // the field, treble adds fine-detail turbulence. 4787 4788 vec2 p = uv * 3.0 * u_reactiveScale; 4789 4790 // Flow field warped by audio 4791 float flowSpeed = 0.3 + speedDriver * 0.3 + energy * 0.4; 4792 vec2 flow = vec2( 4793 arFbm(p + vec2(t * flowSpeed, 0.0), 4), 4794 arFbm(p + vec2(0.0, t * flowSpeed), 4) 4795 ); 4796 4797 // Bass warps the field broadly, treble adds fine turbulence 4798 vec2 warp = flow * (0.3 + warpDriver * 0.5); 4799 float turbulence = arFbm(p * (3.0 + treble * 4.0) + warp + vec2(t * 0.5), 5); 4800 4801 // Combine layers 4802 float n = arFbm(p + warp + vec2(turbulence * 0.3), 4); 4803 n = n * 0.5 + 0.5; 4804 4805 // Secondary flow for depth 4806 float n2 = arFbm(p * 1.5 - warp * 0.8 + vec2(t * 0.3, -t * 0.2), 3); 4807 n2 = n2 * 0.5 + 0.5; 4808 4809 // Blend the two fields 4810 float blend = mix(n, n2, 0.3 + colorDriver * 0.2); 4811 4812 // Energy drives overall intensity 4813 blend = blend * (0.6 + energy * 0.4); 4814 blend += beat * 0.1; 4815 blend = clamp(blend, 0.0, 1.0); 4816 4817 colorPos = fract(blend + energy * u_colorReactivity * 0.2 + t * 0.05); 4818 color = mixColors(u_colors, u_colorPositions, u_colorCount, colorPos); 4819 4820 // Peak brightness modulation 4821 color *= 0.7 + peak * 0.3; 4822 4823 // Subtle caustic highlights 4824 float caustic = pow(max(sin(n * 6.28318 + t) * 0.5 + 0.5, 0.0
4824), 3.0) * mid * 0.2; 4825 vec3 causticColor = mixColors(u_colors, u_colorPositions, u_colorCount, fract(colorPos + 0.4)); 4826 color += causticColor * caustic; 4827 } 4828 4829 // Grain 4830 color += grain(uv, t, u_grain); 4831 4832 // Self-blend (consistent with all other shaders) 4833 if (u_blendMode > 0) { 4834 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, t, u_blendAnimSpeed) : u_blendRotation; 4835 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, t, u_blendAnimSpeed) : u_blendOffset; 4836 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, t, u_blendAnimSpeed) : u_blendIntensity; 4837 bIntensity = noiseModulatedIntensity(bIntensity, uv, t, u_blendNoiseMask, u_blendNoiseScale); 4838 bIntensity = applyBlendFalloff(bIntensity, uv.x, u_blendFalloff); 4839 float tB = blendLayerT(uv, 0.5, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 4840 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 4841 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 4842 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 4843 float tB2 = blendLayerT(uv, 0.5, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 4844 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 4845 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 4846 } 4847 } 4848 4849 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 4850} 4851`,h=`#version 300 es 4852precision highp float; 4853 4854in vec2 vUv; 4855out vec4 fragColor; 4856 4857uniform float u_time; 4858uniform float u_speed; 4859uniform vec3 u_colors[12]; 4860uniform float u_colorPositions[12]; 4861uniform int u_colorCount; 4862uniform float u_direction; 4863uniform float u_grain; 4864uniform vec2 u_resolution; 4865 4866// Blend uniforms 4867uniform int u_blendMode; 4868uniform float u_blendIntensity; 4869uniform float u_blendOffset; 4870uniform float u_blendRotation; 4871uniform float u_blendScale; 4872uniform int u_blendAnimRotation; 4873uniform int u_blendAnimIntensity; 4874uniform int u_blendAnimOffset; 4875uniform float u_blendAnimSpeed; 4876uniform float u_blendNoiseMask; 4877uniform float u_blendNoiseScale; 4878uniform float u_blendFalloff; 4879uniform int u_blendDualLayer; 4880uniform int u_blendMode2; 4881uniform float u_blendIntensity2; 4882uniform float u_blendOffset2; 4883uniform float u_blendRotation2; 4884uniform float u_blendScale2; 4885 4886// Mode-specific 4887uniform int u_chromeStyle; 4888uniform int u_warpIterations; 4889uniform float u_warpAmplitude; 4890uniform float u_warpFrequency; 4891uniform float u_specularSharpness; 4892uniform float u_specularIntensity; 4893uniform float u_chromaticAberration; 4894uniform float u_flowSpeed; 4895 4896__COMMON__ 4897 4898// Chrome style color tints applied in specular 4899vec3 getChromeBaseColor(int style, float height) { 4900 // 0=silver, 1=gold, 2=copper, 3=neon, 4=custom (uses gradient) 4901 if (style == 1) return mix(vec3(0.15, 0.1, 0.02), vec3(1.0, 0.85, 0.4), height); 4902 if (style == 2) return mix(vec3(0.12, 0.05, 0.02), vec3(0.95, 0.6, 0.4), height); 4903 if (style == 3) return mix(vec3(0.0, 0.05, 0.1), vec3(0.2, 1.0, 0.8), height); 4904 // Silver (default) and custom 4905 return vec3(height); 4906} 4907 4908void main() { 4909 vec2 uv = vUv; 4910 float aspect = u_resolution.x / u_resolution.y; 4911 uv.x *= aspect; 4912 float time = u_time * u_speed * u_flowSpeed; 4913 4914 // Mouse influence â velocity-based distortion 4915 vec2 mouseUv = u_mouse * 0.5 + 0.5; 4916 mouseUv.x *= aspect; 4917 float mouseDist = distance(uv, mouseUv); 4918 float mouseInfluence = smoothstep(0.6, 0.0, mouseDist); 4919 4920 // Extra distortion from mouse (simulates velocity) 4921 float mouseDistort = mouseInfluence * 0.5; 4922 4923 // Iterative UV warping â the core liquid chrome effect 4924 vec2 warpUv = uv; 4925 int iters = u_warpIterations; 4926 float amp = u_warpAmplitude; 4927 4928 for (int i = 1; i <= 10; i++) { 4929 if (i > iters) break; 4930 float fi = float(i); 4931 warpUv.x += amp / fi * cos(fi * u_warpFrequency * warpUv.y + time + mouseDistort * 2.0); 4932 warpUv.y += amp / fi * cos(fi * (u_warpFrequency * 0.6) * warpUv.x + time + mouseDistort * 2.0); 4933 } 4934 4935 // Calculate "height" for chrome reflection â creates ridges and valleys 4936 vec2 grid = warpUv * 3.0; 4937 float height = sin(grid.x + grid.y) * 0.5 + 0.5; 4938 4939 // Specular highlights â the chrome "shine" 4940 float spec = smoothstep(u_specularSharpness, 1.0, sin(warpUv.x * 10.0 + warpUv.y * 10.0)); 4941 float spec2 = smoothstep(u_specularSharpness * 0.9, 1.0, sin(warpUv.x * 7.0 - warpUv.y * 5.0 + time * 0.3)); 4942 float specular = max(spec, spec2 * 0.6) * u_specularIntensity; 4943 4944 // Secondary ridges for more complexity 4945 float ridge2 = sin(warpUv.x * 5.0 + warpUv.y * 8.0 + time * 0.2) * 0.5 + 0.5; 4946 height = mix(height, ridge2, 0.3); 4947 4948 // Map height to color 4949 float t = clamp(height, 0.0, 1.0); 4950 4951 vec3 color; 4952 if (u_chromeStyle == 4) { 4953 // Custom: use gradient color stops 4954 color = mixColors(u_colors, u_colorPositions, u_colorCount, t); 4955 } else { 4956 // Preset chrome: base metal color modulated by gradient 4957 vec3 chromeBase = getChromeBaseColor(u_chromeStyle, height); 4958 vec3 gradientColor = mixColors(u_colors, u_colorPositions, u_colorCount, t); 4959 color = chromeBase * gradientColor * 2.0; 4960 } 4961 4962 // Apply specular highlights 4963 color += vec3(specular); 4964 4965 // Chromatic aberration based on mouse proximity 4966 if (u_chromaticAberration > 0.0) { 4967 float ca = u_chromaticAberration + mouseDistort * u_chromaticAberration; 4968 // Re-warp with slight offset for R and B channels 4969 vec2 uvR = uv + vec2(ca, 0.0); 4970 vec2 uvB = uv - vec2(ca, 0.0); 4971 vec2 warpR = uvR; 4972 vec2 warpB = uvB; 4973 for (int i = 1; i <= 10; i++) { 4974 if (i > iters) break; 4975 float fi = float(i); 4976 warpR.x += amp / fi * cos(fi * u_warpFrequency * warpR.y + time); 4977 warpR.y += amp / fi * cos(fi * (u_warpFrequency * 0.6) * warpR.x + time); 4978 warpB.x += amp / fi * cos(fi * u_warpFrequency * warpB.y + time); 4979 warpB.y += amp / fi * cos(fi * (u_warpFrequency * 0.6) * warpB.x + time); 4980 } 4981 float hR = sin(warpR.x * 3.0 + warpR.y * 3.0) * 0.5 + 0.5; 4982 float hB = sin(warpB.x * 3.0 + warpB.y * 3.0) * 0.5 + 0.5; 4983 color.r = mix(color.r, mixColors(u_colors, u_colorPositions, u_colorCount, hR).r, 0.3); 4984 color.b = mix(color.b, mixColors(u_colors, u_colorPositions, u_colorCount, hB).b, 0.3); 4985 } 4986 4987 // Add grain 4988 color += grain(vUv, time, u_grain); 4989 4990 // Self-blend 4991 if (u_blendMode > 0) { 4992 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 4993 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 4994 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 4995 bIntensity = noiseModulatedIntensity(bIntensity, vUv, time, u_blendNoiseMask, u_blendNoiseScale); 4996 bIntensity = applyBlendFalloff(bIntensity, t, u_blendFalloff);
4997 float tB = blendLayerT(vUv, t, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 4998 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 4999 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 5000 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 5001 float tB2 = blendLayerT(vUv, t, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 5002 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 5003 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 5004 } 5005 } 5006 5007 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 5008} 5009`,y=`#version 300 es 5010precision highp float; 5011 5012in vec2 vUv; 5013out vec4 fragColor; 5014 5015uniform float u_time; 5016uniform float u_speed; 5017uniform vec3 u_colors[12]; 5018uniform float u_colorPositions[12]; 5019uniform int u_colorCount; 5020uniform float u_direction; 5021uniform float u_grain; 5022uniform vec2 u_resolution; 5023 5024// Blend uniforms 5025uniform int u_blendMode; 5026uniform float u_blendIntensity; 5027uniform float u_blendOffset; 5028uniform float u_blendRotation; 5029uniform float u_blendScale; 5030uniform int u_blendAnimRotation; 5031uniform int u_blendAnimIntensity; 5032uniform int u_blendAnimOffset; 5033uniform float u_blendAnimSpeed; 5034uniform float u_blendNoiseMask; 5035uniform float u_blendNoiseScale; 5036uniform float u_blendFalloff; 5037uniform int u_blendDualLayer; 5038uniform int u_blendMode2; 5039uniform float u_blendIntensity2; 5040uniform float u_blendOffset2; 5041uniform float u_blendRotation2; 5042uniform float u_blendScale2; 5043 5044// Mode-specific 5045uniform int u_fieldStyle; // 0=fiber, 1=starburst, 2=convergence, 3=fountain 5046uniform int u_lineCount; 5047uniform float u_originX; 5048uniform float u_originY; 5049uniform float u_lineLength; 5050uniform float u_lineThickness; 5051uniform float u_lineCurvature; 5052uniform float u_dotSize; 5053uniform float u_spread; 5054uniform float u_glowIntensity; 5055uniform float u_glowRadius; 5056uniform float u_mouseForce; 5057uniform float u_mouseRadius; 5058 5059__COMMON__ 5060 5061// Hash function for per-line randomization 5062float hash(float n) { return fract(sin(n) * 43758.5453123); } 5063vec2 hash2(float n) { return vec2(hash(n), hash(n + 57.0)); } 5064 5065// Distance from point to line segment 5066float distToSegment(vec2 p, vec2 a, vec2 b) { 5067 vec2 pa = p - a; 5068 vec2 ba = b - a; 5069 float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); 5070 return length(pa - ba * h); 5071} 5072 5073// Cubic bezier point 5074vec2 bezier(vec2 a, vec2 b, vec2 c, float t) { 5075 vec2 ab = mix(a, b, t); 5076 vec2 bc = mix(b, c, t); 5077 return mix(ab, bc, t); 5078} 5079 5080// Distance from point to bezier curve (sampled) 5081float distToBezier(vec2 p, vec2 a, vec2 ctrl, vec2 b, out float closestT) { 5082 float minDist = 100.0; 5083 closestT = 0.0; 5084 for (int i = 0; i <= 16; i++) { 5085 float t = float(i) / 16.0; 5086 vec2 pt = bezier(a, ctrl, b, t); 5087 float d = distance(p, pt); 5088 if (d < minDist) { 5089 minDist = d; 5090 closestT = t; 5091 } 5092 } 5093 return minDist; 5094} 5095 5096void main() { 5097 vec2 uv = vUv; 5098 float aspect = u_resolution.x / u_resolution.y; 5099 vec2 aspectUv = vec2(uv.x * aspect, uv.y); 5100 float time = u_time * u_speed; 5101 5102 // Origin point 5103 vec2 origin = vec2(u_originX * aspect, u_originY); 5104 5105 // Mouse position in aspect-corrected space 5106 vec2 mousePos = (u_mouse * 0.5 + 0.5); 5107 mousePos.x *= aspect; 5108 5109 // Background: dark with subtle gradient tint 5110 float bgDist = distance(aspectUv, origin); 5111 float bgT = clamp(bgDist / 1.2, 0.0, 1.0); 5112 vec3 bgGradient = mixColors(u_colors, u_colorPositions, u_colorCount, bgT); 5113 // Keep background dark but tinted â use sqrt to brighten dark palettes 5114 vec3 bgColor = sqrt(bgGradient) * 0.12; 5115 5116 // Origin glow â use brightest color from palette 5117 float glow = exp(-bgDist * bgDist / (u_glowRadius * u_glowRadius)) * u_glowIntensity; 5118 // Sample brightest region of palette for glow 5119 vec3 glowColor = mixColors(u_colors, u_colorPositions, u_colorCount, 0.7); 5120 glowColor = max(glowColor, vec3(0.3)); // Ensure glow is always visible 5121 5122 // Accumulate line color directly (not just brightness) 5123 vec3 lineAccum = vec3(0.0); 5124 float dotBrightness = 0.0; 5125 float totalWeight = 0.0; 5126 5127 int count = u_lineCount; 5128 5129 for (int i = 0; i < 200; i++) { 5130 if (i >= count) break; 5131 5132 float fi = float(i); 5133 float randSeed = fi * 1.37; 5134 5135 // Base angle distribution 5136 float baseAngle; 5137 if (u_fieldStyle == 0) { 5138 // Fiber: semi-circular spread from origin 5139 baseAngle = -u_spread * 0.5 + u_spread * (fi + 0.5) / float(count); 5140 } else if (u_fieldStyle == 1) { 5141 // Starburst: full radial with golden angle offset 5142 baseAngle = fi * 2.39996; // golden angle 5143 } else if (u_fieldStyle == 2) { 5144 // Convergence: lines come from edges toward origin (reversed) 5145 baseAngle = -u_spread * 0.5 + u_spread * (fi + 0.5) / float(count); 5146 } else { 5147 // Fountain: upward spray 5148 baseAngle = -u_spread * 0.25 + u_spread * 0.5 * (fi + 0.5) / float(count); 5149 baseAngle += 1.5708; // rotate 90 deg (up) 5150 } 5151 5152 // Add per-line direction offset (rotates base) 5153 float dirAngle = radians(u_direction); 5154 baseAngle += dirAngle; 5155 5156 // Per-line randomization 5157 vec2 lineRand = hash2(fi * 7.31); 5158 float lengthVar = 0.7 + lineRand.x * 0.6; // 0.7 â 1.3 5159 float phaseOffset = lineRand.y * 6.283; 5160 5161 // Noise-based curvature 5162 float curveNoise = snoise(vec2(fi * 0.1, time * 0.3)) * u_lineCurvature; 5163 5164 // Line geometry 5165 vec2 dir = vec2(cos(baseAngle), sin(baseAngle)); 5166 float len = u_lineLength * lengthVar; 5167 5168 // Start point 5169 vec2 lineStart = origin; 5170 5171 // End point 5172 vec2 lineEnd = origin + dir * len; 5173 5174 // Control point for bezier curve (perpendicular offset for curvature) 5175 vec2 perp = vec2(-dir.y, dir.x); 5176 vec2 ctrl = origin + dir * len * 0.5 + perp * curveNoise * len * 0.5; 5177 5178 // Gentle drift animation 5179 float drift = sin(time * 0.5 + phaseOffset) * 0.02; 5180 ctrl += perp * drift; 5181 lineEnd += perp * drift * 0.5; 5182 5183 // Mouse force field â displaces endpoint and control point 5184 if (u_mouseForce > 0.0) { 5185 float mouseDistEnd = distance(lineEnd, mousePos); 5186 float mouseDistCtrl = distance(ctrl, mousePos); 5187 float forceEnd = smoothstep(u_mouseRadius, 0.0, mouseDistEnd) * u_mouseForce; 5188 float forceCtrl = smoothstep(u_mouseRadius, 0.0, mouseDistCtrl) * u_mouseForce * 0.5; 5189 5190 vec2 pushEnd = normalize(lineEnd - mousePos + vec2(0.001)) * forceEnd * 0.15; 5191 vec2 pushCtrl = normalize(ctrl - mousePos + vec2(0.001)) * forceCtrl * 0.15; 5192 5193 lineEnd += pushEnd; 5194 ctrl += pushCtrl; 5195 } 5196 5197 // For convergence style, swap start and end 5198 if (u_fieldStyle == 2) { 5199 vec2 tmp = lineStart; 5200 lineStart = lineEnd; 5201 lineEnd = tmp; 5202 } 5203 5204 // Distance from pixel to bezier curve 5205 float closestT; 5206 float d = distToBezier(aspectUv, lineStart, ctrl, lineEnd, closestT); 5207
5208 // Convert pixel-space thickness to UV space 5209 float pxThickness = u_lineThickness / u_resolution.y; 5210 float softness = pxThickness * 2.0; 5211 float lineBright = smoothstep(pxThickness + softness, pxThickness * 0.2, d); 5212 5213 // Fade along line length (tip brighter, base fades) 5214 float lengthFade = smoothstep(0.0, 0.3, closestT); 5215 lineBright *= lengthFade; 5216 5217 // Gentle pulse 5218 float pulse = 0.7 + 0.3 * sin(time * 1.5 + phaseOffset); 5219 lineBright *= pulse; 5220 5221 // Color this line â map line index to gradient position 5222 float lineGradT = (fi + 0.5) / float(count); 5223 vec3 thisLineColor = mixColors(u_colors, u_colorPositions, u_colorCount, lineGradT); 5224 // Ensure lines are always visible by boosting dark colors 5225 thisLineColor = max(thisLineColor, vec3(0.15)); 5226 5227 lineAccum += thisLineColor * lineBright; 5228 totalWeight += lineBright; 5229 5230 // Endpoint dot 5231 vec2 endPt = bezier(lineStart, ctrl, lineEnd, 1.0); 5232 float dotDist = distance(aspectUv, endPt); 5233 float pxDotSize = u_dotSize / u_resolution.y; 5234 float dot = smoothstep(pxDotSize + pxDotSize * 0.5, pxDotSize * 0.2, dotDist) * pulse; 5235 dotBrightness += dot; 5236 } 5237 5238 // Clamp accumulated values 5239 lineAccum = min(lineAccum, vec3(3.0)); 5240 dotBrightness = min(dotBrightness, 2.5); 5241 5242 // Compose: background + glow + colored lines + dots 5243 vec3 color = bgColor; 5244 color += glowColor * glow * 0.5; 5245 color += lineAccum * 1.5; 5246 // Dots glow white-ish for maximum visibility 5247 color += vec3(0.9, 0.95, 1.0) * dotBrightness * 0.7; 5248 5249 // Add grain 5250 color += grain(vUv, time, u_grain); 5251 5252 // Self-blend 5253 float t = clamp(bgT, 0.0, 1.0); 5254 if (u_blendMode > 0) { 5255 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 5256 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 5257 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 5258 bIntensity = noiseModulatedIntensity(bIntensity, vUv, time, u_blendNoiseMask, u_blendNoiseScale); 5259 bIntensity = applyBlendFalloff(bIntensity, t, u_blendFalloff); 5260 float tB = blendLayerT(vUv, t, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 5261 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 5262 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 5263 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 5264 float tB2 = blendLayerT(vUv, t, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 5265 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 5266 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 5267 } 5268 } 5269 5270 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 5271} 5272`,x=`#version 300 es 5273precision highp float; 5274out vec2 vUv; 5275out vec2 vL; 5276out vec2 vR; 5277out vec2 vT; 5278out vec2 vB; 5279uniform vec2 u_texelSize; 5280void main() { 5281 float x = float((gl_VertexID & 1) << 2); 5282 float y = float((gl_VertexID & 2) << 1); 5283 vUv = vec2(x * 0.5, y * 0.5); 5284 vL = vUv - vec2(u_texelSize.x, 0.0); 5285 vR = vUv + vec2(u_texelSize.x, 0.0); 5286 vT = vUv + vec2(0.0, u_texelSize.y); 5287 vB = vUv - vec2(0.0, u_texelSize.y); 5288 gl_Position = vec4(x - 1.0, y - 1.0, 0.0, 1.0); 5289} 5290`,C=`#version 300 es 5291precision highp float; 5292in vec2 vUv; 5293out vec4 fragColor; 5294uniform sampler2D u_target; 5295uniform vec2 u_texelSize; 5296uniform vec3 u_color; 5297uniform vec2 u_point; 5298uniform float u_radius; 5299void main() { 5300 vec2 p = vUv - u_point; 5301 p.x *= u_texelSize.y / u_texelSize.x; 5302 vec3 splat = exp(-dot(p, p) / u_radius) * u_color; 5303 vec3 base = texture(u_target, vUv).xyz; 5304 fragColor = vec4(base + splat, 1.0); 5305} 5306`,w=`#version 300 es 5307precision highp float; 5308in vec2 vUv; 5309out vec4 fragColor; 5310uniform sampler2D u_velocity; 5311uniform sampler2D u_source; 5312uniform vec2 u_texelSize; 5313uniform float u_dt; 5314uniform float u_dissipation; 5315 5316vec4 bilerp(sampler2D sam, vec2 uv, vec2 tsize) { 5317 vec2 st = uv / tsize - 0.5; 5318 vec2 iuv = floor(st); 5319 vec2 fuv = fract(st); 5320 vec4 a = texture(sam, (iuv + vec2(0.5, 0.5)) * tsize); 5321 vec4 b = texture(sam, (iuv + vec2(1.5, 0.5)) * tsize); 5322 vec4 c = texture(sam, (iuv + vec2(0.5, 1.5)) * tsize); 5323 vec4 d = texture(sam, (iuv + vec2(1.5, 1.5)) * tsize); 5324 return mix(mix(a, b, fuv.x), mix(c, d, fuv.x), fuv.y); 5325} 5326 5327void main() { 5328 vec2 coord = vUv - u_dt * bilerp(u_velocity, vUv, u_texelSize).xy * u_texelSize; 5329 vec4 result = u_dissipation * bilerp(u_source, coord, u_texelSize); 5330 result.a = 1.0; 5331 fragColor = result; 5332} 5333`,S=`#version 300 es 5334precision highp float; 5335in vec2 vUv; 5336in vec2 vL; 5337in vec2 vR; 5338in vec2 vT; 5339in vec2 vB; 5340out vec4 fragColor; 5341uniform sampler2D u_velocity; 5342void main() { 5343 float L = texture(u_velocity, vL).x; 5344 float R = texture(u_velocity, vR).x; 5345 float T = texture(u_velocity, vT).y; 5346 float B = texture(u_velocity, vB).y; 5347 float div = 0.5 * (R - L + T - B); 5348 fragColor = vec4(div, 0.0, 0.0, 1.0); 5349} 5350`,A=`#version 300 es 5351precision highp float; 5352in vec2 vUv; 5353in vec2 vL; 5354in vec2 vR; 5355in vec2 vT; 5356in vec2 vB; 5357out vec4 fragColor; 5358uniform sampler2D u_velocity; 5359void main() { 5360 float L = texture(u_velocity, vL).y; 5361 float R = texture(u_velocity, vR).y; 5362 float T = texture(u_velocity, vT).x; 5363 float B = texture(u_velocity, vB).x; 5364 float vorticity = R - L - T + B; 5365 fragColor = vec4(0.5 * vorticity, 0.0, 0.0, 1.0); 5366} 5367`,I=`#version 300 es 5368precision highp float; 5369in vec2 vUv; 5370in vec2 vL; 5371in vec2 vR; 5372in vec2 vT; 5373in vec2 vB; 5374out vec4 fragColor; 5375uniform sampler2D u_velocity; 5376uniform sampler2D u_curl; 5377uniform float u_strength; 5378uniform float u_dt; 5379void main() { 5380 float L = texture(u_curl, vL).x; 5381 float R = texture(u_curl, vR).x; 5382 float T = texture(u_curl, vT).x; 5383 float B = texture(u_curl, vB).x; 5384 float C = texture(u_curl, vUv).x; 5385 vec2 force = 0.5 * vec2(abs(T) - abs(B), abs(R) - abs(L)); 5386 force /= length(force) + 0.0001; 5387 force *= u_strength * C;
5388 force.y *= -1.0; 5389 vec2 velocity = texture(u_velocity, vUv).xy; 5390 velocity += force * u_dt; 5391 fragColor = vec4(velocity, 0.0, 1.0); 5392} 5393`,M=`#version 300 es 5394precision highp float; 5395in vec2 vUv; 5396in vec2 vL; 5397in vec2 vR; 5398in vec2 vT; 5399in vec2 vB; 5400out vec4 fragColor; 5401uniform sampler2D u_pressure; 5402uniform sampler2D u_divergence; 5403void main() { 5404 float L = texture(u_pressure, vL).x; 5405 float R = texture(u_pressure, vR).x; 5406 float T = texture(u_pressure, vT).x; 5407 float B = texture(u_pressure, vB).x; 5408 float divergence = texture(u_divergence, vUv).x; 5409 float pressure = (L + R + B + T - divergence) * 0.25; 5410 fragColor = vec4(pressure, 0.0, 0.0, 1.0); 5411} 5412`,R=`#version 300 es 5413precision highp float; 5414in vec2 vUv; 5415in vec2 vL; 5416in vec2 vR; 5417in vec2 vT; 5418in vec2 vB; 5419out vec4 fragColor; 5420uniform sampler2D u_pressure; 5421uniform sampler2D u_velocity; 5422void main() { 5423 float L = texture(u_pressure, vL).x; 5424 float R = texture(u_pressure, vR).x; 5425 float T = texture(u_pressure, vT).x; 5426 float B = texture(u_pressure, vB).x; 5427 vec2 velocity = texture(u_velocity, vUv).xy; 5428 velocity -= vec2(R - L, T - B); 5429 fragColor = vec4(velocity, 0.0, 1.0); 5430} 5431`,B=`#version 300 es 5432precision highp float; 5433in vec2 vUv; 5434out vec4 fragColor; 5435uniform sampler2D u_pressure; 5436uniform float u_value; 5437void main() { 5438 fragColor = u_value * texture(u_pressure, vUv); 5439} 5440`,D=`#version 300 es 5441precision highp float; 5442 5443in vec2 vUv; 5444out vec4 fragColor; 5445 5446uniform float u_time; 5447uniform float u_speed; 5448uniform vec3 u_colors[12]; 5449uniform float u_colorPositions[12]; 5450uniform int u_colorCount; 5451uniform float u_direction; 5452uniform float u_grain; 5453uniform vec2 u_resolution; 5454 5455// Blend uniforms 5456uniform int u_blendMode; 5457uniform float u_blendIntensity; 5458uniform float u_blendOffset; 5459uniform float u_blendRotation; 5460uniform float u_blendScale; 5461uniform int u_blendAnimRotation; 5462uniform int u_blendAnimIntensity; 5463uniform int u_blendAnimOffset; 5464uniform float u_blendAnimSpeed; 5465uniform float u_blendNoiseMask; 5466uniform float u_blendNoiseScale; 5467uniform float u_blendFalloff; 5468uniform int u_blendDualLayer; 5469uniform int u_blendMode2; 5470uniform float u_blendIntensity2; 5471uniform float u_blendOffset2; 5472uniform float u_blendRotation2; 5473uniform float u_blendScale2; 5474 5475// Fluid sim display â dye texture from simulation 5476uniform sampler2D u_dyeTexture; 5477 5478// Mode-specific 5479uniform int u_simResolution; 5480uniform int u_dyeResolution; 5481uniform float u_densityDissipation; 5482uniform float u_velocityDissipation; 5483uniform int u_pressureIterations; 5484uniform float u_splatRadius; 5485uniform float u_splatForce; 5486uniform int u_autoAnimate; 5487uniform float u_curl; 5488 5489__COMMON__ 5490 5491void main() { 5492 float time = u_time * u_speed; 5493 5494 // Read dye from fluid simulation 5495 vec3 dye = texture(u_dyeTexture, vUv).rgb; 5496 5497 // Map dye intensity to gradient color 5498 float dyeIntensity = max(dye.r, max(dye.g, dye.b)); 5499 float t = clamp(dyeIntensity, 0.0, 1.0); 5500 5501 // Use dye color channel ratios to shift the t position for variety 5502 float colorBias = 0.0; 5503 if (dyeIntensity > 0.01) { 5504 colorBias = (dye.r - dye.b) / (dyeIntensity * 3.0); 5505 } 5506 t = clamp(t + colorBias * 0.2, 0.0, 1.0); 5507 5508 vec3 color = mixColors(u_colors, u_colorPositions, u_colorCount, t); 5509 5510 // Modulate brightness by dye intensity 5511 float brightness = pow(dyeIntensity, 0.7); 5512 color *= brightness; 5513 5514 // Background: faint gradient where no dye 5515 float bgFade = 1.0 - brightness; 5516 float angle = radians(u_direction); 5517 vec2 dir = vec2(cos(angle), sin(angle)); 5518 float bgT = dot(vUv - 0.5, dir) + 0.5; 5519 vec3 bgColor = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(bgT, 0.0, 1.0)); 5520 color += bgColor * bgFade * 0.12; 5521 5522 // Add grain 5523 color += grain(vUv, time, u_grain); 5524 5525 // Self-blend 5526 if (u_blendMode > 0) { 5527 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 5528 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 5529 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 5530 bIntensity = noiseModulatedIntensity(bIntensity, vUv, time, u_blendNoiseMask, u_blendNoiseScale); 5531 bIntensity = applyBlendFalloff(bIntensity, t, u_blendFalloff);
5532 float tB = blendLayerT(vUv, t, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 5533 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 5534 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 5535 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 5536 float tB2 = blendLayerT(vUv, t, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 5537 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 5538 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 5539 } 5540 } 5541 5542 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 5543} 5544`;e.s(["FLUID_ADVECTION_FRAGMENT",0,w,"FLUID_CLEAR_FRAGMENT",0,B,"FLUID_CURL_FRAGMENT",0,A,"FLUID_DIVERGENCE_FRAGMENT",0,S,"FLUID_GRADIENT_SUBTRACT_FRAGMENT",0,R,"FLUID_PRESSURE_FRAGMENT",0,M,"FLUID_SIM_FRAGMENT",0,D,"FLUID_SPLAT_FRAGMENT",0,C,"FLUID_VERTEX",0,x,"FLUID_VORTICITY_FRAGMENT",0,I],19529);let k=`#version 300 es 5545precision highp float; 5546 5547in vec2 vUv; 5548out vec4 fragColor; 5549 5550uniform float u_time; 5551uniform float u_speed; 5552uniform vec3 u_colors[12]; 5553uniform float u_colorPositions[12]; 5554uniform int u_colorCount; 5555uniform float u_direction; 5556uniform float u_grain; 5557uniform vec2 u_resolution; 5558 5559// Blend uniforms 5560uniform int u_blendMode; 5561uniform float u_blendIntensity; 5562uniform float u_blendOffset; 5563uniform float u_blendRotation; 5564uniform float u_blendScale; 5565uniform int u_blendAnimRotation; 5566uniform int u_blendAnimIntensity; 5567uniform int u_blendAnimOffset; 5568uniform float u_blendAnimSpeed; 5569uniform float u_blendNoiseMask; 5570uniform float u_blendNoiseScale; 5571uniform float u_blendFalloff; 5572uniform int u_blendDualLayer; 5573uniform int u_blendMode2; 5574uniform float u_blendIntensity2; 5575uniform float u_blendOffset2; 5576uniform float u_blendRotation2; 5577uniform float u_blendScale2; 5578 5579// Mode-specific 5580uniform int u_warpStyle; // 0=tunnel, 1=vortex, 2=hyperdrive, 3=nebula 5581uniform float u_warpSpeed; 5582uniform float u_nebulaDensity; 5583uniform float u_starBrightness; 5584uniform float u_tunnelRadius; 5585uniform float u_vortexStrength; 5586uniform float u_streakLength; 5587uniform float u_centerDarkness; 5588uniform float u_vignette; 5589uniform float u_chromaticShift; 5590 5591__COMMON__ 5592 5593// Value noise for nebula generation 5594float vnoise(vec2 st) { 5595 vec2 i = floor(st); 5596 vec2 f = fract(st); 5597 float a = fract(sin(dot(i, vec2(12.9898, 78.233))) * 43758.5453); 5598 float b = fract(sin(dot(i + vec2(1.0, 0.0), vec2(12.9898, 78.233))) * 43758.5453); 5599 float c = fract(sin(dot(i + vec2(0.0, 1.0), vec2(12.9898, 78.233))) * 43758.5453); 5600 float d = fract(sin(dot(i + vec2(1.0, 1.0), vec2(12.9898, 78.233))) * 43758.5453); 5601 vec2 u = f * f * (3.0 - 2.0 * f); 5602 return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y; 5603} 5604 5605float vfbm(vec2 st, int octaves) { 5606 float value = 0.0; 5607 float amp = 0.5; 5608 for (int i = 0; i < 6; i++) { 5609 if (i >= octaves) break; 5610 value += amp * vnoise(st); 5611 st *= 2.0; 5612 amp *= 0.5; 5613 } 5614 return value; 5615} 5616 5617void main() { 5618 vec2 uv = (vUv - 0.5) * 2.0; 5619 float aspect = u_resolution.x / u_resolution.y; 5620 uv.x *= aspect; 5621 float time = u_time * u_speed * u_warpSpeed; 5622 5623 // Mouse influence â shifts tunnel center 5624 vec2 mouseOffset = (u_mouse * 0.5 + 0.5 - 0.5) * 0.4; 5625 if (u_mouseMode > 0) { 5626 uv -= mouseOffset; 5627 } 5628 5629 // Polar coordinates 5630 float r = length(uv); 5631 float a = atan(uv.y, uv.x); 5632 5633 // Warp styles 5634 float tunnelCoord; 5635 float angleCoord; 5636 5637 if (u_warpStyle == 0) { 5638 // Tunnel: classic 1/r mapping flowing forward 5639 tunnelCoord = u_tunnelRadius / (r + 0.001) + time; 5640 angleCoord = a / 3.14159265; 5641 } else if (u_warpStyle == 1) { 5642 // Vortex: spiral inward 5643 tunnelCoord = u_tunnelRadius / (r + 0.001) + time; 5644 angleCoord = a / 3.14159265 + time * u_vortexStrength + r * u_vortexStrength * 2.0; 5645 } else if (u_warpStyle == 2) { 5646 // Hyperdrive: elongated streaks 5647 tunnelCoord = u_tunnelRadius / (r + 0.001) + time * 2.0; 5648 angleCoord = a / 3.14159265; 5649 } else { 5650 // Nebula: slow drift through gas clouds 5651 tunnelCoord = u_tunnelRadius / (r + 0.001) + time * 0.3; 5652 angleCoord = a / 3.14159265 + sin(time * 0.2) * 0.1; 5653 } 5654 5655 vec2 polarUv = vec2(tunnelCoord, angleCoord); 5656 5657 // Nebula / star noise 5658 float streakMult = u_warpStyle == 2 ? u_streakLength * 3.0 : 1.0; 5659 float n = vfbm(polarUv * vec2(streakMult, 10.0) * u_nebulaDensity, 4); 5660 5661 // Stars: sharp bright points 5662 float stars = pow(n, 4.0) * 2.0 * u_starBrightness; 5663 5664 // Nebula: soft cloud layer 5665 float nebula = smoothstep(0.35, 0.75, n); 5666 5667 // Secondary detail layer 5668 float detail = vfbm(polarUv * vec2(2.0 * streakMult, 20.0) * u_nebulaDensity + 7.3, 3); 5669 float fineStars = pow(detail, 6.0) * u_starBrightness * 0.5; 5670 5671 // Map to gradient colors 5672 float colorT = clamp(nebula + stars * 0.3, 0.0, 1.0); 5673 vec3 nebulaColor = mixColors(u_colors, u_colorPositions, u_colorCount, colorT); 5674 5675 // Compose 5676 vec3 color = vec3(0.0); 5677 color += nebulaColor * nebula * 0.6; 5678 color += vec3(1.0) * stars; // White-hot stars 5679 color += vec3(0.8, 0.9, 1.0) * fineStars; 5680 5681 // Chromatic aberration on nebula 5682 if (u_chromaticShift > 0.0) { 5683 float nR = vfbm(polarUv * vec2(streakMult, 10.0) * u_nebulaDensity + vec2(u_chromaticShift, 0.0), 4); 5684 float nB = vfbm(polarUv * vec2(streakMult, 10.0) * u_nebulaDensity - vec2(u_chromaticShift, 0.0), 4); 5685 float nebR = smoothstep(0.35, 0.75, nR); 5686 float nebB = smoothstep(0.35, 0.75, nB); 5687 vec3 colR = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(nebR, 0.0, 1.0)); 5688 vec3 colB = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(nebB, 0.0, 1.0)); 5689 color.r = mix(color.r, colR.r * nebR * 0.6, 0.3); 5690 color.b = mix(color.b, colB.b * nebB * 0.6, 0.3); 5691 } 5692 5693 // Center darkness (black hole effect) 5694 float centerFade = smoothstep(0.0, u_centerDarkness, r); 5695 color *= centerFade; 5696 5697 // Edge vignette 5698 float vign = 1.0 - smoothstep(0.5, 1.5 - u_vignette * 0.5, length(vUv - 0.5)); 5699 color *= vign; 5700 5701 // Depth-based fade (distant things dimmer) 5702 float depthFade = smoothstep(0.0, 0.15, r) * (1.0 - smoothstep(1.5, 3.0, r)); 5703 color *= depthFade; 5704 5705 float t = clamp(colorT, 0.0, 1.0); 5706 5707 // Add grain 5708 color += grain(vUv, time, u_grain); 5709 5710 // Self-blend 5711 if (u_blendMode > 0) { 5712 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 5713 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 5714 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 5715 bIntensity = noiseModulatedIntensity(bIntensity, vUv, time, u_blendNoiseMask, u_blendNoiseScale); 5716 bIntensity = applyBlendFalloff(bIntensity, t, u_blendFalloff);
5717 float tB = blendLayerT(vUv, t, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 5718 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 5719 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 5720 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 5721 float tB2 = blendLayerT(vUv, t, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 5722 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 5723 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 5724 } 5725 } 5726 5727 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 5728} 5729`;var O=e.i(607490);let T=`#version 300 es 5730precision highp float; 5731 5732in vec2 vUv; 5733out vec4 fragColor; 5734 5735uniform float u_time; 5736uniform float u_speed; 5737uniform vec3 u_colors[12]; 5738uniform float u_colorPositions[12]; 5739uniform int u_colorCount; 5740uniform float u_direction; 5741uniform float u_grain; 5742uniform vec2 u_resolution; 5743 5744// Blend uniforms 5745uniform int u_blendMode; 5746uniform float u_blendIntensity; 5747uniform float u_blendOffset; 5748uniform float u_blendRotation; 5749uniform float u_blendScale; 5750uniform int u_blendAnimRotation; 5751uniform int u_blendAnimIntensity; 5752uniform int u_blendAnimOffset; 5753uniform float u_blendAnimSpeed; 5754uniform float u_blendNoiseMask; 5755uniform float u_blendNoiseScale; 5756uniform float u_blendFalloff; 5757uniform int u_blendDualLayer; 5758uniform int u_blendMode2; 5759uniform float u_blendIntensity2; 5760uniform float u_blendOffset2; 5761uniform float u_blendRotation2; 5762uniform float u_blendScale2; 5763 5764// Mode-specific uniforms 5765uniform float u_viscosity; 5766uniform float u_flowSpeed; 5767uniform float u_turbulence; 5768uniform float u_thickness; 5769uniform float u_organicScale; 5770uniform int u_layerCount; 5771uniform float u_separation; 5772uniform float u_sheen; 5773 5774__COMMON__ 5775 5776void main() { 5777 vec2 uv = vUv; 5778 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 5779 uv = applyMouseWarp(uv, aspect); 5780 float time = u_time * u_speed * u_flowSpeed; 5781 5782 vec2 p = uv - 0.5; 5783 p.x *= aspect; 5784 5785 // ---- Recursive domain warp (double domain warp) ---- 5786 // Creates complex, flowing organic patterns like ink in water 5787 vec2 q = p * u_organicScale; 5788 5789 // First warp layer: two FBM channels create a 2D displacement field 5790 vec2 w1 = vec2( 5791 fbm(q + vec2(0.0, time * 0.1), 1.0, 3, 0.5, 2.0), 5792 fbm(q + vec2(5.2, -time * 0.08), 1.0, 3, 0.5, 2.0) 5793 ); 5794 5795 // Second warp layer: warped by first for recursive complexity 5796 float visc = u_viscosity * 4.0; 5797 vec2 w2 = vec2( 5798 fbm(q + visc * w1 + vec2(12.3, 0.0), 1.0, 3, 0.5, 2.0), 5799 fbm(q - visc * w1 + vec2(8.2, 0.0), 1.0, 3, 0.5, 2.0) 5800 ); 5801 5802 // Final flow field from double-warped coordinates 5803 float turb = u_turbulence * 4.8; 5804 float n = fbm(q + turb * w2, 1.0, 4, 0.5, 2.0); 5805 5806 // ---- Subsurface rim glow via FBM-derived normal ---- 5807 float nDx = fbm(q + turb * w2 + vec2(0.02, 0.0), 1.0, 1, 0.5, 2.0); 5808 float nDy = fbm(q + turb * w2 + vec2(0.0, 0.02), 1.0, 1, 0.5, 2.0); 5809 vec3 surfN = normalize(vec3(n - nDx, n - nDy, 0.22)); 5810 5811 // Fresnel rim 5812 float fresnel = pow(1.0 - max(dot(surfN, vec3(0.0, 0.0, 1.0)), 0.0), 2.8); 5813 5814 // Specular highlight (traveling light lobe) 5815 vec3 lightDir = normalize(vec3(-0.4 + 0.3 * sin(time * 0.3), 0.65, 0.6)); 5816 vec3 halfVec = normalize(lightDir + vec3(0.0, 0.0, 1.0)); 5817 float spec = pow(max(dot(surfN, halfVec), 0.0), 46.0); 5818 5819 // ---- Color mapping ---- 5820 float angle = radians(u_direction); 5821 vec2 dir = vec2(cos(angle), sin(angle)); 5822 float baseT = dot(uv - 0.5, dir) + 0.5; 5823 5824 float imgLum = imageLuminance(uv, aspect); 5825 if (imgLum >= 0.0) baseT = mix(baseT, imgLum, u_imageIntensity); 5826 5827 float t = clamp(baseT + n * 0.35, 0.0, 1.0); 5828 vec3 color = mixColors(u_colors, u_colorPositions, u_colorCount, t); 5829 5830 // Subsurface rim glow: bright edge color + translucency 5831 vec3 rimCol = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(t + 0.3, 0.0, 1.0)); 5832 color = mix(color, rimCol, fresnel * u_sheen); 5833 color += fresnel * 0.25 * u_sheen; 5834 5835 // Specular highlight 5836 color += spec * (rimCol + vec3(0.5)) * 0.55 * u_sheen; 5837 5838 // ---- Optional depth layers (subtle variation) ---- 5839 int layers = clamp(u_layerCount, 1, 4); 5840 if (layers > 1) { 5841 for (int i = 1; i < 4; i++) { 5842 if (i >= layers) break; 5843 float fi = float(i); 5844 float layerN = fbm(q + turb * w2 + vec2(fi * 2.39, fi * 3.17), 1.0, 3, 0.4, 2.0); 5845 float layerT = clamp(baseT + layerN * 0.3 + fi * u_separation * 0.15, 0.0, 1.0); 5846 vec3 layerCol = mixColors(u_colors, u_colorPositions, u_colorCount, layerT); 5847 float layerMask = smoothstep(0.5 - u_thickness * 0.3, 0.5 + u_thickness * 0.3, layerN * 0.5 + 0.5); 5848 color = mix(color, layerCol, layerMask * 0.25); 5849 } 5850 } 5851 5852 color += grain(uv, time, u_grain); 5853 5854 // Self-blend 5855 if (u_blendMode > 0) { 5856 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 5857 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 5858 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 5859 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 5860 bIntensity = applyBlendFalloff(bIntensity, baseT, u_blendFalloff); 5861 float tB = blendLayerT(uv, baseT, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 5862 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 5863 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 5864 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 5865 float tB2 = blendLayerT(uv, baseT, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 5866 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 5867 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 5868 } 5869 } 5870 5871 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 5872} 5873`,P=`#version 300 es 5874precision highp float; 5875 5876in vec2 vUv; 5877out vec4 fragColor; 5878 5879uniform float u_time; 5880uniform float u_speed; 5881uniform vec3 u_colors[12]; 5882uniform float u_colorPositions[12]; 5883uniform int u_colorCount; 5884uniform float u_direction; 5885uniform float u_grain; 5886uniform vec2 u_resolution; 5887 5888// Blend uniforms 5889uniform int u_blendMode; 5890uniform float u_blendIntensity; 5891uniform float u_blendOffset; 5892uniform float u_blendRotation; 5893uniform float u_blendScale; 5894uniform int u_blendAnimRotation; 5895uniform int u_blendAnimIntensity; 5896uniform int u_blendAnimOffset; 5897uniform float u_blendAnimSpeed; 5898uniform float u_blendNoiseMask; 5899uniform float u_blendNoiseScale; 5900uniform float u_blendFalloff; 5901uniform int u_blendDualLayer; 5902uniform int u_blendMode2; 5903uniform float u_blendIntensity2; 5904uniform float u_blendOffset2; 5905uniform float u_blendRotation2; 5906uniform float u_blendScale2; 5907 5908// Mode-specific uniforms 5909uniform float u_prismScale; 5910uniform float u_dispersion; 5911uniform float u_ior; 5912uniform int u_facets; 5913uniform float u_clarity; 5914uniform float u_sparkle; 5915uniform float u_rotation; 5916uniform float u_depth; 5917 5918__COMMON__ 5919 5920void main() { 5921 vec2 uv = vUv; 5922 float time = u_time * u_speed; 5923 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 5924 uv = applyMouseWarp(uv, aspect); 5925 5926 // Apply global rotation 5927 float rotRad = radians(u_rotation) + time * 0.02; 5928 vec2 center = vec2(0.5); 5929 vec2 rotUv = uv - center; 5930 rotUv = vec2( 5931 rotUv.x * cos(rotRad) - rotUv.y * sin(rotRad), 5932 rotUv.x * sin(rotRad) + rotUv.y * cos(rotRad) 5933 ); 5934 rotUv += center; 5935 5936 vec2 p = rotUv - 0.5; 5937 p.x *= aspect; 5938 5939 // Base gradient direction 5940 float dirAngle = radians(u_direction); 5941 vec2 dir = vec2(cos(dirAngle), sin(dirAngle)); 5942 float baseT = dot(uv - 0.5, dir) + 0.5; 5943 5944 float imgLum = imageLuminance(uv, aspect); 5945 if (imgLum >= 0.0) baseT = mix(baseT, imgLum, u_imageIntensity); 5946 5947 // ---- Domain-warped glass surface ---- 5948 // u_facets controls surface complexity (more = more spectral folds) 5949 float facetScale = float(max(u_facets, 1)) * 0.5; 5950 vec2 q = p * u_prismScale * facetScale; 5951 5952 // Aurora-like cascading domain warp for flowing glass 5953 float warp1 = snoise(q * 1.5 + time * 0.1); 5954 float warp2 = snoise(q * 3.0 - time * 0.07); 5955 q += vec2(warp1, warp2) * u_depth * 0.4; 5956 5957 // Glass surface height field via FBM 5958 float n = fbm(q, 1.0, 5, 0.5, 2.0); 5959 5960 // ---- Surface normal for refraction direction ---- 5961 float nDx = fbm(q + vec2(0.02, 0.0), 1.0, 2, 0.5, 2.0); 5962 float nDy = fbm(q + vec2(0.0, 0.02), 1.0, 2, 0.5, 2.0); 5963 vec3 surfN = normalize(vec3(n - nDx, n - nDy, u_clarity * 0.3 + 0.05)); 5964 5965 // ---- Chromatic dispersion: R/G/B refracted at different angles ---- 5966 // The surface normal's xy magnitude drives how much light separates 5967 float refractStr = length(surfN.xy) * u_dispersion; 5968 5969 // Each color channel refracts at a different IOR 5970 float iorSpread = 1.0 + u_ior * 0.3; 5971 float tR = clamp(baseT + refractStr * iorSpread, 0.0, 1.0); 5972 float tG = clamp(baseT + refractStr * 0.1, 0.0, 1.0); 5973 float tB = clamp(baseT - refractStr * iorSpread, 0.0, 1.0); 5974 5975 vec3 color = vec3( 5976 mixColors(u_colors, u_colorPositions, u_colorCount, tR).r, 5977 mixColors(u_colors, u_colorPositions, u_colorCount, tG).g, 5978 mixColors(u_colors, u_colorPositions, u_colorCount, tB).b 5979 ); 5980 5981 // ---- Caustic brightness where refraction is strongest ---- 5982 float caustic = pow(length(surfN.xy), 2.0) * u_dispersion; 5983 color += color * caustic * 1.5; 5984 5985 // ---- Fresnel rim glow (IOR affects intensity) ---- 5986 float fresnel = pow(1.0 - max(dot(surfN, vec3(0.0, 0.0, 1.0)), 0.0), 1.5 + u_ior * 2.0); 5987 vec3 rimCol = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(baseT + 0.25, 0.0, 1.0)); 5988 color += rimCol * fresnel * 0.4; 5989 color += fresnel * 0.2;
5990 5991 // ---- Sparkle highlights from animated light ---- 5992 if (u_sparkle > 0.0) { 5993 vec3 lightDir = normalize(vec3( 5994 sin(time * 0.17) * 0.6, 5995 cos(time * 0.13) * 0.6, 5996 1.0 5997 )); 5998 float specAngle = max(dot(surfN, lightDir), 0.0); 5999 float sparkleVal = pow(specAngle, 32.0 + u_sparkle * 64.0) * u_sparkle; 6000 6001 // Secondary sparkle 6002 vec3 lightDir2 = normalize(vec3( 6003 cos(time * 0.23 + 1.5) * 0.5, 6004 sin(time * 0.19 + 2.3) * 0.5, 6005 1.0 6006 )); 6007 sparkleVal += pow(max(dot(surfN, lightDir2), 0.0), 48.0) * u_sparkle * 0.6; 6008 6009 color += vec3(sparkleVal) * 1.5; 6010 } 6011 6012 // Intra-surface color variation for depth 6013 float surfaceGrad = n * 0.5 + 0.5; 6014 float tIntra = clamp(baseT + surfaceGrad * 0.15, 0.0, 1.0); 6015 vec3 intraCol = mixColors(u_colors, u_colorPositions, u_colorCount, tIntra); 6016 color = mix(color, intraCol * (0.7 + caustic), 0.1); 6017 6018 color += grain(uv, time, u_grain); 6019 6020 // Self-blend 6021 if (u_blendMode > 0) { 6022 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 6023 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 6024 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 6025 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 6026 bIntensity = applyBlendFalloff(bIntensity, baseT, u_blendFalloff); 6027 float tB = blendLayerT(uv, baseT, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 6028 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 6029 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 6030 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 6031 float tB2 = blendLayerT(uv, baseT, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 6032 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 6033 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 6034 } 6035 } 6036 6037 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 6038} 6039`,F=`#version 300 es 6040precision highp float; 6041 6042in vec2 vUv; 6043out vec4 fragColor; 6044 6045uniform float u_time; 6046uniform float u_speed; 6047uniform vec3 u_colors[12]; 6048uniform float u_colorPositions[12]; 6049uniform int u_colorCount; 6050uniform float u_direction; 6051uniform float u_grain; 6052uniform vec2 u_resolution; 6053 6054// Blend uniforms 6055uniform int u_blendMode; 6056uniform float u_blendIntensity; 6057uniform float u_blendOffset; 6058uniform float u_blendRotation; 6059uniform float u_blendScale; 6060uniform int u_blendAnimRotation; 6061uniform int u_blendAnimIntensity; 6062uniform int u_blendAnimOffset; 6063uniform float u_blendAnimSpeed; 6064uniform float u_blendNoiseMask; 6065uniform float u_blendNoiseScale; 6066uniform float u_blendFalloff; 6067uniform int u_blendDualLayer; 6068uniform int u_blendMode2; 6069uniform float u_blendIntensity2; 6070uniform float u_blendOffset2; 6071uniform float u_blendRotation2; 6072uniform float u_blendScale2; 6073 6074// Mode-specific uniforms 6075uniform float u_density; 6076uniform float u_coverage; 6077uniform float u_softness; 6078uniform float u_windSpeed; 6079uniform float u_lightAngle; 6080uniform float u_scattering; 6081uniform float u_altitude; 6082uniform float u_billowing; 6083 6084__COMMON__ 6085 6086void main() { 6087 vec2 uv = vUv; 6088 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 6089 uv = applyMouseWarp(uv, aspect); 6090 float time = u_time * u_speed; 6091 6092 // Aspect-correct and scale for altitude 6093 vec2 p = uv; 6094 p.x *= aspect; 6095 p *= mix(1.5, 0.6, u_altitude); 6096 6097 // Wind drift 6098 p += vec2(1.0, 0.3) * time * u_windSpeed * 0.15; 6099 6100 // ---- Aurora-like cascading domain warp ---- 6101 float warp1 = snoise(p * 1.2 + time * 0.08); 6102 float warp2 = snoise(p * 2.4 - time * 0.06); 6103 p += vec2(warp1 + warp2 * 0.4) * 0.3 * u_billowing; 6104 6105 // ---- Cloud density via FBM ---- 6106 float n = fbm(p, 1.2, 5, 0.6, 2.1); 6107 n = n * 0.5 + 0.5; 6108 6109 // Coverage threshold and edge softness 6110 float rawDensity = max(n - (1.0 - u_coverage), 0.0); 6111 float cloudDen = smoothstep(0.0, mix(0.02, 0.3, u_softness), rawDensity); 6112 cloudDen = clamp(cloudDen * u_density, 0.0, 1.0); 6113 6114 // ---- Subsurface rim glow via FBM-derived surface normal ---- 6115 float nDx = fbm(p + vec2(0.02, 0.0), 1.2, 2, 0.6, 2.1) * 0.5 + 0.5; 6116 float nDy = fbm(p + vec2(0.0, 0.02), 1.2, 2, 0.6, 2.1) * 0.5 + 0.5; 6117 vec3 surfN = normalize(vec3(n - nDx, n - nDy, 0.22)); 6118 6119 float fresnel = pow(1.0 - max(dot(surfN, vec3(0.0, 0.0, 1.0)), 0.0), 2.5); 6120 6121 // ---- Directional lighting ---- 6122 float lightRad = radians(u_lightAngle);
6123 vec3 lightDir = normalize(vec3(cos(lightRad), sin(lightRad), 0.7)); 6124 float diffuse = mix(0.35, 1.0, max(dot(surfN, lightDir), 0.0)); 6125 6126 // Interior darkening (self-shadow) 6127 float interior = mix(1.0, 0.65, cloudDen * cloudDen); 6128 6129 // Forward scattering at cloud edges (silver lining) 6130 float scatter = pow(max(dot(-surfN.xy, lightDir.xy), 0.0), 2.5); 6131 float edgeMask = smoothstep(0.0, 0.2, cloudDen) * smoothstep(0.85, 0.2, cloudDen); 6132 scatter *= (1.0 - cloudDen) * edgeMask * u_scattering * 3.0; 6133 6134 // ---- Color mapping ---- 6135 float dirAngle = radians(u_direction); 6136 vec2 dir = vec2(cos(dirAngle), sin(dirAngle)); 6137 float baseT = dot(uv - 0.5, dir) + 0.5; 6138 6139 float imgLum = imageLuminance(uv, aspect); 6140 if (imgLum >= 0.0) baseT = mix(baseT, imgLum, u_imageIntensity); 6141 6142 // Cloud color: density shifts gradient position for depth 6143 float cloudT = clamp(baseT + (1.0 - cloudDen) * 0.25 - 0.12, 0.0, 1.0); 6144 vec3 cloudColor = mixColors(u_colors, u_colorPositions, u_colorCount, cloudT); 6145 cloudColor *= diffuse * interior; 6146 6147 // Subsurface rim glow on cloud edges 6148 vec3 rimColor = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(baseT + 0.3, 0.0, 1.0)); 6149 cloudColor += rimColor * fresnel * 0.5 * cloudDen; 6150 6151 // Forward scattering silver lining 6152 cloudColor += rimColor * scatter; 6153 6154 // Sky gradient (darker for contrast) 6155 vec3 skyColor = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(baseT, 0.0, 1.0)); 6156 skyColor *= mix(1.0, 0.7, uv.y * u_altitude) * 0.85; 6157 6158 // Composite cloud over sky 6159 vec3 color = mix(skyColor, cloudColor, cloudDen); 6160 6161 color += grain(uv, time, u_grain); 6162 6163 // Self-blend 6164 if (u_blendMode > 0) { 6165 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 6166 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 6167 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 6168 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 6169 bIntensity = applyBlendFalloff(bIntensity, baseT, u_blendFalloff); 6170 float tB = blendLayerT(uv, baseT, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 6171 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 6172 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 6173 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 6174 float tB2 = blendLayerT(uv, baseT, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 6175 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 6176 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 6177 } 6178 } 6179 6180 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 6181} 6182`,L=`#version 300 es 6183precision highp float; 6184 6185in vec2 vUv; 6186out vec4 fragColor; 6187 6188uniform float u_time; 6189uniform float u_speed; 6190uniform vec3 u_colors[12]; 6191uniform float u_colorPositions[12]; 6192uniform int u_colorCount; 6193uniform float u_direction; 6194uniform float u_grain; 6195uniform vec2 u_resolution; 6196 6197// Blend uniforms 6198uniform int u_blendMode; 6199uniform float u_blendIntensity; 6200uniform float u_blendOffset; 6201uniform float u_blendRotation; 6202uniform float u_blendScale; 6203uniform int u_blendAnimRotation; 6204uniform int u_blendAnimIntensity; 6205uniform int u_blendAnimOffset; 6206uniform float u_blendAnimSpeed; 6207uniform float u_blendNoiseMask; 6208uniform float u_blendNoiseScale; 6209uniform float u_blendFalloff; 6210uniform int u_blendDualLayer; 6211uniform int u_blendMode2; 6212uniform float u_blendIntensity2; 6213uniform float u_blendOffset2; 6214uniform float u_blendRotation2; 6215uniform float u_blendScale2; 6216 6217// Mode-specific uniforms 6218uniform float u_swirlStrength; 6219uniform float u_swirlRadius; 6220uniform int u_spiralArms; 6221uniform float u_tightness; 6222uniform float u_distortion; 6223uniform float u_centerX; 6224uniform float u_centerY; 6225uniform float u_flowSpeed; 6226 6227__COMMON__ 6228 6229#define TAU 6.2831853 6230 6231void main() { 6232 vec2 uv = vUv; 6233 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 6234 uv = applyMouseWarp(uv, aspect); 6235 float time = u_time * u_speed; 6236 float flowTime = time * u_flowSpeed; 6237 6238 // Vortex center 6239 vec2 center = vec2(u_centerX, u_centerY); 6240 vec2 delta = uv - center; 6241 vec2 aspectDelta = vec2(delta.x * aspect, delta.y); 6242 float r = length(aspectDelta); 6243 6244 // Normalized radius 6245 float normR = r / max(u_swirlRadius, 0.01); 6246 6247 // ---- Core vortex: radius-dependent rotation ---- 6248 // More rotation at center, less at edges (exponential falloff) 6249 float swirlAngle = u_swirlStrength * exp(-normR * u_tightness) * TAU; 6250 swirlAngle += sin(flowTime * 0.6) * 0.8; // animated oscillation 6251 6252 // Apply rotation to coordinates 6253 float cosA = cos(swirlAngle); 6254 float sinA = sin(swirlAngle); 6255 vec2 q = vec2( 6256 aspectDelta.x * cosA - aspectDelta.y * sinA, 6257 aspectDelta.x * sinA + aspectDelta.y * cosA 6258 ); 6259 6260 // ---- Organic distortion via noise ---- 6261 if (u_distortion > 0.0) { 6262 q += snoise(q * 2.0 + flowTime * 0.08) * u_distortion * 0.1; 6263 } 6264 6265 // ---- FBM in swirled space: creates flowing spiral texture ---- 6266 // u_spiralArms scales the frequency for more visible spiral bands 6267 float armFreq = float(max(u_spiralArms, 1)) * 1.5; 6268 float n = fbm(q * armFreq + flowTime * vec2(0.1, -0.07), 1.0, 5, 0.5, 2.0); 6269 6270 // ---- Subsurface rim glow via FBM-derived normal ---- 6271 float nDx = fbm(q * armFreq + flowTime * vec2(0.1, -0.07) + vec2(0.02, 0.0), 1.0, 2, 0.5, 2.0); 6272 float nDy = fbm(q * armFreq + flowTime * vec2(0.1, -0.07) + vec2(0.0, 0.02), 1.0, 2, 0.5, 2.0); 6273 vec3 surfN = normalize(vec3(n - nDx, n - nDy, 0.22)); 6274 6275 float fresnel = pow(1.0 - max(dot(surfN, vec3(0.0, 0.0, 1.0)), 0.0), 2.8); 6276 6277 // ---- Color mapping ---- 6278 float dirAngle = radians(u_direction); 6279 vec2 dir = vec2(cos(dirAngle), sin(dirAngle)); 6280 float baseT = dot(uv - 0.5, dir) + 0.5; 6281 6282 float imgLum = imageLuminance(uv, aspect); 6283 if (imgLum >= 0.0) baseT = mix(baseT, imgLum, u_imageIntensity); 6284 6285 // Map FBM field to gradient (shifted by base direction) 6286 float field = n * 0.5 + 0.5; 6287 float t = clamp(baseT * 0.3 + field * 0.7, 0.0, 1.0); 6288 vec3 color = mixColors(u_colors, u_colorPositions, u_colorCount, t); 6289 6290 // Subsurface rim glow 6291 vec3 rimCol = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(t + 0.3, 0.0, 1.0)); 6292 color = mix(color, rimCol, fresnel * 0.4); 6293 color += fresnel * 0.2;
6294 6295 // ---- Radial fade: vortex brightest at center ---- 6296 float radialFade = 1.0 - smoothstep(0.0, 1.2, normR); 6297 color *= mix(0.3, 1.0, radialFade); 6298 6299 // ---- Bright center eye ---- 6300 float eyeRadius = 0.08 * u_swirlRadius; 6301 float eyeGlow = exp(-pow(r / max(eyeRadius, 0.001), 2.0) * 2.0); 6302 vec3 eyeBaseColor = mixColors(u_colors, u_colorPositions, u_colorCount, 0.5); 6303 vec3 eyeColor = mix(vec3(1.2), eyeBaseColor * 1.5, 0.3); 6304 color += eyeColor * eyeGlow * 2.0; 6305 6306 // Outer halo 6307 float haloR = normR * 3.0; 6308 color += eyeBaseColor * exp(-haloR * haloR) * 0.3; 6309 6310 color += grain(uv, time, u_grain); 6311 6312 // Self-blend 6313 if (u_blendMode > 0) { 6314 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 6315 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 6316 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 6317 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 6318 bIntensity = applyBlendFalloff(bIntensity, baseT, u_blendFalloff); 6319 float tB = blendLayerT(uv, baseT, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 6320 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 6321 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 6322 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 6323 float tB2 = blendLayerT(uv, baseT, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 6324 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 6325 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 6326 } 6327 } 6328 6329 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 6330} 6331`,N=`#version 300 es 6332precision highp float; 6333 6334in vec2 vUv; 6335out vec4 fragColor; 6336 6337uniform float u_time; 6338uniform float u_speed; 6339uniform vec3 u_colors[12]; 6340uniform float u_colorPositions[12]; 6341uniform int u_colorCount; 6342uniform float u_direction; 6343uniform float u_grain; 6344uniform vec2 u_resolution; 6345 6346// Blend uniforms (declared for parity; unused by this image-driven mode) 6347uniform int u_blendMode; 6348uniform float u_blendIntensity; 6349uniform float u_blendOffset; 6350uniform float u_blendRotation; 6351uniform float u_blendScale; 6352uniform int u_blendAnimRotation; 6353uniform int u_blendAnimIntensity; 6354uniform int u_blendAnimOffset; 6355uniform float u_blendAnimSpeed; 6356uniform float u_blendNoiseMask; 6357uniform float u_blendNoiseScale; 6358uniform float u_blendFalloff; 6359uniform int u_blendDualLayer; 6360uniform int u_blendMode2; 6361uniform float u_blendIntensity2; 6362uniform float u_blendOffset2; 6363uniform float u_blendRotation2; 6364uniform float u_blendScale2; 6365 6366// Heatmap params (match Paper's controls) 6367uniform float u_innerGlow; // 0-1 tight core glow 6368uniform float u_outerGlow; // 0-1 wide bloom halo 6369uniform float u_contour; // 0-1 contour band strength 6370uniform float u_noise; // 0-1 grain in the heat field 6371uniform float u_scale; // image zoom / procedural scale 6372uniform float u_flowSpeed; // outer-glow animation speed 6373 6374__COMMON__ 6375 6376float hm_getImgFrame(vec2 uv, float th) { 6377 float frame = 1.0; 6378 frame *= smoothstep(0.0, th, uv.y); 6379 frame *= 1.0 - smoothstep(1.0 - th, 1.0, uv.y); 6380 frame *= smoothstep(0.0, th, uv.x); 6381 frame *= 1.0 - smoothstep(1.0 - th, 1.0, uv.x); 6382 return frame; 6383} 6384 6385// 3x3 weighted blur of the green channel (big-blur channel), mirroring Paper. 6386float hm_blurG(vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerG) { 6387 vec2 texel = 1.0 / vec2(textureSize(u_imageTexture, 0)); 6388 vec2 r = radius * texel; 6389 float sum = 4.0 * centerG; 6390 sum += 2.0 * textureGrad(u_imageTexture, uv + vec2(0.0, -r.y), dudx, dudy).g; 6391 sum += 2.0 * textureGrad(u_imageTexture, uv + vec2(0.0, r.y), dudx, dudy).g; 6392 sum += 2.0 * textureGrad(u_imageTexture, uv + vec2(-r.x, 0.0), dudx, dudy).g; 6393 sum += 2.0 * textureGrad(u_imageTexture, uv + vec2(r.x, 0.0), dudx, dudy).g; 6394 sum += textureGrad(u_imageTexture, uv + vec2(-r.x, -r.y), dudx, dudy).g; 6395 sum += textureGrad(u_imageTexture, uv + vec2(r.x, -r.y), dudx, dudy).g; 6396 sum += textureGrad(u_imageTexture, uv + vec2(-r.x, r.y), dudx, dudy).g; 6397 sum += textureGrad(u_imageTexture, uv + vec2(r.x, r.y), dudx, dudy).g; 6398 return sum / 16.0; 6399} 6400 6401float hm_hash(vec2 p) { 6402 return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453123); 6403} 6404 6405void main() { 6406 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 6407 vec2 uvN = vec2(vUv.x, 1.0 - vUv.y); 6408 6409 // No image: a soft animated heat blob so the mode isn't blank. 6410 if (u_hasImage == 0) { 6411 float time = u_time * u_speed; 6412 vec2 p = vec2((vUv.x - 0.5) * aspect, vUv.y - 0.5) / max(u_scale, 0.1); 6413 float d = length(p) * 1.6; 6414 float blob = smoothstep(1.0, 0.0, d); 6415 blob *= 0.55 + 0.6 * (fbm(p * 3.0 + vec2(time * u_flowSpeed * 0.3, time * u_flowSpeed * 0.15), 1.0, 3, 0.5, 2.0) * 0.5 + 0.5); 6416 float heat = clamp(blob * (0.5 + u_innerGlow) + smoothstep(1.4, 0.0, d) * (u_outerGlow * 0.5), 0.0, 1.0); 6417 heat += (0.005 + 0.35 * u_noise) * (hm_hash(uvN) - 0.5); 6418 vec3 c = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(heat, 0.0, 1.0)); 6419 c *= smoothstep(0.0, 0.18, heat); // composite over dark bg (Paper's colorBack) 6420 fragColor = outputColor(c, gl_FragCoord.xy, 1.0); 6421 return; 6422 } 6423 6424 // Reconstruct the padded-texture aspect from the raw image size, using the 6425 // same padding formula as the CPU preprocessing (canvasSize 1000, padding 375). 6426 float ratio = u_imageSize.x / max(u_imageSize.y, 1.0); 6427 float imgW = ratio > 1.0 ? 1000.0 : 1000.0 * ratio; 6428 float imgH = ratio > 1.0 ? 1000.0 / ratio : 1000.0; 6429 float texAspect = (imgW + 750.0) / (imgH + 750.0); 6430 6431 // Paper's exact image-fit sizing (contain, u_fit=1), reconstructed
6431in the 6432 // fragment since HueGrid's vertex shader is a passthrough. origin (0.5,0.5), 6433 // offset (0,0), and rotation (0) use Paper's defaults, so those terms drop out. 6434 vec2 uvC = vUv - 0.5; 6435 float boxX = min(u_resolution.x / texAspect, u_resolution.y) * texAspect; 6436 vec2 boxScale = u_resolution / vec2(boxX, boxX / texAspect); 6437 vec2 vImageUV = uvC * boxScale / max(u_scale, 0.0001); 6438 vImageUV += 0.5; 6439 vImageUV.y = 1.0 - vImageUV.y; 6440 6441 // Paper's un-pad: sample the image region within the padded texture. 6442 vec2 sUV = (vImageUV - 0.5) * 0.5714285714285714 + 0.5; 6443 float imgSoftFrame = hm_getImgFrame(sUV, 0.03); 6444 6445 vec4 img = texture(u_imageTexture, sUV); 6446 vec2 dudx = dFdx(sUV); 6447 vec2 dudy = dFdy(sUV); 6448 6449 float shape = img.r; // contour channel 6450 float gBlur = hm_blurG(sUV, dudx, dudy, 8.0, img.g); // big blur (outer glow) 6451 float outerBlur = 1.0 - mix(1.0, gBlur, shape); 6452 float innerBlur = mix(gBlur, 0.0, shape); 6453 float contourCh = mix(img.b, 0.0, shape); 6454 outerBlur *= imgSoftFrame; 6455 6456 float inner = 0.8 + 0.8 * innerBlur; 6457 inner *= (u_innerGlow * 2.0); 6458 inner += (u_contour * 2.0) * contourCh; 6459 inner = min(1.0, inner); 6460 inner *= (1.0 - shape); 6461 inner = pow(inner, 1.2); 6462 6463 float t = mod(u_time * u_speed * u_flowSpeed * 0.3 - 0.1, 1.0); 6464 float outer = 0.9 * pow(max(outerBlur, 0.0), 0.8); 6465 float y = mod(sUV.y - t, 1.0); 6466 float animatedMask = 0.5 + smoothstep(0.3, 0.65, y) * (1.0 - smoothstep(0.65, 1.0, y)); 6467 outer *= animatedMask; 6468 outer *= mix(0.0, 5.0, pow(u_outerGlow, 2.0)); 6469 outer *= imgSoftFrame; 6470 6471 float heat = clamp(inner + outer, 0.0, 1.0); 6472 heat += (0.005 + 0.35 * u_noise) * (hm_hash(uvN) - 0.5); 6473 heat = clamp(heat, 0.0, 1.0); 6474 6475 vec3 color = mixColors(u_colors, u_colorPositions, u_colorCount, heat); 6476 // Paper composites the heat over a dark background (colorBack, default black): 6477 // fade to near-black where there's little/no heat so the shape glows on dark. 6478 color *= smoothstep(0.0, 0.18, heat); 6479 color += 0.02 * (hm_hash(uvN + 1.0) - 0.5); 6480 6481 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 6482} 6483`,z=`#version 300 es 6484precision highp float; 6485 6486in vec2 vUv; 6487out vec4 fragColor; 6488 6489uniform float u_time; 6490uniform float u_speed; 6491uniform vec3 u_colors[12]; 6492uniform float u_colorPositions[12]; 6493uniform int u_colorCount; 6494uniform float u_direction; 6495uniform float u_grain; 6496uniform vec2 u_resolution; 6497 6498// Blend uniforms 6499uniform int u_blendMode; 6500uniform float u_blendIntensity; 6501uniform float u_blendOffset; 6502uniform float u_blendRotation; 6503uniform float u_blendScale; 6504uniform int u_blendAnimRotation; 6505uniform int u_blendAnimIntensity; 6506uniform int u_blendAnimOffset; 6507uniform float u_blendAnimSpeed; 6508uniform float u_blendNoiseMask; 6509uniform float u_blendNoiseScale; 6510uniform float u_blendFalloff; 6511uniform int u_blendDualLayer; 6512uniform int u_blendMode2; 6513uniform float u_blendIntensity2; 6514uniform float u_blendOffset2; 6515uniform float u_blendRotation2; 6516uniform float u_blendScale2; 6517 6518// Mode-specific uniforms 6519uniform float u_gridScale; 6520uniform float u_lineWidth; 6521uniform float u_glowIntensity; 6522uniform float u_glowSize; 6523uniform float u_pulseSpeed; 6524uniform float u_warp; 6525uniform float u_secondaryGrid; 6526uniform float u_perspective; 6527 6528__COMMON__ 6529 6530void main() { 6531 vec2 uv = vUv; 6532 float time = u_time * u_speed; 6533 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 6534 uv = applyMouseWarp(uv, aspect); 6535 6536 // Center and aspect-correct 6537 vec2 p = uv - 0.5; 6538 p.x *= aspect; 6539 6540 // Perspective tilt: top of screen narrows to create 3D ground plane effect 6541 float perspStrength = u_perspective * 0.8; 6542 float yNorm = uv.y; 6543 float perspScale = 1.0 + perspStrength * (1.0 - yNorm); 6544 p.x *= perspScale; 6545 // Slight vertical foreshortening 6546 p.y = p.y * (1.0 + perspStrength * 0.5) - perspStrength * 0.25; 6547 6548 // Domain warping with noise for organic grid deformation 6549 float warpN1 = snoise(p * 1.8 + time * 0.15); 6550 float warpN2 = snoise(p * 2.6 - time * 0.12); 6551 vec2 warpOffset = vec2(warpN1, warpN2) * u_warp * 0.25; 6552 vec2 warped = p + warpOffset; 6553 6554 // Scale for the grid 6555 float gridSc = max(u_gridScale, 0.5) * 6.0; 6556 vec2 gridUv = warped * gridSc; 6557 6558 // Primary grid: distance to nearest grid line (each axis) 6559 vec2 gridFract = abs(fract(gridUv) - 0.5); 6560 float lineDistX = gridFract.x; 6561 float lineDistY = gridFract.y; 6562 float lineDist = min(lineDistX, lineDistY); 6563 6564 // Line thickness and glow kernel 6565 float lineThick = max(u_lineWidth, 0.01) * 0.08; 6566 float glowK = max(u_glowSize, 0.05) * 12.0; 6567
6568 // Floor the core width at ~1px in screen space (fwidth) so thin grid lines get 6569 // analytic anti-aliasing instead of shimmering/aliasing. Keeps the profile shape. 6570 float coreW = max(lineThick, fwidth(lineDist) * 1.5); 6571 6572 // Neon glow: exponential falloff for realistic neon look 6573 float primaryGlow = exp(-lineDist * glowK); 6574 // Sharp core line (analytic-AA width) 6575 float primaryCore = smoothstep(coreW * 1.5, coreW * 0.3, lineDist); 6576 6577 // Secondary grid at half scale for depth 6578 float secondaryGlow = 0.0; 6579 float secondaryCore = 0.0; 6580 if (u_secondaryGrid > 0.01) { 6581 vec2 gridUv2 = warped * gridSc * 2.0; 6582 vec2 gridFract2 = abs(fract(gridUv2) - 0.5); 6583 float lineDist2 = min(gridFract2.x, gridFract2.y); 6584 float coreW2 = max(lineThick, fwidth(lineDist2) * 1.5); 6585 secondaryGlow = exp(-lineDist2 * glowK * 1.5) * u_secondaryGrid; 6586 secondaryCore = smoothstep(coreW2 * 1.2, coreW2 * 0.2, lineDist2) * u_secondaryGrid * 0.5; 6587 } 6588 6589 // Temporal pulse modulation 6590 float pulse = 1.0 + sin(time * u_pulseSpeed) * 0.3; 6591 6592 // Intersection hotspots: both X and Y are close to grid line 6593 float intersectDist = lineDistX + lineDistY; 6594 float hotspot = exp(-intersectDist * glowK * 2.5); 6595 6596 // Gradient t-value: map grid position to color 6597 // Use direction-based sampling from the un-warped UV 6598 float angle = radians(u_direction); 6599 vec2 dir = vec2(cos(angle), sin(angle)); 6600 float t = dot(uv - 0.5, dir) + 0.5; 6601 6602 // Modulate t by local grid intersection for color variation 6603 vec2 cellId = floor(gridUv); 6604 float cellOffset = snoise(cellId * 0.37) * 0.15; 6605 float tLocal = clamp(t + cellOffset, 0.0, 1.0); 6606 6607 // Image-driven gradient modulation 6608 float imgLum = imageLuminance(uv, aspect); 6609 if (imgLum >= 0.0) { 6610 tLocal = mix(tLocal, imgLum, u_imageIntensity); 6611 } 6612 6613 // Sample user gradient colors 6614 vec3 lineColor = mixColors(u_colors, u_colorPositions, u_colorCount, tLocal); 6615 vec3 hotspotColor = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(tLocal + 0.15, 0.0, 1.0)); 6616 6617 // Dark background 6618 vec3 bgColor = vec3(0.005, 0.005, 0.015); 6619 6620 // Compose neon glow layers with additive blending 6621 float glowAmt = u_glowIntensity * 1.5; 6622 vec3 color = bgColor; 6623 6624 // Primary grid glow (soft outer glow) 6625 color += lineColor * primaryGlow * glowAmt * pulse * 0.6; 6626 // Primary grid core (bright center) 6627 color += lineColor * primaryCore * glowAmt * pulse * 1.4; 6628 6629 // Secondary grid 6630 color += lineColor * 0.5 * secondaryGlow * glowAmt * pulse * 0.4; 6631 color += lineColor * 0.5 * secondaryCore * glowAmt * pulse * 0.6; 6632 6633 // Intersection hotspots (bright specular) 6634 color += hotspotColor * hotspot * glowAmt * pulse * 2.0; 6635 // White-hot center at intersections 6636 color += vec3(1.0, 0.98, 0.95) * hotspot * hotspot * glowAmt * 0.8; 6637 6638 // Subtle ambient glow bleeding into background 6639 float ambientGlow = exp(-lineDist * glowK * 0.3) * 0.08 * u_glowIntensity; 6640 color += lineColor * ambientGlow; 6641 6642 // Slight vignette to darken edges 6643 float vig = 1.0 - smoothstep(0.3, 1.1, length(uv - 0.5) * 1.4); 6644 color *= 0.7 + 0.3 * vig; 6645 6646 // Grain 6647 color += grain(uv, time, u_grain); 6648 6649 // Self-blend 6650 if (u_blendMode > 0) { 6651 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 6652 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 6653 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 6654 bIntensity = noiseModulatedIntensity(bIntensity, vUv, time, u_blendNoiseMask, u_blendNoiseScale); 6655 bIntensity = applyBlendFalloff(bIntensity, t, u_blendFalloff); 6656 float tB = blendLayerT(vUv, t, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 6657 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 6658 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 6659 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 6660 float tB2 = blendLayerT(vUv, t, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 6661 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 6662 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 6663 } 6664 } 6665 6666 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 6667} 6668`,U=`#version 300 es 6669precision highp float; 6670 6671in vec2 vUv; 6672out vec4 fragColor; 6673 6674uniform float u_time; 6675uniform float u_speed; 6676uniform vec3 u_colors[12]; 6677uniform float u_colorPositions[12]; 6678uniform int u_colorCount; 6679uniform float u_direction; 6680uniform float u_grain; 6681uniform vec2 u_resolution; 6682 6683// Blend uniforms 6684uniform int u_blendMode; 6685uniform float u_blendIntensity; 6686uniform float u_blendOffset; 6687uniform float u_blendRotation; 6688uniform float u_blendScale; 6689uniform int u_blendAnimRotation; 6690uniform int u_blendAnimIntensity; 6691uniform int u_blendAnimOffset; 6692uniform float u_blendAnimSpeed; 6693uniform float u_blendNoiseMask; 6694uniform float u_blendNoiseScale; 6695uniform float u_blendFalloff; 6696uniform int u_blendDualLayer; 6697uniform int u_blendMode2; 6698uniform float u_blendIntensity2; 6699uniform float u_blendOffset2; 6700uniform float u_blendRotation2; 6701uniform float u_blendScale2; 6702 6703// Mode-specific uniforms 6704uniform float u_paletteSpeed; 6705uniform float u_complexity; 6706uniform float u_phaseShift; 6707uniform float u_brightness; 6708uniform float u_contrast; 6709uniform float u_frequency; 6710uniform float u_warp; 6711uniform float u_sharpness; 6712 6713__COMMON__ 6714 6715// Inigo Quilez cosine palette formula 6716vec3 cosinePalette(float t, vec3 a, vec3 b, vec3 c, vec3 d) { 6717 return a + b * cos(6.2831853 * (c * t + d)); 6718} 6719 6720void main() { 6721 vec2 uv = vUv; 6722 float time = u_time * u_speed; 6723 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 6724 uv = applyMouseWarp(uv, aspect); 6725 6726 // Center and aspect-correct for spatial calculations 6727 vec2 p = uv - 0.5; 6728 p.x *= aspect; 6729 6730 // Direction-based base t-value 6731 float angle = radians(u_direction); 6732 vec2 dir = vec2(cos(angle), sin(angle)); 6733 float baseT = dot(uv - 0.5, dir) + 0.5; 6734 6735 // Domain warping with noise for organic deformation 6736 float warpN1 = snoise(p * 2.5 + time * 0.12); 6737 float warpN2 = snoise(p * 3.8 - time * 0.09 + vec2(5.2, 1.3)); 6738 float warpN3 = snoise(p * 5.1 + time * 0.07 + vec2(-2.1, 8.7)); 6739 float warpAmount = (warpN1 + warpN2 * 0.5 + warpN3 * 0.25) * u_warp * 0.3; 6740 float t = clamp(baseT + warpAmount, 0.0, 1.0); 6741 6742 // Image-driven gradient modulation 6743 float imgLum = imageLuminance(uv, aspect); 6744 if (imgLum >= 0.0) { 6745 t = mix(t, imgLum, u_imageIntensity); 6746 } 6747 6748 // Derive cosine palette vectors from user gradient colors. 6749 // 'a' = brightness center (average of first two colors) 6750 // 'b' = contrast amplitude (difference between colors) 6751 // 'c' = frequency multiplier per channel 6752 // 'd' = phase offset per channel 6753 vec3 col0 = u_colors[0]; 6754 vec3 col1 = u_colors[min(1, u_colorCount - 1)]; 6755 vec3 col2 = u_colors[min(2, u_colorCount - 1)]; 6756 6757 vec3 a = mix(col0, col1, 0.5) * u_brightness; 6758 vec3 b = abs(col1 - col0) * u_contrast + 0.1; 6759 vec3 c = vec3(u_frequency * 1.0, u_frequency * 1.15, u_frequency * 0.85); 6760 vec3 d = vec3(0.0, u_phaseShift * 0.33, u_phaseShift * 0.67); 6761 6762 // Animate the phase over time for smooth color cycling 6763 float phaseAnim = time * u_paletteSpeed * 0.15; 6764 d += phaseAnim; 6765 6766 // Base layer: primary cosine palette 6767 vec3 color = cosinePalette(t, a, b, c, d); 6768 6769 // Layer additional frequencies for complexity 6770 float complexLayers = u_complexity * 4.0; 6771 int layerCount = int(clamp(complexLayers, 0.0, 4.0)); 6772 6773 for (int i = 1; i <= 4; i++) { 6774 if (i > layerCount) break; 6775 float fi = float(i); 6776 6777 // Each layer uses higher frequency, different phase, and warped t 6778 float layerFreq = u_frequency * (1.0 + fi * 0.8); 6779 vec3 layerC = vec3(layerFreq, layerFreq * 1.1, layerFreq * 0.9); 6780 6781 // Offset the phase per layer for variety 6782 vec3 layerD = d + vec3(fi * 0.37, fi * 0.53, fi * 0.71); 6783 6784 // Slightly different spatial position per layer 6785 float layerWarp = snoise(p * (2.0 + fi * 1.5) + time * (0.05 + fi * 0.03)); 6786 float layerT = clamp(t + layerWarp * u_warp * 0.15, 0.0, 1.0); 6787 6788 vec3 layerColor = cosinePalette(layerT, a * 0.8, b * (0.6 / fi), layerC, layerD); 6789 6790 // Diminishing blend weight per layer 6791 float weight = 0.35 / fi; 6792 color = mix(color, layerColor, weight); 6793 } 6794 6795 // Optional sharpness: create sharper color band transitions 6796 if (u_sharpness > 0.01) { 6797 // Quantize the palette output to create distinct bands 6798 float bands = 3.0 + u_sharpness * 12.0; 6799 vec3 quantized = floor(color * bands + 0.5) / bands; 6800 color = mix(color, quantized, u_sharpness * 0.7); 6801 6802 // Also apply pow for contrast-based sharpening 6803 color = pow(max(color, vec3(0.0)), vec3(1.0 + u_sharpness * 0.5)); 6804 } 6805 6806 // Modulate with the user gradient: blend the cosine palette with 6807 // the direct gradient sample for artistic control 6808 vec3 gradientColor = mixColors(u_colors, u_colorPositions, u_colorCount, t); 6809 color = mix(color, color * gradientColor * 2.0, 0.3); 6810 6811 // Clamp to valid range 6812 color = clamp(color, vec3(0.0), vec3(1.5)); 6813 6814 // Grain 6815 color += grain(uv, time, u_grain); 6816 6817 // Self-blend 6818 if (u_blendMode > 0) { 6819 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 6820 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 6821 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 6822 bIntensity = noiseModulatedIntensity(bIntensity, vUv, time, u_blendNoiseMask, u_blendNoiseScale); 6823 bIntensity = applyBlendFalloff(bIntensity, t, u_blendFalloff);
6824 float tB = blendLayerT(vUv, t, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 6825 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 6826 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 6827 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 6828 float tB2 = blendLayerT(vUv, t, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 6829 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 6830 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 6831 } 6832 } 6833 6834 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 6835} 6836`,q=`#version 300 es 6837precision highp float; 6838 6839in vec2 vUv; 6840out vec4 fragColor; 6841 6842uniform float u_time; 6843uniform float u_speed; 6844uniform vec3 u_colors[12]; 6845uniform float u_colorPositions[12]; 6846uniform int u_colorCount; 6847uniform float u_direction; 6848uniform float u_grain; 6849uniform vec2 u_resolution; 6850 6851// Blend uniforms 6852uniform int u_blendMode; 6853uniform float u_blendIntensity; 6854uniform float u_blendOffset; 6855uniform float u_blendRotation; 6856uniform float u_blendScale; 6857uniform int u_blendAnimRotation; 6858uniform int u_blendAnimIntensity; 6859uniform int u_blendAnimOffset; 6860uniform float u_blendAnimSpeed; 6861uniform float u_blendNoiseMask; 6862uniform float u_blendNoiseScale; 6863uniform float u_blendFalloff; 6864uniform int u_blendDualLayer; 6865uniform int u_blendMode2; 6866uniform float u_blendIntensity2; 6867uniform float u_blendOffset2; 6868uniform float u_blendRotation2; 6869uniform float u_blendScale2; 6870 6871// Mode-specific uniforms 6872uniform int u_layers; 6873uniform float u_complexity; 6874uniform float u_turbulence; 6875uniform float u_colorCycle; 6876uniform float u_pulsate; 6877uniform float u_warmth; 6878uniform float u_scale; 6879uniform float u_blend; 6880 6881__COMMON__ 6882 6883void main() { 6884 vec2 uv = vUv; 6885 float time = u_time * u_speed; 6886 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 6887 uv = applyMouseWarp(uv, aspect); 6888 6889 // Center and aspect-correct 6890 vec2 p = uv - 0.5; 6891 p.x *= aspect; 6892 6893 // Scale the plasma domain 6894 vec2 sp = p * max(u_scale, 0.1) * 4.0; 6895 6896 // ---- Aurora-like domain warp for organic flow ---- 6897 float warp1 = snoise(sp * 0.8 + time * 0.12); 6898 float warp2 = snoise(sp * 1.6 - time * 0.09); 6899 sp += vec2(warp1, warp2) * u_turbulence * 0.3; 6900 6901 // Complexity multiplier 6902 float cx = 1.0 + u_complexity * 1.5; 6903 6904 // ---- Three energy layers with noise-modulated sin patterns ---- 6905 float l1 = sin((sp.x * 11.0 * cx + time * 1.8) + snoise(sp * 4.0) * 4.0) * 0.5 + 0.5; 6906 float l2 = sin((sp.y * 13.0 * cx - time * 1.4) + snoise(sp * 3.3 + vec2(5.0, 0.0)) * 3.2) * 0.5 + 0.5; 6907 float l3 = sin((length(sp) * 18.0 * cx - time * 2.3) + snoise(sp * 2.0 + vec2(0.0, 8.0)) * 4.0) * 0.5 + 0.5; 6908 6909 // Color cycling 6910 float cycleOff = time * u_colorCycle * 0.08; 6911 float t1 = fract(l1 + cycleOff); 6912 float t2 = fract(l2 + cycleOff + 0.33); 6913 float t3 = fract(l3 + cycleOff + 0.66); 6914 6915 // Image modulation 6916 float imgLum = imageLuminance(uv, aspect); 6917 if (imgLum >= 0.0) { 6918 t1 = mix(t1, imgLum, u_imageIntensity); 6919 t2 = mix(t2, imgLum, u_imageIntensity); 6920 t3 = mix(t3, imgLum, u_imageIntensity); 6921 } 6922 6923 // Color each layer from different gradient positions 6924 vec3 c1 = mixColors(u_colors, u_colorPositions, u_colorCount, t1); 6925 vec3 c2 = mixColors(u_colors, u_colorPositions, u_colorCount, t2); 6926 vec3 c3 = mixColors(u_colors, u_colorPositions, u_colorCount, t3); 6927 6928 // ---- Additive blending: layers combine for bright intersections ---- 6929 vec3 additive = clamp(c1 * 0.55 + c2 * 0.45 + c3 * 0.38, vec3(0.0), vec3(2.0)); 6930 6931 // Screen blend path for neon glow 6932 vec3 screenMix = c1; 6933 screenMix = 1.0 - (1.0 - screenMix) * (1.0 - c2 * 0.6); 6934 screenMix = 1.0 - (1.0 - screenMix) * (1.0 - c3 * 0.5); 6935 6936 vec3 color = mix(additive, screenMix, u_blend); 6937 6938 // ---- Subsurface glow via noise-derived normal ---- 6939 float surfaceN = snoise(sp * 2.0 + time * 0.1); 6940 float surfaceDx = snoise((sp + vec2(0.02, 0.0)) * 2.0 + time * 0.1); 6941 float surfaceDy = snoise((sp + vec2(0.0, 0.02)) * 2.0 + time * 0.1); 6942 vec3 surfN = normalize(vec3(surfaceN - surfaceDx, surfaceN - surfaceDy, 0.22)); 6943 float fresnel = pow(1.0 - max(dot(surfN, vec3(0.0, 0.0, 1.0)), 0.0), 2.8); 6944 6945 // Rim glow adds edge brightness 6946 color += fresnel * c1 * 0.3; 6947 6948 // ---- Hot spots: where all 3 layers peak simultaneously ---- 6949 float hotSpot = l1 * l2 * l3; 6950 color += vec3(pow(hotSpot, 2.0) * 3.0) * 0.4 * u_blend; 6951 6952 // ---- Pulsation ---- 6953 float pulse = 1.0 + sin(time * u_pulsate * 0.6) * 0.25 * u_pulsate; 6954 color *= pulse; 6955 6956 // ---- Warmth bias ---- 6957 color.r *= 1.0 + u_warmth * 0.3;
6958 color.b *= 1.0 - u_warmth * 0.15; 6959 6960 // ---- Saturation boost ---- 6961 float lum = dot(color, vec3(0.2126, 0.7152, 0.0722)); 6962 color = mix(vec3(lum), color, 1.3); 6963 6964 color = clamp(color, vec3(0.0), vec3(2.0)); 6965 color += grain(uv, time, u_grain); 6966 6967 // Self-blend (use t1 as reference) 6968 float baseT = t1; 6969 if (u_blendMode > 0) { 6970 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 6971 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 6972 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 6973 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 6974 bIntensity = applyBlendFalloff(bIntensity, baseT, u_blendFalloff); 6975 float tB = blendLayerT(uv, baseT, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 6976 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 6977 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 6978 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 6979 float tB2 = blendLayerT(uv, baseT, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 6980 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 6981 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 6982 } 6983 } 6984 6985 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 6986} 6987`,G=`#version 300 es 6988precision highp float; 6989 6990in vec2 vUv; 6991out vec4 fragColor; 6992 6993uniform float u_time; 6994uniform float u_speed; 6995uniform vec3 u_colors[12]; 6996uniform float u_colorPositions[12]; 6997uniform int u_colorCount; 6998uniform float u_direction; 6999uniform float u_grain; 7000uniform vec2 u_resolution; 7001 7002// Blend uniforms 7003uniform int u_blendMode; 7004uniform float u_blendIntensity; 7005uniform float u_blendOffset; 7006uniform float u_blendRotation; 7007uniform float u_blendScale; 7008uniform int u_blendAnimRotation; 7009uniform int u_blendAnimIntensity; 7010uniform int u_blendAnimOffset; 7011uniform float u_blendAnimSpeed; 7012uniform float u_blendNoiseMask; 7013uniform float u_blendNoiseScale; 7014uniform float u_blendFalloff; 7015uniform int u_blendDualLayer; 7016uniform int u_blendMode2; 7017uniform float u_blendIntensity2; 7018uniform float u_blendOffset2; 7019uniform float u_blendRotation2; 7020uniform float u_blendScale2; 7021 7022// Mode-specific uniforms 7023uniform float u_glowRadius; 7024uniform float u_glowIntensity; 7025uniform float u_scatterAmount; 7026uniform float u_rimPower; 7027uniform float u_absorption; 7028uniform float u_thickness; 7029uniform float u_innerGlow; 7030uniform float u_organicShape; 7031 7032__COMMON__ 7033 7034// Compute a smooth noise-based surface field. 7035// Returns a height value representing the translucent "surface". 7036float surfaceField(vec2 p, float time) { 7037 float n1 = snoise(p * 2.0 + time * 0.08); 7038 float n2 = snoise(p * 4.5 - time * 0.06 + vec2(3.7, 1.2)); 7039 float n3 = snoise(p * 8.2 + time * 0.04 + vec2(-1.5, 5.8)); 7040 float n4 = snoise(p * 14.0 - time * 0.03 + vec2(7.3, -2.9)); 7041 7042 // Organic shape: more octaves = more complex surface topology 7043 float shape = n1 * 0.5 7044 + n2 * 0.25 7045 + n3 * 0.125 * u_organicShape 7046 + n4 * 0.0625 * u_organicShape; 7047 7048 return shape; 7049} 7050 7051// Compute fake normal from noise gradient using central differences. 7052// Accepts the already-computed center value h to avoid a redundant surfaceField call. 7053vec3 computeNormal(vec2 p, float time, float eps, float h) { 7054 float hx = surfaceField(p + vec2(eps, 0.0), time); 7055 float hy = surfaceField(p + vec2(0.0, eps), time); 7056 7057 float dhdx = (hx - h) / eps; 7058 float dhdy = (hy - h) / eps; 7059 7060 // Construct normal from height gradient (pointing "up" from surface) 7061 vec3 normal = normalize(vec3(-dhdx * 0.5, -dhdy * 0.5, 1.0)); 7062 return normal; 7063} 7064 7065void main() { 7066 vec2 uv = vUv; 7067 float time = u_time * u_speed; 7068 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 7069 uv = applyMouseWarp(uv, aspect); 7070 7071 // Center and aspect-correct 7072 vec2 p = uv - 0.5; 7073 p.x *= aspect; 7074 7075 // Direction-based t for gradient mapping 7076 float angle = radians(u_direction); 7077 vec2 dir = vec2(cos(angle), sin(angle)); 7078 float baseT = dot(uv - 0.5, dir) + 0.5; 7079 7080 // Surface field: creates the organic "material" shape 7081 float surface = surfaceField(p, time); 7082 7083 // Thickness: thicker regions absorb more light 7084 // Map surface noise to a thickness value (0 = thin/translucent, 1 = thick/opaque) 7085 float thicknessField = smoothstep(-0.6, 0.6, surface) * u_thickness; 7086 7087 // Compute fake surface normal for fresnel/rim calculation 7088 // Reuses the precomputed surface value to avoid a redundant surfaceField call 7089 float eps = 0.005 + 0.005 * (1.0 - u_organicShape); 7090 vec3 normal = computeNormal(p, time, eps, surface); 7091 7092 // View direction: slightly off-center to create asymmetric rim 7093 float viewShift = sin(time * 0.15) * 0.1;
7094 vec3 viewDir = normalize(vec3(viewShift, 0.05, 1.0)); 7095 7096 // Fresnel rim: edges glow bright (light grazing the surface) 7097 float NdotV = max(dot(normal, viewDir), 0.0); 7098 float rimPow = max(u_rimPower, 0.1) * 4.0; 7099 float fresnel = pow(1.0 - NdotV, rimPow); 7100 7101 // Gradient t-value: modulated by surface topology 7102 float t = clamp(baseT + surface * 0.2, 0.0, 1.0); 7103 7104 // Image-driven gradient modulation 7105 float imgLum = imageLuminance(uv, aspect); 7106 if (imgLum >= 0.0) { 7107 t = mix(t, imgLum, u_imageIntensity); 7108 } 7109 7110 // Base material color from user gradient 7111 vec3 baseColor = mixColors(u_colors, u_colorPositions, u_colorCount, t); 7112 7113 // Subsurface scattering simulation: 7114 // Light penetrates the surface, spreads outward, and takes on the material color. 7115 // We simulate this by sampling colors at offset t-values and blending them. 7116 float scatterRadius = u_scatterAmount * 0.3; 7117 vec3 scatterColor = vec3(0.0); 7118 float scatterWeights = 0.0; 7119 7120 // Sample at multiple offsets around the current point 7121 for (int i = -2; i <= 2; i++) { 7122 float offset = float(i) * scatterRadius * 0.15; 7123 // Also add noise-based spatial scatter 7124 float noiseOffset = snoise(p * 3.0 + vec2(float(i) * 1.7, time * 0.05)) * scatterRadius * 0.1; 7125 float scatterT = clamp(t + offset + noiseOffset, 0.0, 1.0); 7126 7127 vec3 sampleColor = mixColors(u_colors, u_colorPositions, u_colorCount, scatterT); 7128 7129 // Weight: closer samples contribute more 7130 float w = exp(-abs(float(i)) * 0.5); 7131 scatterColor += sampleColor * w; 7132 scatterWeights += w; 7133 } 7134 scatterColor /= max(scatterWeights, 0.001); 7135 7136 // Blend scatter with base: thinner areas show more scatter 7137 float scatterMix = (1.0 - thicknessField * 0.6) * u_scatterAmount * 0.5; 7138 vec3 materialColor = mix(baseColor, scatterColor, scatterMix); 7139 7140 // Absorption: thicker regions absorb more light (darken) 7141 float absorb = 1.0 - thicknessField * u_absorption * 0.7; 7142 materialColor *= absorb; 7143 7144 // Rim glow: bright, saturated light at the edges 7145 vec3 rimColor = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(t + 0.2, 0.0, 1.0)); 7146 // Make rim brighter and slightly desaturated for a luminous effect 7147 rimColor = mix(rimColor, vec3(1.0), 0.3); 7148 float rimIntensity = fresnel * u_glowIntensity * 1.5; 7149 7150 // Inner glow: warm emission from within, modulated by noise 7151 float innerNoiseA = snoise(p * 3.5 + time * 0.12 + vec2(2.1, -0.8)); 7152 float innerNoiseB = snoise(p * 5.8 - time * 0.09 + vec2(-3.4, 6.1)); 7153 float innerField = smoothstep(-0.2, 0.5, innerNoiseA * 0.6 + innerNoiseB * 0.4); 7154 7155 vec3 innerGlowColor = mixColors(u_colors, u_colorPositions, u_colorCount, clamp(t - 0.15, 0.0, 1.0)); 7156 // Warm tint for inner glow to simulate internal light emission 7157 innerGlowColor = mix(innerGlowColor, innerGlowColor * vec3(1.2, 1.05, 0.9), 0.4); 7158 float innerIntensity = innerField * u_innerGlow * (1.0 - thicknessField * 0.3); 7159 7160 // Subsurface glow radius: soft, diffused glow around the entire surface 7161 float distFromCenter = length(p); 7162 float glowFalloff = exp(-distFromCenter * (3.0 - u_glowRadius * 2.0)); 7163 vec3 ssGlow = scatterColor * glowFalloff * u_glowIntensity * 0.4; 7164 7165 // Final composition: base material + rim + subsurface + inner glow 7166 vec3 color = materialColor; 7167 color += rimColor * rimIntensity; 7168 color += ssGlow; 7169 color += innerGlowColor * innerIntensity * 0.5; 7170 7171 // Subtle surface variation to avoid flatness 7172 float surfaceDetail = snoise(p * 12.0 + time * 0.02) * 0.03; 7173 color += color * surfaceDetail; 7174 7175 // Soft vignette to keep focus 7176 float vig = 1.0 - smoothstep(0.4, 1.0, distFromCenter * 1.2); 7177 color *= 0.85 + 0.15 * vig; 7178 7179 // Clamp 7180 color = clamp(color, vec3(0.0), vec3(1.6)); 7181 7182 // Grain 7183 color += grain(uv, time, u_grain); 7184 7185 // Self-blend 7186 if (u_blendMode > 0) { 7187 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 7188 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 7189 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 7190 bIntensity = noiseModulatedIntensity(bIntensity, vUv, time, u_blendNoiseMask, u_blendNoiseScale); 7191 bIntensity = applyBlendFalloff(bIntensity, t, u_blendFalloff);
7192 float tB = blendLayerT(vUv, t, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 7193 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 7194 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 7195 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 7196 float tB2 = blendLayerT(vUv, t, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 7197 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 7198 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 7199 } 7200 } 7201 7202 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 7203} 7204`,H=`#version 300 es 7205precision highp float; 7206 7207in vec2 vUv; 7208out vec4 fragColor; 7209 7210// Standard uniforms 7211uniform float u_time; 7212uniform float u_speed; 7213uniform vec3 u_colors[12]; 7214uniform float u_colorPositions[12]; 7215uniform int u_colorCount; 7216uniform float u_direction; 7217uniform float u_grain; 7218uniform vec2 u_resolution; 7219 7220// Blend uniforms 7221uniform int u_blendMode; 7222uniform float u_blendIntensity; 7223uniform float u_blendOffset; 7224uniform float u_blendRotation; 7225uniform float u_blendScale; 7226uniform int u_blendAnimRotation; 7227uniform int u_blendAnimIntensity; 7228uniform int u_blendAnimOffset; 7229uniform float u_blendAnimSpeed; 7230uniform float u_blendNoiseMask; 7231uniform float u_blendNoiseScale; 7232uniform float u_blendFalloff; 7233uniform int u_blendDualLayer; 7234uniform int u_blendMode2; 7235uniform float u_blendIntensity2; 7236uniform float u_blendOffset2; 7237uniform float u_blendRotation2; 7238uniform float u_blendScale2; 7239 7240// Mode-specific uniforms 7241uniform int u_effectType; // 0=fire, 1=rain, 2=wind, 3=storm, 4=sand 7242uniform float u_fontSize; 7243uniform float u_density; 7244uniform int u_charSet; 7245uniform float u_flowSpeed; 7246uniform float u_turbulence; 7247uniform float u_noiseScale; 7248uniform float u_contrast; 7249uniform float u_threshold; 7250uniform float u_warpIntensity; 7251uniform float u_gridAngle; 7252uniform float u_cursorInfluence; 7253uniform float u_cursorRadius; 7254uniform float u_colorInfluence; 7255uniform int u_bgMode; // 0=solid, 1=gradient 7256uniform vec3 u_bgColorRGB; 7257uniform vec3 u_inkColorRGB; 7258 7259__COMMON__ 7260 7261// --------------------------------------------------------------------------- 7262// Hash helpers 7263// --------------------------------------------------------------------------- 7264float columnHash(float col) { 7265 return fract(sin(col * 127.1 + 311.7) * 43758.5453); 7266} 7267 7268float cellHash(float col, float row) { 7269 return fract(sin(col * 127.1 + row * 269.5 + 311.7) * 43758.5453); 7270} 7271 7272// --------------------------------------------------------------------------- 7273// Character bitmap sets (5x5 packed into int, bit = iy*5 + ix) 7274// --------------------------------------------------------------------------- 7275 7276// Digit patterns (0-9) -- readable 5x5 bitmaps 7277// Layout: row 0 = bottom, row 4 = top (matches iy*5+ix bit packing) 7278// 7279// 0: ring 1: center col 2: zigzag 3: right-turn 7280// 4: T-bar 5: snake 6: bulge 7: slash 7281// 8: hourglass 9: hook 7282int[10] digitPatterns() { 7283 return int[10]( 7284 // 0: .###. | 1: ..#.. | 2: .###. | 3: .###. 7285 // #...# | .##.. | ....# | ....# 7286 // #...# | ..#.. | .###. | ..##. 7287 // #...# | ..#.. | #.... | ....# 7288 // .###. | .###. | ##### | .###. 7289 0xE9D2E, // 0 = 01110 10011 10100 10010 01110 7290 0x7108C, // 1 = 00111 00010 00001 00001 01100 7291 0x1F4270E, // 2 = 11111 00100 00100 01110 01110 (simplified) 7292 0xE83A0E, // 3 = 01110 10000 01110 00000 01110 (simplified) 7293 7294 // 4: #...# | 5: ##### | 6: .###. | 7: ##### 7295 // #...# | #.... | #.... | ...#. 7296 // ##### | .###. | ####. | ..#.. 7297 // ....# | ....# | #...# | .#... 7298 // ....# | ####. | .###. | #.... 7299 0x108FD1, // 4 7300 0xE82F1F, // 5 7301 0xE958E, // 6 7302 0x11111F, // 7 7303 7304 // 8: .###. | 9: .###. 7305 // #...# | #...# 7306 // .###. | .#### 7307 // #...# | ....# 7308 // .###. | .###. 7309 0xE95D2E, // 8 7310 0xE87D2E // 9 7311 ); 7312} 7313 7314// Symbol patterns -- ordered by density: space . : - = + # % @ ! 7315int[10] symbolPatterns() { 7316 return int[10]( 7317 0, // space 7318 0x4000, // . 7319 0x4010040, // : (invalid > 25 bits, but kept for consistency with ascii.ts) 7320 0xA8000, // - 7321 0xA80A8, // = 7322 0x4AE04, // + 7323 0xEA5AE, // # 7324 0x155D57, // % 7325 0x1F7FBE, // @ 7326 0x4E444 // ! 7327 ); 7328} 7329 7330// Katakana-style angular patterns -- geometric strokes 7331int[10] katakanaPatterns() { 7332 return int[10]( 7333 // Angular strokes reminiscent of katakana characters 7334 0x1F0842, // a-like: horizontal top + diagonal 7335 0x4A52A, // i-like: two strokes 7336 0xE0C21, // u-like: crown shape 7337 0x15294, // e-like: H-bar 7338 0xE4A52, // o-like: cross with tail 7339 0x4E4E4, // ka-like: vertical with bars 7340 0x1597A, // ki-like: ladder 7341 0xA5294, // ku-like: angle 7342 0x739CE, // ke-like: flag 7343 0x4E944 // ko-like: box with stem 7344 ); 7345} 7346 7347// Mixed patterns -- digits then symbols interleaved 7348int[20] mixedPatterns() { 7349 int d[10] = digitPatterns(); 7350 int s[10] = symbolPatterns(); 7351 return int[20]( 7352 d[0], d[1], d[2], d[3], d[4], 7353 d[5], d[6], d[7], d[8], d[9], 7354 s[0], s[1], s[2], s[3], s[4], 7355 s[5], s[6], s[7], s[8], s[9] 7356 ); 7357} 7358 7359// --------------------------------------------------------------------------- 7360// Character pixel lookup 7361// --------------------------------------------------------------------------- 7362float getFireCharPixel(int charIndex, vec2 pos, int charSetId) { 7363 int ix = int(pos.x); 7364 int iy = int(pos.y); 7365 if (ix < 0 || ix >= 5 || iy < 0 || iy >= 5) return 0.0; 7366 7367 int bit = iy * 5 + ix; 7368 int pattern = 0; 7369 7370 if (charSetId == 0) { 7371 // Digits 7372 int pats[10] = digitPatterns();
7373 int idx = clamp(charIndex, 0, 9); 7374 pattern = pats[idx]; 7375 } else if (charSetId == 1) { 7376 // Symbols 7377 int pats[10] = symbolPatterns(); 7378 int idx = clamp(charIndex, 0, 9); 7379 pattern = pats[idx]; 7380 } else if (charSetId == 2) { 7381 // Mixed: 0-9 digits, 10-19 symbols 7382 int mixIdx = charIndex; 7383 if (mixIdx < 10) { 7384 int pats[10] = digitPatterns(); 7385 pattern = pats[clamp(mixIdx, 0, 9)]; 7386 } else { 7387 int pats[10] = symbolPatterns(); 7388 pattern = pats[clamp(mixIdx - 10, 0, 9)]; 7389 } 7390 } else { 7391 // Katakana 7392 int pats[10] = katakanaPatterns(); 7393 int idx = clamp(charIndex, 0, 9); 7394 pattern = pats[idx]; 7395 } 7396 7397 return float((pattern >> bit) & 1); 7398} 7399 7400// --------------------------------------------------------------------------- 7401// Density field functions 7402// --------------------------------------------------------------------------- 7403 7404// Fire: FBM + upward domain warp, dense at bottom, sparse at top 7405float fireDensity(vec2 p, float time, float scale, float warp) { 7406 vec2 q = p * scale; 7407 q.y -= time * 0.3; 7408 7409 // Two noise layers for domain warp 7410 float w1 = snoise(q * 0.8 + time * 0.15); 7411 float w2 = snoise(q * 1.5 - time * 0.12); 7412 q += vec2(w1, w2) * warp; 7413 7414 float d = fbm(q, 2.0, 4, 1.0, 2.0) * 0.5 + 0.5; 7415 7416 // Vertical bias: dense at bottom, sparse at top 7417 d *= mix(0.2, 1.0, pow(1.0 - p.y, 0.5)); 7418 7419 return clamp(d, 0.0, 1.0); 7420} 7421 7422// Rain: continuous falling character streams â columns of drops one after another 7423float rainDensity(vec2 p, float time, float scale, float warp) { 7424 float density = 0.0; 7425 7426 // Two depth layers for parallax richness 7427 for (int layer = 0; layer < 2; layer++) { 7428 float layerSeed = float(layer) * 53.7; 7429 float layerScale = scale * (1.0 + float(layer) * 0.3); 7430 float dropSpeed = 1.5 + float(layer) * 0.7; 7431 7432 // Dense column grid â many narrow columns 7433 float colWidth = 1.0 / (layerScale * 20.0); 7434 float col = floor(p.x / colWidth); 7435 float colFrac = fract(p.x / colWidth); 7436 7437 float ch = columnHash(col + layerSeed); 7438 7439 // 90% of columns active for heavy rain 7440 if (ch < 0.1) continue; 7441 7442 // Column thinness â narrow vertical band 7443 float wobble = snoise(vec2(col * 0.2, time * 0.08)) * warp * 0.15; 7444 float thin = smoothstep(0.4, 0.1, abs(colFrac - 0.5 - wobble)); 7445 7446 // Scroll Y downward â continuous falling stream 7447 float colSpeed = dropSpeed * (0.5 + ch); 7448 float scrollY = p.y + time * colSpeed * 0.25 + ch * 13.0; 7449 7450 // Continuous stream with organic gaps via layered noise 7451 // Low-freq noise for large stream segments, hi-freq for texture 7452 float n1 = snoise(vec2(col * 1.7 + layerSeed, scrollY * scale * 3.0)); 7453 float n2 = snoise(vec2(col * 0.5 + layerSeed * 2.0, scrollY * scale * 6.0)) * 0.3; 7454 float dropY = n1 + n2; 7455 7456 // Bias toward visible â only deepest troughs create gaps (~75% solid) 7457 float streamMask = smoothstep(-0.6, -0.1, dropY); 7458 7459 // Intensity variation along stream for visual depth 7460 float streamIntensity = 0.4 + 0.6 * smoothstep(-0.1, 0.5, dropY); 7461 7462 density += thin * streamMask * streamIntensity; 7463 } 7464 7465 return clamp(density, 0.0, 1.0); 7466} 7467 7468// Wind: horizontally-stretched noise with directional flow 7469float windDensity(vec2 p, float time, float scale, float warp) { 7470 float angle = radians(u_gridAngle); 7471 vec2 windDir = vec2(cos(angle), sin(angle)); 7472 7473 // Horizontally stretched noise (compress along wind direction) 7474 vec2 q = p * scale; 7475 // Stretch perpendicular to wind, compress along wind 7476 float along = dot(q, windDir); 7477 float perp = dot(q, vec2(-windDir.y, windDir.x)); 7478 vec2 stretched = vec2(along * 0.3, perp * 2.0); 7479 7480 // Directional flow 7481 stretched.x -= time * 0.5; 7482 7483 // Domain warp 7484 float w1 = snoise(stretched * 0.8 + time * 0.1) * warp; 7485 stretched += vec2(w1); 7486 7487 float d = snoise(stretched) * 0.5 + 0.5; 7488 7489 // Gust bursts: periodic sine modulation 7490 float gust = sin(along * 2.0 - time * 1.5) * 0.5 + 0.5; 7491 d *= mix(0.5, 1.0, gust); 7492 7493 // Second octave 7494 float d2 = snoise(stretched * 2.0 + time * 0.15) * 0.5 + 0.5; 7495 d = mix(d, d2, 0.3); 7496 7497 return clamp(d, 0.0, 1.0); 7498} 7499 7500// Storm: turbulent FBM with rotating vortex spiral 7501float stormDensity(vec2 p, float time, float scale, float warp) { 7502 vec2 center = vec2(0.5, 0.5); 7503 vec2 delta = p - center; 7504 float dist = length(delta); 7505 float ang = atan(delta.y, delta.x); 7506 7507 // Spiral rotation: angle increases with distance and time 7508 ang += dist * 4.0 - time * 0.8; 7509 7510 // Convert back to cartesian for noise sampling 7511 vec2 q = vec2(cos(ang), sin(ang)) * dist * scale; 7512 7513 // Domain warp 7514 float w1 = snoise(q * 0.6 + time * 0.2) * warp; 7515 float w2 = snoise(q * 1.2 - time * 0.15) * warp; 7516 q += vec2(w1, w2); 7517 7518 // High-frequency turbulent FBM (5 octaves) 7519 float d = fbm(q, 2.0, 5, 1.0, 2.0) * 0.5 + 0.5; 7520 7521 // Add spiral arms 7522 float arms = sin(ang * 3.0 + dist * 8.0 - time * 1.2) * 0.5 + 0.5; 7523 d = mix(d, arms, 0.4); 7524 7525 // Eye of the storm: less dense at exact center 7526 float eye = smoothstep(0.0, 0.15, dist); 7527 d *= eye; 7528 7529 return clamp(d, 0.0, 1.0); 7530} 7531 7532// Sand: flowing particles drifting with wind, settling with gravity 7533float sandDensity(vec2 p, float time, float scale, float warp) { 7534 float density = 0.0; 7535 7536 // Wind direction from gridAngle 7537 float angle = radians(u_gridAngle); 7538 vec2 windDir = vec2(cos(angle), sin(angle)); 7539 7540 // Multiple particle layers at different scales 7541 for (int layer = 0; layer < 4; layer++) { 7542 float layerOffset = float(layer) * 3.14; 7543 float layerScale = scale * (1.5 + float(layer) * 0.8); 7544 7545 // Move with wind + slight gravity (downward drift) 7546 vec2 flow = windDir * time * 0.3 * (1.0 + float(layer) * 0.2); 7547 flow.y -= time * 0.05; // gravity settling 7548 7549 vec2 q = p * layerScale + flow + layerOffset; 7550 7551 // Domain warp for organic drift 7552 float w1 = snoise(q * 0.3 + time * 0.08) * warp; 7553 float w2 = snoise(q * 0.5 - time * 0.06) * warp * 0.5; 7554 q += vec2(w1, w2); 7555 7556 // High-frequency noise for individual grain-like dots 7557 float n = snoise(q * 2.0) * 0.5 + 0.5; 7558 7559 // Sharpen into point-like particles (high power = sharper dots) 7560 n = pow(n, 3.0); 7561 7562 // Layer intensity varies (front layers denser) 7563 float layerWeight = 0.4 + 0.2 * float(3 - layer); 7564 density += n * layerWeight; 7565 } 7566 7567 // Gravity bias: denser at bottom, sparser at top 7568 density *= mix(0.3, 1.0, pow(1.0 - p.y, 0.7)); 7569 7570 // Turbulent gusts 7571 float gust = snoise(vec2(p.x * 2.0 + time * 0.4, p.y * 0.5)) * 0.5 + 0.5; 7572 density *= mix(0.6, 1.2, gust); 7573 7574 return clamp(density, 0.0, 1.0); 7575} 7576 7577// --------------------------------------------------------------------------- 7578// Main 7579// --------------------------------------------------------------------------- 7580void main() { 7581 vec2 uv = vUv; 7582 float time = u_time * u_speed; 7583 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 7584 uv = applyMouseWarp(uv, aspect); 7585 7586 // Base gradient direction for color sampling and self-blend 7587 float angle = radians(u_direction); 7588 vec2 dir = vec2(cos(angle), sin(angle)); 7589 float baseT = dot(uv - 0.5, dir) + 0.5; 7590 baseT = clamp(baseT, 0.0, 1.0); 7591 7592 // Image luminance modulation 7593 float imgLum = imageLuminance(uv, aspect); 7594 if (imgLum >= 0.0) { 7595 baseT = mix(baseT, imgLum, u_imageIntensity); 7596 } 7597 7598 // ----------------------------------------------------------------------- 7599 // Rotated cell grid from gl_FragCoord.xy 7600 // ----------------------------------------------------------------------- 7601 float cellSize = max(u_fontSize * u_density, 1.0); 7602 float gridRad = radians(u_gridAngle); 7603 mat2 gridRot = mat2(cos(gridRad), -sin(gridRad), sin(gridRad), cos(gridRad)); 7604 7605 vec2 rotatedCoord = gridRot * gl_FragCoord.xy; 7606 vec2 cell = floor(rotatedCoord / cellSize); 7607 vec2 cellUV = fract(rotatedCoord / cellSize) * 5.0; 7608 7609 // Cell center in UV space (for mouse distance, color sampling) 7610 vec2 cellCenterPx = (cell + 0.5) * cellSize; 7611 // Unrotate back to screen space 7612 mat2 gridRotInv = mat2(cos(gridRad), sin(gridRad), -sin(gridRad), cos(gridRad)); 7613 vec2 cellCenterScreen = gridRotInv * cellCenterPx; 7614 vec2 cellCenter = cellCenterScreen / u_resolution; 7615 7616 // ----------------------------------------------------------------------- 7617 // Sample density field at cell center 7618 // ----------------------------------------------------------------------- 7619 float scale = u_noiseScale; 7620 float warp = u_warpIntensity; 7621 float flowTime = time * u_flowSpeed; 7622 7623 float density = 0.0; 7624 if (u_effectType == 0) { 7625 density = fireDensity(cellCenter, flowTime, scale, warp); 7626 } else if (u_effectType == 1) { 7627 density = rainDensity(cellCenter, flowTime, scale, warp); 7628 } else if (u_effectType == 2) { 7629 density = windDensity(cellCenter, flowTime, scale, warp); 7630 } else if (u_effectType == 3) { 7631 density = stormDensity(cellCenter, flowTime, scale, warp); 7632 } else { 7633 density = sandDensity(cellCenter, flowTime, scale, warp); 7634 } 7635 7636 // Turbulence: add high-frequency noise variation 7637 if (u_turbulence > 0.0) { 7638 float turb = snoise(cellCenter * scale * 3.0 + flowTime * 0.3) * 0.5 + 0.5; 7639 density = mix(density, density * turb, u_turbulence * 0.5); 7640 } 7641 7642 // Apply contrast (power curve) 7643 density = pow(clamp(density, 0.0, 1.0), u_contrast); 7644 7645 // Apply threshold (smoothstep cutoff) 7646 density = smoothstep(u_threshold, u_threshold + 0.3, density); 7647 7648 // ----------------------------------------------------------------------- 7649 // Mouse cursor boosts local density 7650 // ----------------------------------------------------------------------- 7651 if (u_mouseMode > 0) { 7652 vec2 mouseUv = u_mouse * 0.5 + 0.5;
7653 float mouseDist = distance(cellCenter, mouseUv); 7654 7655 if (u_cursorInfluence > 0.0) { 7656 float cursorBoost = smoothstep(u_cursorRadius, 0.0, mouseDist) * u_cursorInfluence; 7657 density = clamp(density + cursorBoost, 0.0, 1.0); 7658 } 7659 7660 // Mouse velocity trail: subtle density boost along movement path 7661 float velMag = length(u_mouseVelocity); 7662 if (velMag > 0.001) { 7663 float trailBoost = smoothstep(u_cursorRadius * 2.0, 0.0, mouseDist) * velMag * 5.0; 7664 trailBoost = clamp(trailBoost, 0.0, 0.4); 7665 density = clamp(density + trailBoost, 0.0, 1.0); 7666 } 7667 } 7668 7669 // ----------------------------------------------------------------------- 7670 // Map density -> character index (ordered by visual weight) 7671 // ----------------------------------------------------------------------- 7672 int charCount = 10; 7673 if (u_charSet == 2) charCount = 20; // mixed set 7674 7675 // Cell hash for per-cell character variation 7676 float charHash = cellHash(cell.x, cell.y); 7677 7678 // Base index from density (0 = lightest/sparsest, 9/19 = heaviest/densest) 7679 int charIdx = int(density * float(charCount - 1)); 7680 7681 // Small random variation for natural feel (+/- 1 from density index) 7682 int variation = int(charHash * 3.0) - 1; // -1, 0, or 1 7683 charIdx = clamp(charIdx + variation, 0, charCount - 1); 7684 7685 // ----------------------------------------------------------------------- 7686 // Render 5x5 bitmap pixel 7687 // ----------------------------------------------------------------------- 7688 float pixel = getFireCharPixel(charIdx, cellUV, u_charSet); 7689 7690 // ----------------------------------------------------------------------- 7691 // Color composition: light background, dark ink 7692 // ----------------------------------------------------------------------- 7693 7694 // Background color â solid or gradient mode 7695 float gradientT = dot(cellCenter - 0.5, dir) + 0.5; 7696 gradientT = clamp(gradientT, 0.0, 1.0); 7697 vec3 bgColor = (u_bgMode == 1) 7698 ? mixColors(u_colors, u_colorPositions, u_colorCount, gradientT) 7699 : u_bgColorRGB; 7700 7701 // Ink color â user-chosen inkColor as base, with optional gradient tint 7702 vec3 darkInk = u_inkColorRGB; 7703 // Gradient-sampled ink for color variation across the canvas 7704 vec3 gradientInk = mixColors(u_colors, u_colorPositions, u_colorCount, gradientT); 7705 vec3 inkColor = mix(darkInk, gradientInk, u_colorInfluence); 7706 7707 // Final composition: mix background toward ink based on pixel * density 7708 vec3 color = mix(bgColor, inkColor, pixel * density); 7709 7710 // ----------------------------------------------------------------------- 7711 // Grain 7712 // ----------------------------------------------------------------------- 7713 color += grain(uv, time, u_grain); 7714 7715 // ----------------------------------------------------------------------- 7716 // Self-blend 7717 // ----------------------------------------------------------------------- 7718 if (u_blendMode > 0) { 7719 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, time, u_blendAnimSpeed) : u_blendRotation; 7720 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, time, u_blendAnimSpeed) : u_blendOffset; 7721 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, time, u_blendAnimSpeed) : u_blendIntensity; 7722 bIntensity = noiseModulatedIntensity(bIntensity, uv, time, u_blendNoiseMask, u_blendNoiseScale); 7723 bIntensity = applyBlendFalloff(bIntensity, baseT, u_blendFalloff); 7724 float tB = blendLayerT(uv, baseT, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 7725 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 7726 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 7727 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 7728 float tB2 = blendLayerT(uv, baseT, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 7729 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 7730 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 7731 } 7732 } 7733 7734 // ----------------------------------------------------------------------- 7735 // Final output 7736 // ----------------------------------------------------------------------- 7737 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 7738} 7739`,E=`#version 300 es 7740precision highp float; 7741 7742in vec2 vUv; 7743out vec4 fragColor; 7744 7745uniform float u_time; 7746uniform float u_speed; 7747uniform vec3 u_colors[12]; 7748uniform float u_colorPositions[12]; 7749uniform int u_colorCount; 7750uniform float u_direction; 7751uniform float u_grain; 7752uniform vec2 u_resolution; 7753 7754// Blend uniforms 7755uniform int u_blendMode; 7756uniform float u_blendIntensity; 7757uniform float u_blendOffset; 7758uniform float u_blendRotation; 7759uniform float u_blendScale; 7760uniform int u_blendAnimRotation; 7761uniform int u_blendAnimIntensity; 7762uniform int u_blendAnimOffset; 7763uniform float u_blendAnimSpeed; 7764uniform float u_blendNoiseMask; 7765uniform float u_blendNoiseScale; 7766uniform float u_blendFalloff; 7767uniform int u_blendDualLayer; 7768uniform int u_blendMode2; 7769uniform float u_blendIntensity2; 7770uniform float u_blendOffset2; 7771uniform float u_blendRotation2; 7772uniform float u_blendScale2; 7773 7774__COMMON__ 7775 7776// Hash functions for particle positions 7777float hash11(float p) { 7778 p = fract(p * 0.1031); 7779 p *= p + 33.33; 7780 p *= p + p; 7781 return fract(p); 7782} 7783 7784vec2 hash21(float p) { 7785 vec3 p3 = fract(vec3(p) * vec3(0.1031, 0.1030, 0.0973)); 7786 p3 += dot(p3, p3.yzx + 33.33); 7787 return fract((p3.xx + p3.yz) * p3.zy); 7788} 7789 7790// Curl noise: rotate gradient of scalar noise by 90 degrees 7791vec2 curlNoise(vec2 p, float t) { 7792 float eps = 0.01; 7793 float nx = snoise(vec2(p.x + eps, p.y) + t * 0.1); 7794 float ny = snoise(vec2(p.x, p.y + eps) + t * 0.1); 7795 float n0 = snoise(p + t * 0.1); 7796 // Curl = (dN/dy, -dN/dx) 7797 float dNdx = (nx - n0) / eps; 7798 float dNdy = (ny - n0) / eps; 7799 return vec2(dNdy, -dNdx) * 0.15; 7800} 7801 7802void main() { 7803 vec2 uv = vUv; 7804 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 7805 uv = applyMouseWarp(uv, aspect); 7806 float t = u_time * u_speed; 7807 7808 vec2 aspectUv = vec2(uv.x * aspect, uv.y); 7809
7810 // Dark tinted background from gradient 7811 float dirAngle = radians(u_direction); 7812 vec2 dir = vec2(cos(dirAngle), sin(dirAngle)); 7813 float baseT = dot(uv - 0.5, dir) + 0.5; 7814 7815 float imgLum = imageLuminance(uv, aspect); 7816 if (imgLum >= 0.0) baseT = mix(baseT, imgLum, u_imageIntensity); 7817 7818 vec3 bgColor = mixColors(u_colors, u_colorPositions, u_colorCount, baseT); 7819 bgColor *= 0.08; 7820 7821 // Accumulate particle glow 7822 vec3 particleAccum = vec3(0.0); 7823 float totalGlow = 0.0; 7824 7825 const int PARTICLE_COUNT = 300; 7826 for (int i = 0; i < PARTICLE_COUNT; i++) { 7827 float fi = float(i); 7828 7829 // Base position from hash 7830 vec2 basePos = hash21(fi * 7.23 + 1.7); 7831 7832 // Animate along curl noise field 7833 vec2 pos = basePos; 7834 // Accumulate curl displacement over multiple steps for smoother trails 7835 vec2 curl1 = curlNoise(pos * 3.0, t * 0.4 + fi * 0.01); 7836 vec2 curl2 = curlNoise((pos + curl1) * 3.0, t * 0.4 + fi * 0.01 + 10.0); 7837 pos += curl1 + curl2 * 0.5; 7838 7839 // Wrap positions 7840 pos = fract(pos); 7841 7842 // Aspect correct for distance calc 7843 vec2 pAspect = vec2(pos.x * aspect, pos.y); 7844 float d = distance(aspectUv, pAspect); 7845 7846 // Particle size varies per particle 7847 float size = mix(0.006, 0.018, hash11(fi * 3.14)); 7848 7849 // Soft gaussian dot 7850 float glow = exp(-d * d / (size * size)); 7851 7852 // Fade particles based on curl speed for trailing effect 7853 float speed = length(curl1) * 8.0; 7854 float trail = 0.6 + 0.4 * clamp(speed, 0.0, 1.0); 7855 glow *= trail; 7856 7857 // Per-particle palette color 7858 float colorT = fract(fi / float(PARTICLE_COUNT) + t * 0.05); 7859 vec3 pColor = mixColors(u_colors, u_colorPositions, u_colorCount, colorT); 7860 pColor = max(pColor, vec3(0.12)); 7861 7862 particleAccum += pColor * glow; 7863 totalGlow += glow; 7864 } 7865 7866 // Soft background glow from nearby particle density 7867 float densityGlow = min(totalGlow, 3.0) * 0.05; 7868 vec3 densityColor = mixColors(u_colors, u_colorPositions, u_colorCount, baseT); 7869 7870 // Compose 7871 vec3 color = bgColor; 7872 color += densityColor * densityGlow; 7873 color += particleAccum * 1.8; 7874 7875 color += grain(uv, t, u_grain); 7876 7877 // Self-blend 7878 if (u_blendMode > 0) { 7879 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, t, u_blendAnimSpeed) : u_blendRotation; 7880 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, t, u_blendAnimSpeed) : u_blendOffset; 7881 float bIntensity = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, t, u_blendAnimSpeed) : u_blendIntensity; 7882 bIntensity = noiseModulatedIntensity(bIntensity, uv, t, u_blendNoiseMask, u_blendNoiseScale); 7883 bIntensity = applyBlendFalloff(bIntensity, baseT, u_blendFalloff); 7884 float tB = blendLayerT(uv, baseT, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 7885 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 7886 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity); 7887 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 7888 float tB2 = blendLayerT(uv, baseT, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 7889 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 7890 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 7891 } 7892 } 7893 7894 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 7895} 7896`,W=`#version 300 es 7897precision highp float; 7898 7899in vec2 vUv; 7900out vec4 fragColor; 7901 7902uniform float u_time; 7903uniform float u_speed; 7904uniform vec3 u_colors[12]; 7905uniform float u_colorPositions[12]; 7906uniform int u_colorCount; 7907uniform float u_direction; 7908uniform float u_grain; 7909uniform vec2 u_resolution; 7910 7911// Blend uniforms 7912uniform int u_blendMode; 7913uniform float u_blendIntensity; 7914uniform float u_blendOffset; 7915uniform float u_blendRotation; 7916uniform float u_blendScale; 7917uniform int u_blendAnimRotation; 7918uniform int u_blendAnimIntensity; 7919uniform int u_blendAnimOffset; 7920uniform float u_blendAnimSpeed; 7921uniform float u_blendNoiseMask; 7922uniform float u_blendNoiseScale; 7923uniform float u_blendFalloff; 7924uniform int u_blendDualLayer; 7925uniform int u_blendMode2; 7926uniform float u_blendIntensity2; 7927uniform float u_blendOffset2; 7928uniform float u_blendRotation2; 7929uniform float u_blendScale2; 7930 7931__COMMON__ 7932 7933// Deterministic hash 7934float hash11(float p) { 7935 p = fract(p * 0.1031); 7936 p *= p + 33.33; 7937 p *= p + p; 7938 return fract(p); 7939} 7940 7941vec2 hash21(float p) { 7942 vec3 p3 = fract(vec3(p) * vec3(0.1031, 0.1030, 0.0973)); 7943 p3 += dot(p3, p3.yzx + 33.33); 7944 return fract((p3.xx + p3.yz) * p3.zy); 7945} 7946 7947// Bokeh circle: soft fill with brighter ring edge 7948float bokehCircle(float dist, float radius, float softness) { 7949 // Soft interior 7950 float inner = smoothstep(radius, radius * (1.0 - softness), dist); 7951 // Bright ring near edge 7952 float ring = smoothstep(radius * 1.05, radius, dist) * 7953 smoothstep(radius * 0.75, radius * 0.92, dist); 7954 return inner * 0.5 + ring * 0.7; 7955} 7956 7957void main() { 7958 vec2 uv = vUv; 7959 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 7960 uv = applyMouseWarp(uv, aspect); 7961 float t = u_time * u_speed; 7962 7963 vec2 aspectUv = vec2(uv.x * aspect, uv.y); 7964
7965 // Background: warm-tinted gradient 7966 float dirAngle = radians(u_direction); 7967 vec2 dir = vec2(cos(dirAngle), sin(dirAngle)); 7968 float baseT = dot(uv - 0.5, dir) + 0.5; 7969 7970 float imgLum = imageLuminance(uv, aspect); 7971 if (imgLum >= 0.0) baseT = mix(baseT, imgLum, u_imageIntensity); 7972 7973 vec3 bgColor = mixColors(u_colors, u_colorPositions, u_colorCount, baseT); 7974 bgColor *= 0.15; 7975 7976 vec3 colorAccum = bgColor; 7977 7978 // 3 depth layers: back (0) to front (2) 7979 for (int layer = 0; layer < 3; layer++) { 7980 float fl = float(layer); 7981 float depth = 1.0 - fl * 0.35; // 1.0, 0.65, 0.3 7982 7983 // Deeper layers: softer, larger, more transparent 7984 float baseRadius = mix(0.08, 0.03, fl / 2.0); 7985 float softness = mix(0.7, 0.3, fl / 2.0); 7986 float opacity = mix(0.25, 0.6, fl / 2.0); 7987 int count = int(mix(35.0, 50.0, fl / 2.0)); 7988 7989 // Parallax drift â each layer moves at different speed 7990 vec2 drift = vec2( 7991 sin(t * 0.15 * depth + fl * 2.0) * 0.08, 7992 cos(t * 0.12 * depth + fl * 1.5) * 0.06 7993 ) * depth; 7994 7995 for (int i = 0; i < 50; i++) { 7996 if (i >= count) break; 7997 float fi = float(i); 7998 float seed = fi * 13.73 + fl * 100.0; 7999 8000 // Random position 8001 vec2 pos = hash21(seed); 8002 pos += drift; 8003 pos = fract(pos); 8004 8005 // Size variation per circle 8006 float sizeVar = 0.6 + 0.8 * hash11(seed + 7.0); 8007 float radius = baseRadius * sizeVar; 8008 8009 vec2 pAspect = vec2(pos.x * aspect, pos.y); 8010 float d = distance(aspectUv, pAspect); 8011 8012 float b = bokehCircle(d, radius, softness); 8013 8014 // Color from palette with warm shift 8015 float colorT = fract(hash11(seed + 3.0) + fl * 0.15); 8016 vec3 circleColor = mixColors(u_colors, u_colorPositions, u_colorCount, colorT); 8017 // Warm tinting â push slightly toward amber 8018 circleColor = mix(circleColor, circleColor * vec3(1.1, 1.0, 0.85), 0.3); 8019 circleColor = max(circleColor, vec3(0.08)); 8020 8021 colorAccum += circleColor * b * opacity; 8022 } 8023 } 8024 8025 vec3 color = colorAccum; 8026 8027 color += grain(uv, t, u_grain); 8028 8029 // Self-blend 8030 if (u_blendMode > 0) { 8031 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, t, u_blendAnimSpeed) : u_blendRotation; 8032 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, t, u_blendAnimSpeed) : u_blendOffset; 8033 float bIntensity2 = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, t, u_blendAnimSpeed) : u_blendIntensity; 8034 bIntensity2 = noiseModulatedIntensity(bIntensity2, uv, t, u_blendNoiseMask, u_blendNoiseScale); 8035 bIntensity2 = applyBlendFalloff(bIntensity2, baseT, u_blendFalloff); 8036 float tB = blendLayerT(uv, baseT, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 8037 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 8038 color = applyBlendMode(u_blendMode, color, blendCol, bIntensity2); 8039 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 8040 float tB2 = blendLayerT(uv, baseT, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 8041 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 8042 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 8043 } 8044 } 8045 8046 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 8047} 8048`,V=`#version 300 es 8049precision highp float; 8050 8051in vec2 vUv; 8052out vec4 fragColor; 8053 8054uniform float u_time; 8055uniform float u_speed; 8056uniform vec3 u_colors[12]; 8057uniform float u_colorPositions[12]; 8058uniform int u_colorCount; 8059uniform float u_direction; 8060uniform float u_grain; 8061uniform vec2 u_resolution; 8062 8063// Blend uniforms 8064uniform int u_blendMode; 8065uniform float u_blendIntensity; 8066uniform float u_blendOffset; 8067uniform float u_blendRotation; 8068uniform float u_blendScale; 8069uniform int u_blendAnimRotation; 8070uniform int u_blendAnimIntensity; 8071uniform int u_blendAnimOffset; 8072uniform float u_blendAnimSpeed; 8073uniform float u_blendNoiseMask; 8074uniform float u_blendNoiseScale; 8075uniform float u_blendFalloff; 8076uniform int u_blendDualLayer; 8077uniform int u_blendMode2; 8078uniform float u_blendIntensity2; 8079uniform float u_blendOffset2; 8080uniform float u_blendRotation2; 8081uniform float u_blendScale2; 8082 8083__COMMON__ 8084 8085float hash11(float p) { 8086 p = fract(p * 0.1031); 8087 p *= p + 33.33; 8088 p *= p + p; 8089 return fract(p); 8090} 8091 8092vec2 hash22(vec2 p) { 8093 vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973)); 8094 p3 += dot(p3, p3.yzx + 33.33); 8095 return fract((p3.xx + p3.yz) * p3.zy); 8096} 8097 8098// 4-point star shape via polar distance 8099float starShape(vec2 p, float size, int points) { 8100 float angle = atan(p.y, p.x); 8101 float r = length(p); 8102 float fp = float(points); 8103 // Modulate radius: peaks at each arm, valleys in between 8104 float star = cos(angle * fp) * 0.4 + 0.6;
8105 // Additional thin cross spikes 8106 float cross = pow(abs(cos(angle * fp * 0.5)), 16.0) * 0.5; 8107 float shape = r / (size * (star + cross)); 8108 return shape; 8109} 8110 8111void main() { 8112 vec2 uv = vUv; 8113 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 8114 uv = applyMouseWarp(uv, aspect); 8115 float t = u_time * u_speed; 8116 8117 vec2 aspectUv = vec2(uv.x * aspect, uv.y); 8118 8119 // Dark background with subtle gradient tint 8120 float dirAngle = radians(u_direction); 8121 vec2 dir = vec2(cos(dirAngle), sin(dirAngle)); 8122 float baseT = dot(uv - 0.5, dir) + 0.5; 8123 8124 float imgLum = imageLuminance(uv, aspect); 8125 if (imgLum >= 0.0) baseT = mix(baseT, imgLum, u_imageIntensity); 8126 8127 vec3 bgColor = mixColors(u_colors, u_colorPositions, u_colorCount, baseT); 8128 bgColor *= 0.06; 8129 8130 vec3 color = bgColor; 8131 8132 // Grid-based particle placement for ~150 stars 8133 const float GRID = 12.0; 8134 for (float gy = 0.0; gy < GRID; gy++) { 8135 for (float gx = 0.0; gx < GRID; gx++) { 8136 vec2 cell = vec2(gx, gy); 8137 vec2 cellHash = hash22(cell + 0.5); 8138 8139 // Skip ~15% of cells for irregular distribution 8140 if (cellHash.x < 0.15) continue; 8141 8142 // Particle position within cell 8143 vec2 jitter = hash22(cell * 17.3 + 3.7); 8144 vec2 starPos = (cell + 0.15 + jitter * 0.7) / GRID; 8145 8146 vec2 pAspect = vec2(starPos.x * aspect, starPos.y); 8147 vec2 delta = aspectUv - pAspect; 8148 8149 float seed = cell.x * GRID + cell.y; 8150 8151 // Varied size 8152 float size = mix(0.005, 0.022, hash11(seed * 5.17)); 8153 8154 // Star shape distance 8155 float starDist = starShape(delta, size, 4); 8156 8157 // Core glow (gaussian) 8158 float coreGlow = exp(-starDist * starDist * 8.0); 8159 8160 // Sharp star rays 8161 float rays = max(1.0 - starDist, 0.0); 8162 rays = pow(rays, 3.0); 8163 8164 float brightness = coreGlow * 0.8 + rays * 0.6; 8165 8166 // Per-star twinkle 8167 float twinkleSpeed = mix(1.5, 4.0, hash11(seed * 2.31)); 8168 float twinklePhase = hash11(seed * 8.93) * 6.283; 8169 float twinkle = sin(t * twinkleSpeed + twinklePhase) * 0.5 + 0.5; 8170 // Sharpen twinkle: occasional bright flashes 8171 twinkle = pow(twinkle, 2.0); 8172 // Keep minimum brightness so stars don't fully vanish 8173 twinkle = 0.15 + 0.85 * twinkle; 8174 8175 brightness *= twinkle; 8176 8177 // Color from palette 8178 float colorT = hash11(seed * 3.71); 8179 vec3 starColor = mixColors(u_colors, u_colorPositions, u_colorCount, colorT); 8180 starColor = max(starColor, vec3(0.2)); 8181 // Push bright stars toward white 8182 starColor = mix(starColor, vec3(1.0), brightness * 0.4); 8183 8184 color += starColor * brightness; 8185 } 8186 } 8187 8188 color += grain(uv, t, u_grain); 8189 8190 // Self-blend 8191 if (u_blendMode > 0) { 8192 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, t, u_blendAnimSpeed) : u_blendRotation; 8193 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, t, u_blendAnimSpeed) : u_blendOffset; 8194 float bInt = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, t, u_blendAnimSpeed) : u_blendIntensity; 8195 bInt = noiseModulatedIntensity(bInt, uv, t, u_blendNoiseMask, u_blendNoiseScale); 8196 bInt = applyBlendFalloff(bInt, baseT, u_blendFalloff); 8197 float tB = blendLayerT(uv, baseT, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 8198 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 8199 color = applyBlendMode(u_blendMode, color, blendCol, bInt); 8200 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 8201 float tB2 = blendLayerT(uv, baseT, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 8202 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 8203 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 8204 } 8205 } 8206 8207 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 8208} 8209`,X=`#version 300 es 8210precision highp float; 8211 8212in vec2 vUv; 8213out vec4 fragColor; 8214 8215uniform float u_time; 8216uniform float u_speed; 8217uniform vec3 u_colors[12]; 8218uniform float u_colorPositions[12]; 8219uniform int u_colorCount; 8220uniform float u_direction; 8221uniform float u_grain; 8222uniform vec2 u_resolution; 8223 8224// Blend uniforms 8225uniform int u_blendMode; 8226uniform float u_blendIntensity; 8227uniform float u_blendOffset; 8228uniform float u_blendRotation; 8229uniform float u_blendScale; 8230uniform int u_blendAnimRotation; 8231uniform int u_blendAnimIntensity; 8232uniform int u_blendAnimOffset; 8233uniform float u_blendAnimSpeed; 8234uniform float u_blendNoiseMask; 8235uniform float u_blendNoiseScale; 8236uniform float u_blendFalloff; 8237uniform int u_blendDualLayer; 8238uniform int u_blendMode2; 8239uniform float u_blendIntensity2; 8240uniform float u_blendOffset2; 8241uniform float u_blendRotation2; 8242uniform float u_blendScale2; 8243 8244__COMMON__ 8245 8246float hash11(float p) { 8247 p = fract(p * 0.1031); 8248 p *= p + 33.33; 8249 p *= p + p; 8250 return fract(p); 8251} 8252 8253// Rain streak: elongated soft capsule along fall direction 8254float rainStreak(vec2 uv, vec2 pos, float streakLen, float thickness, float windAngle) { 8255 vec2 delta = uv - pos; 8256 // Rotate into streak-local space (aligned with fall direction + wind) 8257 float c = cos(windAngle); 8258 float s = sin(windAngle); 8259 vec2 local = vec2(delta.x * c + delta.y * s, -delta.x * s + delta.y * c); 8260 8261 // Capsule SDF: clamp along streak length 8262 float halfLen = streakLen * 0.5; 8263 local.y = clamp(local.y, -halfLen, halfLen); 8264 vec2 nearest = vec2(0.0, local.y); 8265 float d = distance(vec2(delta.x * c + delta.y * s, -delta.x * s + delta.y * c), nearest); 8266 8267 // Motion blur: fade along streak length (brighter at head) 8268 float along = (-delta.x * s + delta.y * c); 8269 float headFade = smoothstep(-halfLen, halfLen * 0.3, along); 8270 8271 return exp(-d * d / (thickness * thickness)) * headFade; 8272} 8273 8274void main() { 8275 vec2 uv = vUv; 8276 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 8277 uv = applyMouseWarp(uv, aspect); 8278 float t = u_time * u_speed; 8279 8280 vec2 aspectUv = vec2(uv.x * aspect, uv.y); 8281
8282 // Background: dark with gradient tint 8283 float dirAngle = radians(u_direction); 8284 vec2 dir = vec2(cos(dirAngle), sin(dirAngle)); 8285 float baseT = dot(uv - 0.5, dir) + 0.5; 8286 8287 float imgLum = imageLuminance(uv, aspect); 8288 if (imgLum >= 0.0) baseT = mix(baseT, imgLum, u_imageIntensity); 8289 8290 vec3 bgColor = mixColors(u_colors, u_colorPositions, u_colorCount, baseT); 8291 bgColor *= 0.1; 8292 8293 // Slight wind angle (radians from vertical) 8294 float windAngle = 0.12 + sin(t * 0.2) * 0.04; 8295 8296 vec3 rainAccum = vec3(0.0); 8297 8298 // Multiple rain columns with different speeds 8299 const int COLUMNS = 30; 8300 const int DROPS_PER_COL = 6; 8301 8302 for (int col = 0; col < COLUMNS; col++) { 8303 float fc = float(col); 8304 float colSeed = fc * 7.31; 8305 8306 // Column x position 8307 float colX = hash11(colSeed) * aspect; 8308 // Slight x jitter per column 8309 colX += sin(t * 0.3 + fc * 2.0) * 0.005; 8310 8311 // Depth layer (affects size, speed, brightness) 8312 float depth = hash11(colSeed + 1.0); 8313 float fallSpeed = mix(0.3, 0.8, depth); 8314 float streakLen = mix(0.03, 0.10, depth); 8315 float thickness = mix(0.001, 0.004, depth); 8316 float brightness = mix(0.3, 0.8, depth); 8317 8318 for (int drop = 0; drop < DROPS_PER_COL; drop++) { 8319 float fd = float(drop); 8320 float dropSeed = colSeed + fd * 17.0; 8321 8322 // Stagger drops in time 8323 float phase = hash11(dropSeed) * 6.0; 8324 float y = fract(phase - t * fallSpeed); 8325 // Slight x variation per drop 8326 float dropX = colX + hash11(dropSeed + 5.0) * 0.01; 8327 8328 vec2 dropPos = vec2(dropX, y); 8329 float streak = rainStreak(aspectUv, dropPos, streakLen, thickness, windAngle); 8330 8331 // Color from palette 8332 float colorT = hash11(dropSeed + 3.0); 8333 vec3 dropColor = mixColors(u_colors, u_colorPositions, u_colorCount, colorT); 8334 dropColor = max(dropColor, vec3(0.15)); 8335 // Push bright drops toward white for glassy look 8336 dropColor = mix(dropColor, vec3(0.8, 0.85, 1.0), 0.3); 8337 8338 rainAccum += dropColor * streak * brightness; 8339 } 8340 } 8341 8342 // Edge fade at top and bottom 8343 float edgeFade = smoothstep(0.0, 0.1, uv.y) * smoothstep(1.0, 0.85, uv.y); 8344 8345 vec3 color = bgColor; 8346 color += rainAccum * edgeFade * 2.0; 8347 8348 // Subtle ambient mist from palette 8349 float mist = snoise(vec2(uv.x * 3.0, uv.y * 1.5 - t * 0.05)) * 0.5 + 0.5; 8350 vec3 mistColor = mixColors(u_colors, u_colorPositions, u_colorCount, baseT); 8351 color += mistColor * mist * 0.03; 8352 8353 color += grain(uv, t, u_grain); 8354 8355 // Self-blend 8356 if (u_blendMode > 0) { 8357 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, t, u_blendAnimSpeed) : u_blendRotation; 8358 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, t, u_blendAnimSpeed) : u_blendOffset; 8359 float bInt = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, t, u_blendAnimSpeed) : u_blendIntensity; 8360 bInt = noiseModulatedIntensity(bInt, uv, t, u_blendNoiseMask, u_blendNoiseScale); 8361 bInt = applyBlendFalloff(bInt, baseT, u_blendFalloff); 8362 float tB = blendLayerT(uv, baseT, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 8363 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 8364 color = applyBlendMode(u_blendMode, color, blendCol, bInt); 8365 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 8366 float tB2 = blendLayerT(uv, baseT, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 8367 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 8368 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 8369 } 8370 } 8371 8372 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 8373} 8374`,Y=`#version 300 es 8375precision highp float; 8376 8377in vec2 vUv; 8378out vec4 fragColor; 8379 8380uniform float u_time; 8381uniform float u_speed; 8382uniform vec3 u_colors[12]; 8383uniform float u_colorPositions[12]; 8384uniform int u_colorCount; 8385uniform float u_direction; 8386uniform float u_grain; 8387uniform vec2 u_resolution; 8388 8389// Blend uniforms 8390uniform int u_blendMode; 8391uniform float u_blendIntensity; 8392uniform float u_blendOffset; 8393uniform float u_blendRotation; 8394uniform float u_blendScale; 8395uniform int u_blendAnimRotation; 8396uniform int u_blendAnimIntensity; 8397uniform int u_blendAnimOffset; 8398uniform float u_blendAnimSpeed; 8399uniform float u_blendNoiseMask; 8400uniform float u_blendNoiseScale; 8401uniform float u_blendFalloff; 8402uniform int u_blendDualLayer; 8403uniform int u_blendMode2; 8404uniform float u_blendIntensity2; 8405uniform float u_blendOffset2; 8406uniform float u_blendRotation2; 8407uniform float u_blendScale2; 8408 8409__COMMON__ 8410 8411float hash11(float p) { 8412 p = fract(p * 0.1031); 8413 p *= p + 33.33; 8414 p *= p + p; 8415 return fract(p); 8416} 8417 8418vec2 hash21(float p) { 8419 vec3 p3 = fract(vec3(p) * vec3(0.1031, 0.1030, 0.0973)); 8420 p3 += dot(p3, p3.yzx + 33.33); 8421 return fract((p3.xx + p3.yz) * p3.zy); 8422} 8423 8424// Rotate a 2D point 8425vec2 rot2d(vec2 p, float a) { 8426 float c = cos(a); 8427 float s = sin(a); 8428 return vec2(p.x * c - p.y * s, p.x * s + p.y * c); 8429} 8430 8431// SDF for a rectangle 8432float sdBox(vec2 p, vec2 halfSize) { 8433 vec2 d = abs(p) - halfSize; 8434 return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); 8435} 8436 8437// SDF for a diamond (rotated square) 8438float sdDiamond(vec2 p, float size) { 8439 p = abs(p); 8440 return (p.x + p.y - size) * 0.707; 8441} 8442 8443void main() { 8444 vec2 uv = vUv; 8445 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 8446 uv = applyMouseWarp(uv, aspect); 8447 float t = u_time * u_speed; 8448 8449 vec2 aspectUv = vec2(uv.x * aspect, uv.y); 8450 8451 // Light-ish background from gradient 8452 float dirAngle = radians(u_direction); 8453 vec2 dir = vec2(cos(dirAngle), sin(dirAngle)); 8454 float baseT = dot(uv - 0.5, dir) + 0.5; 8455 8456 float imgLum = imageLuminance(uv, aspect); 8457 if (imgLum >= 0.0) baseT = mix(baseT, imgLum, u_imageIntensity); 8458 8459 vec3 bgColor = mixColors(u_colors, u_colorPositions, u_colorCount, baseT); 8460 bgColor *= 0.12; 8461 8462 vec3 confettiAccum = vec3(0.0); 8463 8464 const int PIECE_COUNT = 120; 8465 8466 for (int i = 0; i < PIECE_COUNT; i++) { 8467 float fi = float(i); 8468 float seed = fi * 11.37; 8469 8470 // Random initial position
8471 vec2 initPos = hash21(seed); 8472 8473 // Gravity fall: different speeds per piece 8474 float fallSpeed = mix(0.15, 0.45, hash11(seed + 1.0)); 8475 float sway = sin(t * mix(1.0, 3.0, hash11(seed + 2.0)) + fi * 3.0) * 0.04; 8476 8477 // Current position (wrapping vertically) 8478 vec2 pos; 8479 pos.x = initPos.x * aspect + sway; 8480 pos.y = fract(initPos.y + 0.5 - t * fallSpeed); 8481 8482 vec2 delta = aspectUv - pos; 8483 8484 // Tumbling rotation 8485 float tumbleSpeed = mix(2.0, 6.0, hash11(seed + 3.0)); 8486 float tumblePhase = hash11(seed + 4.0) * 6.283; 8487 float angle = t * tumbleSpeed + tumblePhase; 8488 8489 vec2 rotDelta = rot2d(delta, angle); 8490 8491 // Shape type: 0=square, 1=diamond, 2=rectangle 8492 float shapeType = hash11(seed + 5.0); 8493 float size = mix(0.005, 0.015, hash11(seed + 6.0)); 8494 8495 float d; 8496 if (shapeType < 0.33) { 8497 // Square 8498 d = sdBox(rotDelta, vec2(size)); 8499 } else if (shapeType < 0.66) { 8500 // Diamond 8501 d = sdDiamond(rotDelta, size * 1.4); 8502 } else { 8503 // Rectangle (elongated) 8504 d = sdBox(rotDelta, vec2(size * 0.5, size * 1.5)); 8505 } 8506 8507 // Soft edge 8508 float shape = 1.0 - smoothstep(-0.001, 0.002, d); 8509 8510 // Simulate 3D tumble: modulate brightness with sin of rotation 8511 // (as confetti rotates, it shows face vs edge) 8512 float faceBright = abs(sin(angle * 0.5)) * 0.6 + 0.4; 8513 shape *= faceBright; 8514 8515 // Color from palette 8516 float colorT = hash11(seed + 7.0); 8517 vec3 pieceColor = mixColors(u_colors, u_colorPositions, u_colorCount, colorT); 8518 pieceColor = max(pieceColor, vec3(0.15)); 8519 // Boost saturation for celebratory feel 8520 float luma = dot(pieceColor, vec3(0.299, 0.587, 0.114)); 8521 pieceColor = mix(vec3(luma), pieceColor, 1.4); 8522 8523 confettiAccum += pieceColor * shape; 8524 } 8525 8526 vec3 color = bgColor + confettiAccum * 1.5; 8527 8528 color += grain(uv, t, u_grain); 8529 8530 // Self-blend 8531 if (u_blendMode > 0) { 8532 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, t, u_blendAnimSpeed) : u_blendRotation; 8533 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, t, u_blendAnimSpeed) : u_blendOffset; 8534 float bInt = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, t, u_blendAnimSpeed) : u_blendIntensity; 8535 bInt = noiseModulatedIntensity(bInt, uv, t, u_blendNoiseMask, u_blendNoiseScale); 8536 bInt = applyBlendFalloff(bInt, baseT, u_blendFalloff); 8537 float tB = blendLayerT(uv, baseT, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 8538 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 8539 color = applyBlendMode(u_blendMode, color, blendCol, bInt); 8540 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 8541 float tB2 = blendLayerT(uv, baseT, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 8542 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 8543 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 8544 } 8545 } 8546 8547 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 8548} 8549`,j=`#version 300 es 8550precision highp float; 8551 8552in vec2 vUv; 8553out vec4 fragColor; 8554 8555uniform float u_time; 8556uniform float u_speed; 8557uniform vec3 u_colors[12]; 8558uniform float u_colorPositions[12]; 8559uniform int u_colorCount; 8560uniform float u_direction; 8561uniform float u_grain; 8562uniform vec2 u_resolution; 8563 8564// Blend uniforms 8565uniform int u_blendMode; 8566uniform float u_blendIntensity; 8567uniform float u_blendOffset; 8568uniform float u_blendRotation; 8569uniform float u_blendScale; 8570uniform int u_blendAnimRotation; 8571uniform int u_blendAnimIntensity; 8572uniform int u_blendAnimOffset; 8573uniform float u_blendAnimSpeed; 8574uniform float u_blendNoiseMask; 8575uniform float u_blendNoiseScale; 8576uniform float u_blendFalloff; 8577uniform int u_blendDualLayer; 8578uniform int u_blendMode2; 8579uniform float u_blendIntensity2; 8580uniform float u_blendOffset2; 8581uniform float u_blendRotation2; 8582uniform float u_blendScale2; 8583 8584__COMMON__ 8585 8586float hash11(float p) { 8587 p = fract(p * 0.1031); 8588 p *= p + 33.33; 8589 p *= p + p; 8590 return fract(p); 8591} 8592 8593vec2 hash22(vec2 p) { 8594 vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973)); 8595 p3 += dot(p3, p3.yzx + 33.33); 8596 return fract((p3.xx + p3.yz) * p3.zy); 8597} 8598 8599void main() { 8600 vec2 uv = vUv; 8601 float aspect = u_resolution.x / max(u_resolution.y, 1.0); 8602 uv = applyMouseWarp(uv, aspect); 8603 float t = u_time * u_speed; 8604 8605 // Center the coordinate system 8606 vec2 centered = uv - 0.5; 8607 centered.x *= aspect; 8608 8609 float r = length(centered); 8610 float theta = atan(centered.y, centered.x); 8611 8612 // Direction-based base T for blending 8613 float dirAngle = radians(u_direction); 8614 vec2 dir = vec2(cos(dirAngle), sin(dirAngle)); 8615 float baseT = dot(uv - 0.5, dir) + 0.5; 8616 8617 float imgLum = imageLuminance(uv, aspect); 8618 if (imgLum >= 0.0) baseT = mix(baseT, imgLum, u_imageIntensity); 8619 8620 // Very dark cosmic background 8621 vec3 bgColor = mixColors(u_colors, u_colorPositions, u_colorCount, baseT); 8622 bgColor *= 0.03; 8623 8624 // ---- Bright galaxy core ---- 8625 float coreGlow = exp(-r * r * 50.0) * 1.5; 8626 float coreHalo = exp(-r * r * 8.0) * 0.3; 8627 vec3 coreColor = mixColors(u_colors, u_colorPositions, u_colorCount, 0.5); 8628 coreColor = max(coreColor, vec3(0.4)); 8629 // Push core toward warm white 8630 coreColor = mix(coreColor, vec3(1.0, 0.95, 0.85), 0.5); 8631 8632 // ---- Spiral arms ---- 8633 // Differential rotation: inner regions rotate faster 8634 float rotSpeed = t * 0.2; 8635 float diffTheta = theta + rotSpeed / (r + 0.15); 8636 8637 // Logarithmic spiral: angle = a * ln(r) + offset 8638 float spiralTightness = 3.0; 8639 8640 float armAccum = 0.0; 8641 vec3 armColorAccum = vec3(0.0); 8642 8643 // 3 spiral arms 8644 for (int arm = 0; arm < 3; arm++) { 8645 float armOffset = float(arm) * 6.283 / 3.0; 8646 8647 // How close this pixel is to the spiral arm 8648 float spiralAngle = spiralTightness * log(max(r, 0.01)) + armOffset; 8649 float angleDiff = diffTheta - spiralAngle; 8650 // Wrap to [-PI, PI] 8651 angleDiff = mod(angleDiff + 3.14159, 6.28318) - 3.14159; 8652 8653 // Arm width (wider at larger radius) 8654 float armWidth = mix(0.3, 0.8, clamp(r * 2.0, 0.0, 1.0)); 8655 float armBright = exp(-angleDiff * angleDiff / (armWidth * armWidth)); 8656 8657 // Fade arm at very large and very small radii 8658 armBright *= smoothstep(0.02, 0.08, r) * smoothstep(0.55, 0.3, r); 8659 8660 armAccum += armBright; 8661 8662 // Color varies along arm and between arms 8663 float armT = fract(r * 2.0 + float(arm) * 0.33); 8664 vec3 armCol = mixColors(u_colors, u_colorPositions, u_colorCount, armT); 8665 armColorAccum += armCol * armBright; 8666 } 8667 8668 armAccum = min(armAccum, 2.0); 8669 armColorAccum = min(armColorAccum, vec3(2.0)); 8670 8671 // ---- Star particles along arms ---- 8672 // Grid-based hash for star placement 8673 vec3 starAccum = vec3(0.0); 8674 8675 const float STAR_GRID = 24.0; 8676 for (float sy = 0.0; sy < STAR_GRID; sy++) { 8677 for (float sx = 0.0; sx < STAR_GRID; sx++) { 8678 vec2 cell = vec2(sx, sy); 8679 vec2 cellHash = hash22(cell + 7.0); 8680 8681 // Star position in UV space 8682 vec2 starUv = (cell + cellHash) / STAR_GRID; 8683 vec2 starCentered = starUv - 0.5; 8684 starCentered.x *= aspect; 8685 8686 float starR = length(starCentered); 8687 float starTheta = atan(starCentered.y, starCentered.x); 8688 8689 // Check if star is near a spiral arm 8690 float starDiffTheta = starTheta + rotSpeed / (starR + 0.15); 8691 float nearArm = 0.0; 8692 for (int arm = 0; arm < 3; arm++) { 8693 float armOff = float(arm) * 6.283 / 3.0; 8694 float spiralA = spiralTightness * log(max(starR, 0.01)) + armOff; 8695 float aDiff = mod(starDiffTheta - spiralA + 3.14159, 6.28318) - 3.14159; 8696 float armW = mix(0.4, 1.0, clamp(starR * 2.0, 0.0, 1.0)); 8697 nearArm += exp(-aDiff * aDiff / (armW * armW)); 8698 } 8699 8700 // Star probability increases near arms 8701 float prob = mix(0.05, 0.7, min(nearArm, 1.0)); 8702 float seed = cell.x * STAR_GRID + cell.y; 8703 if (hash11(seed * 3.17) > prob) continue; 8704 8705 // Star distance from current pixel 8706 vec2 sAspect = vec2(starUv.x * aspect, starUv.y); 8707 vec2 aspectUvLocal = vec2(uv.x * aspect, uv.y); 8708 float d = distance(aspectUvLocal, sAspect); 8709 8710 // Star size 8711 float starSize = mix(0.001, 0.006, hash11(seed * 2.73)); 8712 8713 // Star glow 8714 float glow = exp(-d * d / (starSize * starSize)); 8715 8716 // Twinkle 8717 float twinkle = sin(t * mix(1.0, 3.5, hash11(seed * 4.1)) + seed * 3.0) * 0.5 + 0.5; 8718 glow *= 0.3 + 0.7 * twinkle; 8719 8720 // Star color 8721 float colorT = hash11(seed * 1.93); 8722 vec3 starCol = mixColors(u_colors, u_colorPositions, u_colorCount, colorT); 8723 starCol = max(starCol, vec3(0.3)); 8724 // Push toward blue-white for cosmic feel 8725 starCol = mix(starCol, vec3(0.8, 0.85, 1.0), 0.3); 8726 8727 starAccum += starCol * glow; 8728 } 8729 } 8730 8731 // ---- Compose ---- 8732 vec3 color = bgColor; 8733 8734 // Spiral arm nebula glow 8735 color += armColorAccum * 0.5; 8736 8737 // Core 8738 color += coreColor * (coreGlow + coreHalo); 8739 8740 // Stars 8741 color += starAccum * 1.5; 8742 8743 color += grain(uv, t, u_grain); 8744 8745 // Self-blend 8746 if (u_blendMode > 0) { 8747 float bRotation = u_blendAnimRotation > 0 ? animatedBlendRotation(u_blendRotation, t, u_blendAnimSpeed) : u_blendRotation; 8748 float bOffset = u_blendAnimOffset > 0 ? animatedBlendOffset(u_blendOffset, t, u_blendAnimSpeed) : u_blendOffset; 8749 float bInt = u_blendAnimIntensity > 0 ? animatedBlendIntensity(u_blendIntensity, t, u_blendAnimSpeed) : u_blendIntensity; 8750 bInt = noiseModulatedIntensity(bInt, uv, t, u_blendNoiseMask, u_blendNoiseScale); 8751 bInt = applyBlendFalloff(bInt, baseT, u_blendFalloff); 8752 float tB = blendLayerT(uv, baseT, u_resolution, u_direction, bOffset, bRotation, u_blendScale); 8753 vec3 blendCol = mixColors(u_colors, u_colorPositions, u_colorCount, tB); 8754 color = applyBlendMode(u_blendMode, color, blendCol, bInt); 8755 if (u_blendDualLayer > 0 && u_blendMode2 > 0) { 8756 float tB2 = blendLayerT(uv, baseT, u_resolution, u_direction, u_blendOffset2, u_blendRotation2, u_blendScale2); 8757 vec3 blendCol2 = mixColors(u_colors, u_colorPositions, u_colorCount, tB2); 8758 color = applyBlendMode(u_blendMode2, color, blendCol2, u_blendIntensity2); 8759 } 8760 } 8761 8762 fragColor = outputColor(color, gl_FragCoord.xy, 1.0); 8763} 8764`,K={simple:o,noise:t,aurora:i.AURORA_FRAGMENT,radial:n,dither:l,halftone:a,ascii:r,mesh:s,cosmic:u,heightfield3d:f,isometric:c,terrainHud:d,cinematicBeam:m,fractalGlass:p,surfaces3d:v,metallic3d:b,audioReactive:g,liquidChrome:h,particleField:y,fluidSim:D,eventHorizon:k,blackHole:O.BLACK_HOLE_FRAGMENT,liquidGradient:T,prismaticGlass:P,cloud:F,swirlVortex:L,heatmap:N,liquidMetal:"#ver
8764sion 300 es\nprecision highp float;\nout vec4 fragColor;\nvoid main() { fragColor = vec4(0.0, 0.0, 0.0, 1.0); }",neonMesh:z,cosinePalette:U,additivePlasma:q,subsurfaceGlow:G,asciiArt:H,particleFlow:E,particleBokeh:W,particleSparkle:V,particleRain:X,particleConfetti:Y,particleGalaxy:j,meshGradient:"void main() { gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0); }"};e.s(["FRAGMENT_SHADERS",0,K],204776)}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.