Eigenstate Collapse - Quantum Probability Clouds

📅 April 25, 2026 🏷️ art
quantum julia-set probability-cloud psychedelic synesthesia fractal wave-function iridescent complex-numbers recursive pending-review
Generated by GridFlow AI | Tags: quantum, julia-set, probability-cloud, psychedelic, synesthesia, fractal, wave-function, iridescent, complex-numbers, recursive

💡 AI 提示词

Quantum Wave Function Collapse Probability Clouds - a psychedelic synesthesia visualization using complex number mapping with Julia set fractal per-pixel rendering, multi-layer compositing with blend modes, iridescent probability tendrils rendered with curves, cosmic dust particles, and wave function collapse ring effects on mouse click

🔧 核心算法要点

  1. Complex number mapping: Julia set iteration z=z^2+c computed per-pixel with smooth coloring via logescape algorithm for probability density visualization
  2. Multi-layer compositing: Three offscreen createGraphics buffers (fractal, glow, overlay) composited with SCREEN and ADD blend modes for luminous depth
  3. Iridescent palette generation: HSB color space with sine-wave modulation creating shifting gradients with high saturation peaks
  4. Organic probability tendrils: Recursive noise-driven bezier curves emanating from center, simulating quantum probability wave functions
  5. Wave function collapse animation: Radial ring expansion with chromatic phase offsets triggered on mouse press
  6. Volumetric nebula glow: Layered ellipses with ADD blending simulating dark energy accumulation around fractal structures
  7. Cosmic dust particles: Perlin noise-driven particle field adding depth and stellar atmosphere
  8. Dynamic parameter control: Mouse position continuously maps to Julia set c parameter; keyboard cycles presets; spacebar randomizes

🎨 原始代码

