Ego-Death Fractal Tunnel Recursive Descent

📅 April 25, 2026 🏷️ art
fractal-tunnel domain-warping recursive-descent ego-death hallucinogenic psychedelic-art monochrome-void pixel-manipulation pending-review
Generated by GridFlow AI | Tags: fractal-tunnel, domain-warping, recursive-descent, ego-death, hallucinogenic, psychedelic-art, monochrome-void, pixel-manipulation

💡 AI 提示词

Create a profound hallucinatory monochrome fractal tunnel depicting ego-death and recursive descent into infinite void. Use pixel-level domain warping with multiple noise sampling passes. Apply multi-layer compositing with glow buffers. The single hue should be deep violet-cyan with ethereal bloom and recursive fractal geometry.

🔧 核心算法要点

  1. Domain warping performed in 3 nested passes sampling noise at noise-warped coordinates for fractal chaos
  2. Recursive tunnel geometry computed in polar coordinates with logarithmic spiral distortion and time-varying wave perturbations
  3. Pixel-level rendering via loadPixels() loop with step size for performance, computing tunnel depth from concentric layer intersections
  4. Multi-layer offscreen buffer compositing: pixel tunnel buffer + glow buffer + curve overlay buffer
  5. Additive blend mode (blendMode ADD) for glow layer compositing over pixel buffer
  6. Recursive curve rendering using curveVertex() for bezier-like organic tunnel walls with fractal depth scaling
  7. Recursive function calls reducing scale by 0.75x per depth level for self-similar fractal structure

🎨 原始代码

