Ego-Death Fractal Tunnel into the Riemann Zeta Zero

📅 April 25, 2026 🏷️ art
fractal julia-set riemann-zeta psychedelic tunnel synesthesia ego-death recursive-void pending-review
Generated by GridFlow AI | Tags: fractal, julia-set, riemann-zeta, psychedelic, tunnel, synesthesia, ego-death, recursive-void

💡 AI 提示词

Ego-Death Fractal Tunnel into the Riemann Zeta Zero - psychedelic synesthesia with deep shifting gradients and iridescent elements using complex number mapping with Julia set iterations per-pixel

🔧 核心算法要点

  1. Complex plane Julia set iteration mapping each pixel with time-evolving c parameter based on Riemann zeta approximation
  2. Approximate Riemann zeta function using Dirichlet eta series and reflection formula for critical line evaluation
  3. Multi-layer compositing with createGraphics offscreen buffers for fractal, tunnel geometry, and void layers
  4. Additive and screen blend modes for luminous iridescent glow effects impossible with single-canvas rendering
  5. Recursive void spirals using curveVertex sequences with fractal noise for organic depth
  6. Ego-death vortex spiral animation converging toward zeta zero with chromatic aberration bloom
  7. Per-pixel fractal computation with smooth iteration coloring influenced by zeta function magnitude and phase

🎨 原始代码