var sketch = function(p) {
  var container;
  var fractalBuffer;
  var glowBuffer;
  var overlayBuffer;
  
  var juliaC = { re: -0.7, im: 0.27 };
  var maxIterations = 120;
  var colorShift = 0;
  var timeDrift = 0;
  var palette = [];
  
  var collapseActive = false;
  var collapseProgress = 0;
  var collapseX = 0;
  var collapseY = 0;
  
  var modeIndex = 0;
  var modeCPresets = [
    { re: -0.7, im: 0.27 },
    { re: -0.8, im: 0.156 },
    { re: 0.285, im: 0.01 },
    { re: -0.745, im: 0.113 },
    { re: -0.1, im: 0.651 }
  ];
  
  p.setup = function() {
    container = document.getElementById('p5-wrapper');
    p.createCanvas(container.offsetWidth, container.offsetHeight).parent(container);
    p.colorMode(p.HSB, 360, 100, 100, 100);
    p.noStroke();
    
    fractalBuffer = p.createGraphics(p.width, p.height);
    glowBuffer = p.createGraphics(p.width, p.height);
    overlayBuffer = p.createGraphics(p.width, p.height);
    
    fractalBuffer.colorMode(p.HSB, 360, 100, 100, 100);
    glowBuffer.colorMode(p.HSB, 360, 100, 100, 100);
    overlayBuffer.colorMode(p.HSB, 360, 100, 100, 100);
    
    generatePalette();
  };
  
  function generatePalette() {
    palette = [];
    for (var i = 0; i < 256; i++) {
      var t = i / 256;
      var h = (360 + t * 720 + colorShift) % 360;
      var s = 70 + 30 * p.sin(t * p.PI * 4);
      var b = 60 + 40 * (1 - p.abs(t - 0.5) * 2);
      palette.push({ h: h, s: s, b: b });
    }
  }
  
  p.windowResized = function() {
    p.resizeCanvas(container.offsetWidth, container.offsetHeight);
    fractalBuffer.resizeCanvas(p.width, p.height);
    glowBuffer.resizeCanvas(p.width, p.height);
    overlayBuffer.resizeCanvas(p.width, p.height);
    generatePalette();
  };
  
  p.draw = function() {
    timeDrift += 0.008;
    
    var mouseNormX = p.constrain(p.mouseX / p.width, 0, 1);
    var mouseNormY = p.constrain(p.mouseY / p.height, 0, 1);
    
    if (p.mouseX > 0 && p.mouseX < p.width) {
      juliaC.re = p.lerp(-1.2, 0.3, mouseNormX) + p.sin(timeDrift * 0.3) * 0.05;
      juliaC.im = p.lerp(-0.8, 0.8, mouseNormY) + p.cos(timeDrift * 0.25) * 0.05;
    }
    
    computeJuliaFractal();
    
    renderLayers();
    
    if (collapseActive) {
      collapseProgress += 0.025;
      if (collapseProgress >= 1) {
        collapseActive = false;
        collapseProgress = 0;
      }
    }
    
    colorShift = (colorShift + 0.3) % 360;
  };
  
  function computeJuliaFractal() {
    fractalBuffer.loadPixels();
    var scale = p.min(p.width, p.height) * 0.008;
    var step = 2;
    
    for (var px = 0; px < p.width; px += step) {
      for (var py = 0; py < p.height; py += step) {
        var zRe = (px - p.width / 2) / scale;
        var zIm = (py - p.height / 2) / scale;
        var zRe2 = zRe * zRe;
        var zIm2 = zIm * zIm;
        var iteration = 0;
        
        while (iteration < maxIterations && zRe2 + zIm2 < 4) {
          zIm = 2 * zRe * zIm + juliaC.im;
          zRe = zRe2 - zIm2 + juliaC.re;
          zRe2 = zRe * zRe;
          zIm2 = zIm * zIm;
          iteration++;
        }
        
        var idx = 4 * (py * p.width + px);
        
        if (iteration >= maxIterations) {
          fractalBuffer.pixels[idx] = 0;
          fractalBuffer.pixels[idx + 1] = 0;
          fractalBuffer.pixels[idx + 2] = 5;
        } else {
          var smoothIter = iteration - p.log2(p.log2(zRe2 + zIm2)) + 4;
          var colorIdx = Math.floor(smoothIter * 3 + timeDrift * 50) % 256;
          var col = palette[colorIdx];
          
          var escapeBoost = p.map(iteration, 0, maxIterations, 1.5, 0.3);
          fractalBuffer.pixels[idx] = col.h;
          fractalBuffer.pixels[idx + 1] = col.s * escapeBoost;
          fractalBuffer.pixels[idx + 2] = col.b * (1 + escapeBoost * 0.5);
        }
        fractalBuffer.pixels[idx + 3] = 100;
      }
    }
    fractalBuffer.updatePixels();
  }
  
  function renderLayers() {
    p.background(0, 0, 3);
    
    p.fill(240, 90, 12);
    p.noStroke();
    for (var y = 0; y < p.height; y += 3) {
      var t = y / p.height;
      var h = p.lerp(240, 280, t);
      var b = p.lerp(8, 18, t);
      p.fill(h, 70, b);
      p.rect(0, y, p.width, 3);
    }
    
    glowBuffer.clear();
    glowBuffer.blendMode(p.ADD);
    
    var glowPulse = 0.5 + 0.5 * p.sin(timeDrift * 2);
    var nebulaCX = p.width * (0.5 + 0.15 * p.cos(timeDrift * 0.7));
    var nebulaCY = p.height * (0.5 + 0.15 * p.sin(timeDrift * 0.5));
    
    for (var i = 6; i >= 0; i--) {
      var layerH = (timeDrift * 30 + i * 50) % 360;
      var layerS = 60 + i * 5;
      var layerB = 30 + glowPulse * 20 - i * 3;
      var layerA = (25 - i * 2) * glowPulse;
      var layerR = 180 + i * 60 + glowPulse * 50;
      
      glowBuffer.fill(layerH, layerS, layerB, layerA);
      glowBuffer.ellipse(nebulaCX, nebulaCY, layerR, layerR * 0.85);
    }
    
    p.image(glowBuffer, 0, 0);
    
    p.blendMode(p.SCREEN);
    p.image(fractalBuffer, 0, 0);
    
    renderProbabilityTendrils();
    
    if (collapseActive) {
      renderCollapseEffect();
    }
    
    renderCosmicDust();
    
    p.blendMode(p.BLEND);
  }
  
  function renderProbabilityTendrils() {
    p.blendMode(p.ADD);
    p.strokeWeight(1.2);
    
    var tendrilCount = 14;
    
    for (var t = 0; t < tendrilCount; t++) {
      var baseAngle = (t / tendrilCount) * p.TWO_PI + timeDrift * 0.4;
      var hue = (t * 25 + timeDrift * 40) % 360;
      
      p.stroke(hue, 65, 85, 55);
      p.noFill();
      p.beginShape();
      
      var numPoints = 50;
      for (var i = 0; i <= numPoints; i++) {
        var progress = i / numPoints;
        var length = 120 + progress * 350;
        
        var noiseVal1 = p.noise(t * 0.4, progress * 2.5, timeDrift * 0.8);
        var noiseVal2 = p.noise(t * 0.4 + 50, progress * 2.5 + 20, timeDrift * 0.8);
        var angle = baseAngle + (noiseVal1 - 0.5) * 2.5;
        var wobble = p.sin(progress * 10 + timeDrift * 4 + t) * 25 * (1 - progress * 0.6);
        
        var x = p.width / 2 + p.cos(angle) * length + wobble;
        var y = p.height / 2 + p.sin(angle) * length + wobble * 0.6;
        
        if (i === 0) {
          p.curveVertex(x, y);
          p.curveVertex(x, y);
        } else if (i === numPoints) {
          p.curveVertex(x, y);
        } else {
          p.curveVertex(x, y);
        }
      }
      p.endShape();
    }
    
    for (var t = 0; t < 6; t++) {
      var baseAngle = (t / 6) * p.TWO_PI - timeDrift * 0.6;
      
      p.stroke(280 + t * 12, 45, 75, 35);
      p.beginShape();
      
      for (var i = 0; i <= 25; i++) {
        var progress = i / 25;
        var length = 60 + progress * 180;
        
        var angle = baseAngle + (p.noise(t * 0.5, progress * 4, timeDrift * 1.2) - 0.5) * 1.8;
        var harmonic = p.sin(progress * 18 + timeDrift * 6) * 12;
        
        var x = p.width / 2 + p.cos(angle) * length + harmonic;
        var y = p.height / 2 + p.sin(angle) * length + harmonic * 0.4;
        
        p.curveVertex(x, y);
      }
      p.endShape();
    }
    
    p.noStroke();
  }
  
  function renderCollapseEffect() {
    p.blendMode(p.ADD);
    p.noFill();
    
    var rings = 10;
    for (var r = 0; r < rings; r++) {
      var ringPhase = p.constrain((collapseProgress - r * 0.07) / 0.4, 0, 1);
      
      if (ringPhase > 0 && ringPhase < 1) {
        var radius = ringPhase * p.max(p.width, p.height) * 0.8;
        var alpha = (1 - ringPhase) * 180;
        var hue = (r * 35 + timeDrift * 60) % 360;
        var strokeW = 4 - r * 0.3;
        
        p.stroke(hue, 90, 100, alpha);
        p.strokeWeight(strokeW);
        p.ellipse(collapseX, collapseY, radius * 2, radius * 2);
      }
    }
    
    if (collapseProgress < 0.15) {
      var burstAlpha = (1 - collapseProgress / 0.15) * 250;
      var burstSize = 30 + collapseProgress * 600;
      
      p.noStroke();
      p.fill(50, 100, 100, burstAlpha);
      p.ellipse(collapseX, collapseY, burstSize, burstSize);
      p.fill(0, 0, 100, burstAlpha * 0.6);
      p.ellipse(collapseX, collapseY, burstSize * 0.4, burstSize * 0.4);
    }
    
    p.strokeWeight(1);
  }
  
  function renderCosmicDust() {
    p.blendMode(p.ADD);
    
    var dustCount = 60;
    for (var i = 0; i < dustCount; i++) {
      var dustX = (p.noise(i * 0.08, timeDrift * 0.3) - 0.2) * p.width * 1.4;
      var dustY = (p.noise(i * 0.08 + 70, timeDrift * 0.3) - 0.2) * p.height * 1.4;
      var dustS = 1.5 + p.noise(i * 0.15) * 4;
      var dustA = 40 + p.noise(i * 0.2 + 30) * 80;
      var dustH = (280 + i * 8 + p.sin(timeDrift + i) * 30) % 360;
      
      p.fill(dustH, 60, 100, dustA);
      p.noStroke();
      p.ellipse(dustX, dustY, dustS, dustS);
    }
    
    p.blendMode(p.BLEND);
  }
  
  p.mousePressed = function() {
    collapseActive = true;
    collapseProgress = 0;
    collapseX = p.mouseX;
    collapseY = p.mouseY;
  };
  
  p.keyPressed = function() {
    if (p.key === 'c' || p.key === 'C') {
      modeIndex = (modeIndex + 1) % modeCPresets.length;
      juliaC.re = modeCPresets[modeIndex].re;
      juliaC.im = modeCPresets[modeIndex].im;
    }
    if (p.key === 'r' || p.key === 'R') {
      colorShift = (colorShift + 60) % 360;
      generatePalette();
    }
    if (p.key === ' ') {
      juliaC.re = p.random(-1.2, 0.4);
      juliaC.im = p.random(-0.6, 0.6);
    }
  };
};
// p5 init stripped

✨ AI 艺术解读

This artwork visualizes the quantum mechanical paradox of wave function collapse - the transition from superposition of all possible states to a single observed reality. The Julia set fractal represents the probability amplitude distribution, with mouse interaction allowing the viewer to probe different eigenstates of the quantum system. The iridescent probability tendrils emanating from the center evoke the branching paths of parallel universes, while the collapse animation triggered by clicks represents the moment of observation that forces the wave function to choose a single reality. The psychedelic color palette reflects the subjective, consciousness-dependent nature of quantum measurement, transforming mathematical abstraction into a visceral, synesthetic experience that mirrors altered states of perception.

📝 补充说明

  • Performance optimization: Using step=2 for pixel-level fractal computation with interpolation gaps filled by smooth color gradients
  • Julia set c parameter bounded to meaningful regions prevents跑去 non-descript regions; time drift adds subtle animation without destabilizing
  • Blend mode discipline: BLEND for opaque layers, ADD for luminous glows, SCREEN for preserving fractal contrast against nebula
  • Color palette restraint: Despite psychedelic theme, limited to coordinated HSB ranges with controlled saturation to maintain sophistication
  • Interactivity design: Three-tier interaction - passive mouse drift (contemplative), click collapse (dramatic), keyboard reset (exploration)