var sketch = function(p) {
  var tunnelBuffer, glowBuffer, depthBuffer;
  var time = 0;
  var recursionDepth = 7;
  var tunnelRadius;
  var pixelBuffer;
  var pixelStep = 3;
  var mouseInfluence = 0;
  var spiralPhase = 0;
  var depthMask;
  var baseHue = 0.72;

  p.setup = function() {
    var container = document.getElementById('p5-wrapper');
    var w = container.offsetWidth;
    var h = container.offsetHeight;
    p.createCanvas(w, h).parent(container);
    p.colorMode(p.HSB, 1);
    p.noStroke();
    p.frameRate(30);

    tunnelBuffer = p.createGraphics(w, h);
    glowBuffer = p.createGraphics(w, h);
    depthBuffer = p.createGraphics(w, h);
    pixelBuffer = p.createGraphics(w, h);

    tunnelBuffer.colorMode(p.HSB, 1);
    glowBuffer.colorMode(p.HSB, 1);
    depthBuffer.colorMode(p.HSB, 1);
    pixelBuffer.colorMode(p.HSB, 1);

    tunnelRadius = Math.min(w, h) * 0.42;
    pixelStep = Math.max(2, Math.floor(Math.min(w, h) / 400));

    initDepthMask(w, h);
  };

  function initDepthMask(w, h) {
    depthBuffer.loadPixels();
    var d = depthBuffer.pixelDensity();
    var idx = 0;
    for (var y = 0; y < h; y++) {
      for (var x = 0; x < w; x++) {
        var cx = x - w / 2;
        var cy = y - h / 2;
        var dist = Math.sqrt(cx * cx + cy * cy);
        var angle = Math.atan2(cy, cx);
        var logDist = Math.log(dist + 1) * 3;
        var depthVal = (logDist % 1) * (1 - dist / (w * 0.7));
        depthVal = Math.max(0, Math.min(1, depthVal));
        depthBuffer.pixels[idx] = depthVal * 255;
        depthBuffer.pixels[idx + 1] = 255;
        depthBuffer.pixels[idx + 2] = 255;
        depthBuffer.pixels[idx + 3] = 255;
        idx += 4;
      }
    }
    depthBuffer.updatePixels();
  }

  p.draw = function() {
    var w = p.width;
    var h = p.height;
    var cx = w / 2 + (p.mouseX - w / 2) * 0.15;
    var cy = h / 2 + (p.mouseY - h / 2) * 0.15;

    p.background(0, 0, 0.03);

    renderPixelLevelDomainWarp(pixelBuffer, w, h, cx, cy);

    p.image(pixelBuffer, 0, 0);

    p.blendMode(p.ADD);
    renderGlowLayer(w, h, cx, cy);
    p.blendMode(p.BLEND);

    renderRecursiveCurveTunnel(tunnelBuffer, cx, cy, recursionDepth, 1);
    p.image(tunnelBuffer, 0, 0);

    renderCurveOverlay(w, h, cx, cy);
    p.image(depthBuffer, 0, 0);

    time += 0.006;
    spiralPhase += 0.02;
    mouseInfluence = p.lerp(mouseInfluence, 1, 0.02);
  };

  function renderPixelLevelDomainWarp(buf, w, h, cx, cy) {
    buf.loadPixels();
    var d = buf.pixelDensity();
    var step = pixelStep;

    for (var py = 0; py < h; py += step) {
      for (var px = 0; px < w; px += step) {
        var dx = px - cx;
        var dy = py - cy;
        var baseAngle = Math.atan2(dy, dx);
        var baseDist = Math.sqrt(dx * dx + dy * dy);

        var warpX = px;
        var warpY = py;

        for (var warpPass = 0; warpPass < 3; warpPass++) {
          var noiseX = warpX * 0.002 + warpPass * 17.3;
          var noiseY = warpY * 0.002 + warpPass * 23.7;
          var noiseZ = time * 0.4 + warpPass * 5.1;
          var warpStrength = 80 / (warpPass + 1);
          warpX += (p.noise(noiseX, noiseY, noiseZ) - 0.5) * warpStrength;
          warpY += (p.noise(noiseX + 100, noiseY + 100, noiseZ) - 0.5) * warpStrength;
        }

        var finalDx = warpX - cx;
        var finalDy = warpY - cy;
        var finalDist = Math.sqrt(finalDx * finalDx + finalDy * finalDy);
        var finalAngle = Math.atan2(finalDy, finalDx);

        var spiralAngle = finalAngle + Math.log(finalDist + 1) * 2.5 + spiralPhase;
        var spiralWarp = p.noise(Math.cos(spiralAngle) * 0.5, Math.sin(spiralAngle) * 0.5, time * 0.3);

        var tunnelDepth = 0;
        var tunnelScale = tunnelRadius;

        for (var d = 0; d < recursionDepth + 3; d++) {
          var layerNoise = p.noise(d * 0.5, time * 0.25, finalAngle * 0.1);
          var layerR = tunnelScale * (0.9 + layerNoise * 0.1);
          if (finalDist < layerR && finalDist > layerR * 0.05) {
            var layerDepth = (layerR - finalDist) / layerR;
            tunnelDepth += layerDepth * (1 - d / (recursionDepth + 3)) * 0.7;
          }
          tunnelScale *= 0.82;
        }

        var recursiveNoise = p.noise(
          finalDx * 0.004 + spiralWarp * 30,
          finalDy * 0.004 + spiralWarp * 30,
          time * 0.6 + tunnelDepth * 2
        );

        var recursiveNoise2 = p.noise(
          finalDx * 0.008 + tunnelDepth * 5,
          finalDy * 0.008 + tunnelDepth * 5,
          time * 0.4
        );

        var recursiveNoise3 = p.noise(
          finalDx * 0.016 + recursiveNoise2 * 20,
          finalDy * 0.016 + recursiveNoise2 * 20,
          time * 0.8
        );

        var finalValue = tunnelDepth * (0.4 + recursiveNoise * 0.6) * (0.5 + recursiveNoise2 * 0.5);
        finalValue += recursiveNoise3 * 0.15 * tunnelDepth;
        finalValue *= (0.7 + spiralWarp * 0.3);
        finalValue = Math.pow(finalValue, 0.7);

        var hue = baseHue + tunnelDepth * 0.08 + spiralWarp * 0.05;
        hue = (hue % 1 + 1) % 1;

        var sat = 0.85 * finalValue;
        var bri = finalValue * 1.2;

        for (var fillY = py; fillY < Math.min(py + step, h); fillY++) {
          for (var fillX = px; fillX < Math.min(px + step, w); fillX++) {
            var idx = (fillY * w + fillX) * 4 * d;
            buf.pixels[idx] = hue * 255;
            buf.pixels[idx + 1] = sat * 255;
            buf.pixels[idx + 2] = bri * 255;
            buf.pixels[idx + 3] = Math.min(255, finalValue * 300);
          }
        }
      }
    }

    buf.updatePixels();
  }

  function renderRecursiveCurveTunnel(buf, cx, cy, depth, scale) {
    buf.clear();

    if (depth <= 0 || scale < 0.05) return;

    var layers = depth + 2;

    for (var layer = 0; layer < layers; layer++) {
      var layerScale = scale * (1 - layer * 0.12);
      var layerTime = time + layer * 0.3;
      var layerHue = baseHue + layer * 0.02;

      var segments = 80 + depth * 12;
      var points = [];

      for (var i = 0; i <= segments; i++) {
        var angle = (i / segments) * p.TWO_PI;

        var n1 = p.noise(
          Math.cos(angle) * 0.8 + layer * 2.5,
          Math.sin(angle) * 0.8 + layer * 2.5,
          layerTime * 0.5
        );
        var n2 = p.noise(
          Math.cos(angle * 2) * 0.4 + layer * 4.1,
          Math.sin(angle * 2) * 0.4 + layer * 4.1,
          layerTime * 0.3 + 50
        );
        var n3 = p.noise(
          Math.cos(angle * 4) * 0.2 + layer * 7.3,
          Math.sin(angle * 4) * 0.2 + layer * 7.3,
          layerTime * 0.2 + 100
        );

        var combinedNoise = n1 * 0.5 + n2 * 0.3 + n3 * 0.2;

        var baseR = tunnelRadius * layerScale;
        var wave1 = Math.sin(angle * 3 + layerTime * 2) * baseR * 0.08;
        var wave2 = Math.sin(angle * 5 - layerTime * 1.5) * baseR * 0.05;
        var wave3 = Math.sin(angle * 7 + layerTime * 3) * baseR * 0.03;

        var radius = baseR * (0.7 + combinedNoise * 0.3) + wave1 + wave2 + wave3;

        var warpAngle = angle + p.noise(angle * 2, layerTime) * 0.3;

        var px = cx + Math.cos(warpAngle) * radius;
        var py = cy + Math.sin(warpAngle) * radius;

        points.push({ x: px, y: py });
      }

      var alpha = (depth - layer) / depth * 0.6 + 0.1;
      var strokeW = (depth - layer) * 0.5 + 0.5;

      buf.stroke(layerHue, 0.8, 1, alpha);
      buf.strokeWeight(strokeW * p.height * 0.003);
      buf.noFill();

      buf.beginShape();
      for (var i = 0; i < points.length; i++) {
        buf.curveVertex(points[i].x, points[i].y);
      }
      buf.endShape(p.CLOSE);
    }

    var nextDepth = depth - 1;
    var nextScale = scale * 0.75;

    renderRecursiveCurveTunnel(buf, cx, cy, nextDepth, nextScale);
  }

  function renderGlowLayer(w, h, cx, cy) {
    glowBuffer.clear();
    glowBuffer.background(0, 0, 0);

    var numLayers = 5;
    for (var g = 0; g < numLayers; g++) {
      var gScale = 1 - g * 0.15;
      var gTime = time + g * 0.2;
      var gAlpha = 0.15 - g * 0.02;

      var segments = 60 + g * 10;
      glowBuffer.stroke(baseHue, 0.9, 1, gAlpha);
      glowBuffer.strokeWeight((8 - g * 1.5) * p.height * 0.003);
      glowBuffer.noFill();

      glowBuffer.beginShape();
      for (var i = 0; i <= segments; i++) {
        var angle = (i / segments) * p.TWO_PI;
        var n = p.noise(Math.cos(angle) + g, Math.sin(angle) + g, gTime);
        var r = tunnelRadius * gScale * (0.75 + n * 0.25);
        var px = cx + Math.cos(angle) * r;
        var py = cy + Math.sin(angle) * r;
        glowBuffer.curveVertex(px, py);
      }
      glowBuffer.endShape(p.CLOSE);
    }

    glowBuffer.filter(p.BLUR, 3 + Math.sin(time * 2) * 1.5);

    glowBuffer.loadPixels();
    for (var i = 0; i < glowBuffer.pixels.length; i += 4) {
      if (glowBuffer.pixels[i + 3] > 0) {
        glowBuffer.pixels[i] = baseHue * 255;
        glowBuffer.pixels[i + 1] *= 0.7;
        glowBuffer.pixels[i + 2] = 255;
      }
    }
    glowBuffer.updatePixels();

    glowBuffer.blendMode(p.ADD);
    glowBuffer.image(glowBuffer, 0, 0);
    glowBuffer.blendMode(p.BLEND);

    p.image(glowBuffer, 0, 0);
  }

  function renderCurveOverlay(w, h, cx, cy) {
    depthBuffer.clear();

    var bezierLayers = recursionDepth;

    for (var b = 0; b < bezierLayers; b++) {
      var bTime = time * 0.7 + b * 0.5;
      var bScale = 1 - b * 0.1;
      var bHue = (baseHue + b * 0.03) % 1;

      var numCurves = 4;
      for (var c = 0; c < numCurves; c++) {
        var curveAngle = (c / numCurves) * p.TWO_PI + bTime * 0.5;

        depthBuffer.stroke(bHue, 0.6, 0.9, 0.4 - b * 0.04);
        depthBuffer.strokeWeight((2 - b * 0.2) * p.height * 0.002);
        depthBuffer.noFill();

        var ctrlDist = tunnelRadius * bScale * 0.6;
        var endDist = tunnelRadius * bScale * (0.5 + p.noise(b, c, bTime) * 0.3);

        var x0 = cx + Math.cos(curveAngle) * tunnelRadius * bScale * 0.3;
        var y0 = cy + Math.sin(curveAngle) * tunnelRadius * bScale * 0.3;

        var cx1 = cx + Math.cos(curveAngle + 0.5) * ctrlDist;
        var cy1 = cy + Math.sin(curveAngle + 0.5) * ctrlDist;

        var cx2 = cx + Math.cos(curveAngle - 0.5) * ctrlDist;
        var cy2 = cy + Math.sin(curveAngle - 0.5) * ctrlDist;

        var x3 = cx + Math.cos(curveAngle) * endDist;
        var y3 = cy + Math.sin(curveAngle) * endDist;

        depthBuffer.beginShape();
        depthBuffer.vertex(x0, y0);
        depthBuffer.bezierVertex(cx1, cy1, cx2, cy2, x3, y3);
        depthBuffer.endShape();
      }
    }
  }

  p.mousePressed = function() {
    spiralPhase += Math.PI * 0.5;
    mouseInfluence = 1.5;
  };

  p.keyPressed = function() {
    if (p.key === ' ') {
      recursionDepth = recursionDepth === 3 ? 9 : 3;
      tunnelRadius = Math.min(p.width, p.height) * (0.3 + recursionDepth * 0.015);
    }
    if (p.key === 'r' || p.key === 'R') {
      time = 0;
      spiralPhase = 0;
    }
  };

  p.windowResized = function() {
    var container = document.getElementById('p5-wrapper');
    var w = container.offsetWidth;
    var h = container.offsetHeight;
    p.resizeCanvas(w, h);
    tunnelRadius = Math.min(w, h) * 0.42;
    pixelStep = Math.max(2, Math.floor(Math.min(w, h) / 400));

    tunnelBuffer.resizeCanvas(w, h);
    glowBuffer.resizeCanvas(w, h);
    depthBuffer.resizeCanvas(w, h);
    pixelBuffer.resizeCanvas(w, h);

    initDepthMask(w, h);
  };
};

✨ AI 艺术解读

This artwork simulates the dissolution of ego consciousness through recursive descent into an infinite fractal tunnel void. The domain-warped pixel rendering creates impossible geometric surfaces where boundaries blur and reform through recursive noise distortions. Multiple composited layers suggest the layered nature of psychedelic ego-death experiences, while the perpetual spiral descent represents consciousness engaging with infinite recursive depth. The restrained monochrome palette of deep violet-cyan with ethereal bloom evokes a transcendental, otherworldly void beyond ordinary perception.

📝 补充说明

  • Domain warping is the core technique: sample noise at noise-warped coordinates, repeat 3 times for fractal complexity
  • Pixel-level rendering with step size 2-4 balances performance and visual fidelity
  • Use pixelDensity() when indexing pixels array for proper high-DPI display support
  • Recursive depth controlled by spacebar toggle for different visual complexity modes
  • Mouse influence creates center offset with smooth interpolation for subtle interaction