var sketch = function(p) {
  var fractalBuffer, tunnelGraphics, voidGraphics, bloomBuffer;
  var palette, currentPalette;
  var time = 0;
  var mode = 0;
  var paletteModes = ['psychedelic', 'alchemical', 'bismuth', 'abyssal'];
  var zoomLevel = 1;
  var mouseInfluence = { x: 0, y: 0 };
  var egoDeathActive = false;
  var egoDeathParticles = [];

  var RES = 3;

  p.setup = function() {
    var container = document.getElementById('p5-wrapper');
    p.createCanvas(container.offsetWidth, container.offsetHeight).parent(container);
    p.colorMode(p.RGB, 255, 255, 255, 255);
    p.noStroke();

    fractalBuffer = p.createGraphics(p.width, p.height);
    tunnelGraphics = p.createGraphics(p.width, p.height);
    voidGraphics = p.createGraphics(p.width, p.height);
    bloomBuffer = p.createGraphics(p.width, p.height);

    initPalette();
    fractalBuffer.pixelDensity(1);
    p.pixelDensity(1);
  };

  function initPalette() {
    var modeName = paletteModes[mode];
    if (modeName === 'psychedelic') {
      palette = [
        [20, 10, 60],
        [60, 20, 120],
        [120, 30, 180],
        [180, 60, 220],
        [220, 120, 200],
        [255, 200, 100],
        [100, 255, 200],
        [200, 255, 255]
      ];
    } else if (modeName === 'alchemical') {
      palette = [
        [10, 15, 50],
        [80, 100, 140],
        [180, 160, 80],
        [220, 200, 120],
        [100, 180, 200],
        [60, 80, 120]
      ];
    } else if (modeName === 'bismuth') {
      palette = [
        [40, 40, 60],
        [100, 120, 140],
        [160, 180, 200],
        [200, 180, 160],
        [180, 140, 100],
        [140, 100, 160],
        [200, 200, 220],
        [180, 200, 180]
      ];
    } else {
      palette = [
        [40, 5, 10],
        [80, 15, 20],
        [120, 30, 30],
        [60, 40, 30],
        [100, 50, 40],
        [30, 20, 15],
        [150, 60, 50],
        [80, 30, 25]
      ];
    }
    currentPalette = palette;
  }

  function lerpColor(c1, c2, t) {
    return [
      c1[0] + (c2[0] - c1[0]) * t,
      c1[1] + (c2[1] - c1[1]) * t,
      c1[2] + (c2[2] - c1[2]) * t
    ];
  }

  function getColorAtPosition(t) {
    var idx1 = Math.floor(t) % currentPalette.length;
    var idx2 = (idx1 + 1) % currentPalette.length;
    var f = (t % 1);
    return lerpColor(currentPalette[idx1], currentPalette[idx2], f);
  }

  function complexMul(a, b) {
    return {
      re: a.re * b.re - a.im * b.im,
      im: a.re * b.im + a.im * b.re
    };
  }

  function complexDiv(a, b) {
    var denom = b.re * b.re + b.im * b.im;
    if (denom < 1e-10) return { re: 0, im: 0 };
    return {
      re: (a.re * b.re + a.im * b.im) / denom,
      im: (a.im * b.re - a.re * b.im) / denom
    };
  }

  function complexExp(a) {
    var expReal = Math.exp(a.re);
    return {
      re: expReal * Math.cos(a.im),
      im: expReal * Math.sin(a.im)
    };
  }

  function complexLog(a) {
    return {
      re: Math.log(Math.sqrt(a.re * a.re + a.im * a.im)),
      im: Math.atan2(a.im, a.re)
    };
  }

  function complexPow(base, exp) {
    var logBase = complexLog(base);
    return complexExp({
      re: logBase.re * exp - logBase.im * 0,
      im: logBase.im * exp
    });
  }

  function computeZeta(sigma, t) {
    var s = { re: sigma, im: t };
    var etaSum = { re: 0, im: 0 };
    var one = { re: 1, im: 0 };
    var negOne = { re: -1, im: 0 };

    for (var k = 1; k <= 60; k++) {
      var denom = complexPow({ re: k, im: 0 }, s);
      if (denom.re * denom.re + denom.im * denom.im > 1e-10) {
        var term = complexDiv(k % 2 === 1 ? one : negOne, denom);
        etaSum.re += term.re;
        etaSum.im += term.im;
      }
    }

    var oneMinusPow = complexPow({ re: 2, im: 0 }, { re: 1 - sigma, im: -t });
    var diff = { re: 1 - oneMinusPow.re, im: -oneMinusPow.im };


    if (diff.re * diff.re + diff.im * diff.im > 1e-10) {
      return complexDiv(etaSum, diff);
    }

    return { re: 1, im: 0 };
  }

  function iterateJulia(cx, cy, maxIter) {
    var zx = cx;
    var zy = cy;
    var zetaC = computeZeta(0.5, cx * 5);

    var cReal = 0.3 + 0.3 * Math.sin(time * 0.3) + zetaC.re * 0.1;
    var cImag = 0.5 + 0.2 * Math.cos(time * 0.25) + zetaC.im * 0.1;

    for (var i = 0; i < maxIter; i++) {
      var zxNew = zx * zx - zy * zy + cReal;
      zy = 2 * zx * zy + cImag;
      zx = zxNew;


      if (zx * zx + zy * zy > 256) {
        return { iter: i, escape: true, zx: zx, zy: zy };
      }
    }
    return { iter: maxIter, escape: false, zx: zx, zy: zy };
  }

  function drawFractalLayer() {
    fractalBuffer.loadPixels();
    var pixels = fractalBuffer.pixels;

    for (var y = 0; y < p.height; y += RES) {
      for (var x = 0; x < p.width; x += RES) {
        var nx = (x - p.width / 2) / (p.height * 0.5 * zoomLevel);
        var ny = (y - p.height / 2) / (p.height * 0.5 * zoomLevel);

        var mx = (p.mouseX - p.width / 2) / p.width;
        var my = (p.mouseY - p.height / 2) / p.height;
        var mouseEffect = Math.exp(-(mx * mx + my * my) * 10);

        var zetaVal = computeZeta(0.5 + nx * 0.1, ny * 10);

        var jResult = iterateJulia(nx + mx * mouseEffect * 0.5, ny + my * mouseEffect * 0.5, 80);

        var iterNorm = jResult.iter / 80;
        var smoothIter = iterNorm;

        if (jResult.escape) {
          var log_zn = Math.log(jResult.zx * jResult.zx + jResult.zy * jResult.zy) / 2;
          var nu = Math.log(log_zn / Math.log(2)) / Math.log(2);
          smoothIter = jResult.iter + 1 - nu;
          smoothIter = smoothIter / 80;
        }

        var zetaMag = Math.sqrt(zetaVal.re * zetaVal.re + zetaVal.im * zetaVal.im);
        var zetaPhase = Math.atan2(zetaVal.im, zetaVal.re);

        var colorT = smoothIter * 3 + zetaPhase * 0.5 + time * 0.1 + mouseEffect * 2;
        var col = getColorAtPosition(colorT % 1);

        var bright = smoothIter * 0.6 + Math.min(zetaMag * 0.1, 0.4);
        var chroma = 1 + 0.5 * Math.sin(zetaPhase * 3 + time);

        for (var dy = 0; dy < RES && y + dy < p.height; dy++) {
          for (var dx = 0; dx < RES && x + dx < p.width; dx++) {
            var idx = ((y + dy) * p.width + (x + dx)) * 4;
            var r = col[0] * bright * chroma;
            var g = col[1] * bright;
            var b = col[2] * bright / chroma;

            pixels[idx] = Math.min(255, r);
            pixels[idx + 1] = Math.min(255, g);
            pixels[idx + 2] = Math.min(255, b);
            pixels[idx + 3] = 255;
          }
        }
      }
    }

    fractalBuffer.updatePixels();
  }

  function drawTunnelGeometry() {
    tunnelGraphics.clear();
    var cx = p.width / 2;
    var cy = p.height / 2;

    var mx = (p.mouseX - cx) / cx;
    var my = (p.mouseY - cy) / cy;

    tunnelGraphics.push();
    tunnelGraphics.translate(cx, cy);
    tunnelGraphics.noFill();

    var layers = 12;
    for (var layer = 0; layer < layers; layer++) {
      var layerRatio = layer / layers;
      var baseRadius = p.height * (0.3 - layerRatio * 0.25);
      var alpha = (180 - layerRatio * 120) * (0.5 + 0.5 * Math.sin(time + layer));
      var sw = 2 - layerRatio * 1.5;

      tunnelGraphics.strokeWeight(sw);
      tunnelGraphics.stroke(
        currentPalette[layer % currentPalette.length][0],
        currentPalette[layer % currentPalette.length][1],
        currentPalette[layer % currentPalette.length][2],
        alpha
      );

      tunnelGraphics.beginShape();
      var segments = 120;
      for (var i = 0; i <= segments; i++) {
        var angle = (i / segments) * p.TWO_PI * 3;
        var tunnelAngle = angle + time * 0.3 * (layer % 2 === 0 ? 1 : -1);

        var depthFactor = layerRatio * 0.3;
        var noise1 = p.noise(
          Math.cos(tunnelAngle) * 2 + depthFactor,
          Math.sin(tunnelAngle) * 2 + depthFactor,
          time * 0.5
        );
        var noise2 = p.noise(
          Math.cos(tunnelAngle) * 3 - depthFactor,
          Math.sin(tunnelAngle) * 3 - depthFactor,
          time * 0.3 + 100
        );

        var radiusMod = baseRadius * (0.7 + 0.4 * (noise1 * 0.7 + noise2 * 0.3));
        var spiralFactor = 1 + layerRatio * 0.5;
        var spiralAngle = tunnelAngle + layerRatio * Math.PI * 2 + mx * 0.5;

        var finalX = radiusMod * Math.cos(spiralAngle) * spiralFactor;
        var finalY = radiusMod * Math.sin(spiralAngle) * spiralFactor;

        if (i === 0) {
          tunnelGraphics.vertex(finalX, finalY);
        } else {
          tunnelGraphics.vertex(finalX, finalY);
        }
      }
      tunnelGraphics.endShape(p.CLOSE);
    }

    tunnelGraphics.pop();
  }

  function drawRecursiveVoid() {
    voidGraphics.clear();
    var cx = p.width / 2;
    var cy = p.height / 2;

    voidGraphics.push();
    voidGraphics.translate(cx, cy);

    var depthLevels = 10;
    for (var depth = 0; depth < depthLevels; depth++) {
      var depthRatio = depth / depthLevels;
      var radius = 80 + depth * 60;
      var segments = 8 + depth * 4;
      var alpha = 150 - depth * 12;

      voidGraphics.noFill();
      voidGraphics.strokeWeight(2.5 - depthRatio * 2);
      voidGraphics.stroke(
        currentPalette[(depth + 2) % currentPalette.length][0],
        currentPalette[(depth + 2) % currentPalette.length][1],
        currentPalette[(depth + 2) % currentPalette.length][2],
        alpha
      );

      voidGraphics.beginShape();
      for (var i = 0; i <= segments; i++) {
        var angle = (i / segments) * p.TWO_PI;
        var noiseVal = p.noise(
          Math.cos(angle) * 2.5 + depth,
          Math.sin(angle) * 2.5 + depth,
          time * 0.4
        );
        var rMod = radius * (0.6 + 0.8 * noiseVal);

        voidGraphics.curveVertex(
          rMod * Math.cos(angle) + mx * 20,
          rMod * Math.sin(angle) + my * 20
        );
      }
      voidGraphics.endShape(p.CLOSE);

      if (depth < depthLevels - 1) {
        for (var k = 0; k < 6; k++) {
          var kAngle = (k / 6) * p.TWO_PI + time * 0.2;
          var kR = radius * 0.4 * (1 + 0.3 * Math.sin(time + k));
          voidGraphics.fill(
            currentPalette[(depth + k) % currentPalette.length][0],
            currentPalette[(depth + k) % currentPalette.length][1],
            currentPalette[(depth + k) % currentPalette.length][2],
            100
          );
          voidGraphics.noStroke();
          voidGraphics.ellipse(
            kR * Math.cos(kAngle),
            kR * Math.sin(kAngle),
            10 - depth,
            10 - depth
          );
        }
      }
    }

    voidGraphics.pop();
  }

  function drawZetaSpiral() {
    var cx = p.width / 2;
    var cy = p.height / 2;

    for (var spiral = 0; spiral < 8; spiral++) {
      var spiralOffset = spiral * 0.08;
      var baseR = 60 + spiral * 25;

      p.strokeWeight(2.5 + 1.5 * Math.sin(time * 2 + spiral));

      p.beginShape();
      for (var i = 0; i <= 150; i++) {
        var t = i * 0.08 + time * 0.6 + spiralOffset;
        var r = baseR + t * 35;
        var theta = t * 2.5 + spiral * 0.4;

        var zetaVal = computeZeta(0.5, t * 0.1);
        var colorT = (spiral + t * 0.2) % 1;
        var col = getColorAtPosition(colorT);
        var bright = 180 + 75 * Math.sin(t * 4 + spiral * 2);

        p.stroke(col[0], col[1], col[2], bright);
        p.vertex(cx + r * Math.cos(theta), cy + r * Math.sin(theta));
      }
      p.endShape();
    }
  }

  function drawIridescentPulse() {
    var cx = p.width / 2;
    var cy = p.height / 2;
    var pulseR = 180 + 120 * Math.sin(time * 1.5);

    for (var ring = 0; ring < 6; ring++) {
      var r = pulseR + ring * 60;
      var alpha = 40 - ring * 5;
      var col = currentPalette[(ring + 4) % currentPalette.length];

      p.noFill();
      p.stroke(col[0], col[1], col[2], alpha);
      p.strokeWeight(1.5);
      p.ellipse(cx, cy, r * 2, r * 2);
    }

    p.fill(255, 255, 255, 15 + 15 * Math.sin(time * 5));
    p.noStroke();
    p.ellipse(cx, cy, 60 + 20 * Math.sin(time * 3), 60 + 20 * Math.sin(time * 3));
  }

  function drawEgoDeath() {
    if (!egoDeathActive) return;


    for (var i = egoDeathParticles.length - 1; i >= 0; i--) {
      var part = egoDeathParticles[i];
      part.x += part.vx;
      part.y += part.vy;
      part.life -= 0.015;
      part.size *= 0.98;


      if (part.life <= 0) {
        egoDeathParticles.splice(i, 1);
        continue;
      }

      var col = getColorAtPosition(part.phase);
      p.fill(col[0], col[1], col[2], part.life * 255);
      p.noStroke();
      p.ellipse(part.x, part.y, part.size, part.size);
    }

    if (egoDeathParticles.length === 0) {
      egoDeathActive = false;
    }
  }

  function triggerEgoDeath() {
    egoDeathActive = true;
    var mx = p.mouseX;
    var my = p.mouseY;

    for (var i = 0; i < 80; i++) {
      var angle = p.random(p.TWO_PI);
      var speed = p.random(3, 12);
      var r = p.random(10, 120);
      var col = getColorAtPosition(p.random(1));


      egoDeathParticles.push({
        x: mx + Math.cos(angle) * r,
        y: my + Math.sin(angle) * r,
        vx: Math.cos(angle) * speed,
        vy: Math.sin(angle) * speed,
        size: p.random(8, 20),
        life: 1,
        phase: p.random(1)
      });
    }

    for (var j = 0; j < 6; j++) {
      var r = 30 + j * 40;
      var col = currentPalette[j % currentPalette.length];
      p.noFill();
      p.stroke(col[0], col[1], col[2], 200);
      p.strokeWeight(3);
      p.ellipse(mx, my, r * 2, r * 2);
    }
  }

  function handleKeyboard() {
    if (p.key === 'z' || p.key === 'Z') {
      mode = (mode + 1) % 4;
      initPalette();
    }
    if (p.key === 'r' || p.key === 'R') {
      zoomLevel = 1;
      egoDeathParticles = [];
      egoDeathActive = false;
    }
    if (p.key === '1') zoomLevel = Math.max(0.5, zoomLevel - 0.2);
    if (p.key === '2') zoomLevel = Math.min(4, zoomLevel + 0.2);
  }

  p.draw = function() {
    time += 0.012;

    var bgColor = currentPalette[0];
    p.background(bgColor[0] * 0.3, bgColor[1] * 0.3, bgColor[2] * 0.3);

    zoomLevel = 1 + 0.5 * Math.sin(time * 0.3);

    drawFractalLayer();
    drawTunnelGeometry();
    drawRecursiveVoid();

    p.blendMode(p.ADD);
    p.image(fractalBuffer, 0, 0);
    p.image(tunnelGraphics, 0, 0);
    p.image(voidGraphics, 0, 0);
    p.blendMode(p.SCREEN);
    p.image(fractalBuffer, 0, 0);
    p.blendMode(p.BLEND);

    drawZetaSpiral();
    drawIridescentPulse();
    drawEgoDeath();

    p.fill(180, 160, 200, 120);
    p.textAlign(p.LEFT, p.BOTTOM);
    p.textSize(11);
    p.text('Mode: ' + paletteModes[mode] + ' [Z]', 12, p.height - 12);
    p.text('[1/2] Zoom | [R] Reset | Click for Ego-Death', 12, p.height - 30);
    p.text('Ego-Death Fractal Tunnel - Riemann Zeta Zero', 12, p.height - 48);
  };

  p.mouseMoved = function() {
    mouseInfluence.x = (p.mouseX - p.width / 2) / p.width;
    mouseInfluence.y = (p.mouseY - p.height / 2) / p.height;
  };

  p.mousePressed = function() {
    triggerEgoDeath();
  };

  p.keyPressed = function() {
    handleKeyboard();
  };

  p.windowResized = function() {
    var container = document.getElementById('p5-wrapper');
    p.resizeCanvas(container.offsetWidth, container.offsetHeight);

    fractalBuffer = p.createGraphics(p.width, p.height);
    tunnelGraphics = p.createGraphics(p.width, p.height);
    voidGraphics = p.createGraphics(p.width, p.height);
    fractalBuffer.pixelDensity(1);
  };
};

✨ AI 艺术解读

This artwork simulates a metaphysical descent into the Riemann zeta zero - the most profound unsolved mystery in mathematics. The fractal tunnel represents consciousness dissolving into pure mathematical truth, while the iridescent spiral evokes ego-death transformation. Each pixel computes Julia set dynamics colored by complex zeta values, creating a synesthetic bridge between number theory and visual experience. The recursive voids spiral inward like ancient temples or cosmic event horizons, inviting the viewer to confront mathematical infinity.

📝 补充说明

  • Julia set c parameter evolves with time and incorporates zeta function values for mathematically-inspired morphing
  • Resolution step of 3 used for pixel-level computation balance between detail and performance
  • Four curated palette modes: psychedelic synesthesia, alchemical transmutation, bismuth crystal, abyssal horror
  • Ego-death particle burst triggered on click creates transient ego dissolution visual event
  • Additive blending creates natural bloom without expensive Gaussian blur post-processing