Orbital Strange Attractor Breeding Sacred Geometry

📅 April 25, 2026 🏷️ art
strange-attractor sacred-geometry orbital-mechanics alchemical-palette flow-field generative-art fractal-geometry cosmic-visualization pending-review
Generated by GridFlow AI | Tags: strange-attractor, sacred-geometry, orbital-mechanics, alchemical-palette, flow-field, generative-art, fractal-geometry, cosmic-visualization

💡 AI 提示词

Orbital Strange Attractor Breeding Sacred Geometry - create a metaphysical generative artwork combining Clifford and Peter de Jong strange attractors mapped to flow fields, with alchemical transmutation colors (mercury silver, sulfur yellow, deep cosmic indigo), multi-layer compositing, sacred geometry overlays including golden spiral integration and meta-polyhedra, particle systems influenced by the attractor flow, and interactive mouse/keyboard controls for parameter mutation and burst effects

🔧 核心算法要点

  1. Generate strange attractor point clouds using Clifford equations (x = sin(a*y) + c*cos(a*x), y = sin(b*x) + d*cos(b*y)) and Peter de Jong equations (x = sin(a*y) - cos(b*x), y = sin(c*x) - cos(d*y))
  2. Create a nearest-neighbor flow field by computing distance to attractor points for every position in the canvas
  3. Render multi-layer compositing with separate offscreen buffers for attractor visualization, flow field curves, sacred geometry, and composite output
  4. Apply pixel-level manipulation for background depth noise and vignette effects with step-based iteration for performance
  5. Implement particle systems that follow the flow field with velocity accumulation and mouse influence, using ADD blend mode for luminous effects
  6. Draw sacred geometry overlays including golden angle spiral distributions, bezier-curved radial lines, and curveVertex polygon mandalas
  7. Generate interactive burst particles on mouse click with physics-based trajectories and switching between attractor modes for parameter breeding
  8. Use Bezier curves and organic shape rendering instead of basic primitives, with controlled color palette of mercury silver, sulfur yellow, and cosmic indigo

🎨 原始代码

var sketch = function(p) {
  var attractorBuffer, flowBuffer, geometryBuffer, compositeBuffer;
  var a = -1.4, b = 1.6, c = 1.0, d = 0.7;
  var seqA = 1.7, seqB = 1.9, seqC = -0.8, seqD = -1.2;
  var phase = 0;
  var attractorMode = 0;
  var cosmicParticles = [];
  var numParticles = 800;
  var attractorPoints = [];
  var mouseInfluence = 0;
  var clickBurst = false;
  var burstParticles = [];

  p.setup = function() {
    var container = document.getElementById('p5-wrapper');
    var cnv = p.createCanvas(container.offsetWidth, container.offsetHeight).parent(container);
    p.colorMode(p.RGB, 255, 255, 255, 1);
    p.background(10, 5, 25);

    attractorBuffer = p.createGraphics(p.width, p.height);
    flowBuffer = p.createGraphics(p.width, p.height);
    geometryBuffer = p.createGraphics(p.width, p.height);
    compositeBuffer = p.createGraphics(p.width, p.height);

    attractorBuffer.colorMode(p.RGB, 255, 255, 255, 1);
    flowBuffer.colorMode(p.RGB, 255, 255, 255, 1);
    geometryBuffer.colorMode(p.RGB, 255, 255, 255, 1);
    compositeBuffer.colorMode(p.RGB, 255, 255, 255, 1);

    attractorBuffer.noStroke();
    flowBuffer.noStroke();
    geometryBuffer.noStroke();
    compositeBuffer.noStroke();

    generateAttractorPoints();
    initCosmicParticles();
  };

  function generateAttractorPoints() {
    attractorPoints = [];
    var x = p.random(-2, 2), y = p.random(-2, 2);
    var trail = [];
    var iterations = 3000;

    for (var i = 0; i < iterations; i++) {
      var newX, newY;

      if (attractorMode === 0) {
        newX = p.sin(a * y) + c * p.cos(a * x);
        newY = p.sin(b * x) + d * p.cos(b * y);
      } else {
        newX = p.sin(seqA * y) - p.cos(seqB * x);
        newY = p.sin(seqC * x) - p.cos(seqD * y);
      }

      x = newX;
      y = newY;
      trail.push({x: x, y: y});
    }

    var minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
    for (var j = 0; j < trail.length; j++) {
      minX = p.min(minX, trail[j].x);
      maxX = p.max(maxX, trail[j].x);
      minY = p.min(minY, trail[j].y);
      maxY = p.max(maxY, trail[j].y);
    }

    var rangeX = maxX - minX || 1;
    var rangeY = maxY - minY || 1;
    var scale = p.min(p.width * 0.8 / rangeX, p.height * 0.8 / rangeY);
    var cx = p.width / 2, cy = p.height / 2;

    for (var k = 0; k < trail.length; k++) {
      attractorPoints.push({
        sx: (trail[k].x - minX) / rangeX * scale + cx - scale/2,
        sy: (trail[k].y - minY) / rangeY * scale + cy - scale/2,
        x: trail[k].x, y: trail[k].y
      });
    }
  }

  function initCosmicParticles() {
    cosmicParticles = [];
    for (var i = 0; i < numParticles; i++) {
      cosmicParticles.push({
        x: p.random(p.width),
        y: p.random(p.height),
        vx: p.random(-0.5, 0.5),
        vy: p.random(-0.5, 0.5),
        life: p.random(0.5, 1),
        size: p.random(1, 4),
        hueShift: p.random(0, 60)
      });
    }
  }

  function getFlowField(x, y) {
    var minDist = Infinity;
    var closest = null;

    for (var i = 0; i < attractorPoints.length; i += 8) {
      var dx = x - attractorPoints[i].sx;
      var dy = y - attractorPoints[i].sy;
      var dist = dx * dx + dy * dy;
      if (dist < minDist) {
        minDist = dist;
        closest = attractorPoints[i];
      }
    }

    if (closest) {
      var angle = p.atan2(y - closest.sy, x - closest.sx) + phase;
      return { angle: angle, dist: p.sqrt(minDist) };
    }
    return { angle: 0, dist: 1000 };
  }

  function drawBackgroundLayer() {
    compositeBuffer.background(10, 5, 25, 0.15);

    compositeBuffer.loadPixels();
    var d = compositeBuffer.pixels;
    var step = 3;

    for (var x = 0; x < p.width; x += step) {
      for (var y = 0; y < p.height; y += step) {
        var noiseVal = p.noise(x * 0.003, y * 0.003, phase * 0.1);
        var depth = p.map(noiseVal, 0, 1, 0, 0.4);

        var idx = (x + y * p.width) * 4;
        d[idx] = p.lerp(d[idx], 20 + noiseVal * 15, depth);
        d[idx + 1] = p.lerp(d[idx + 1], 10 + noiseVal * 8, depth);
        d[idx + 2] = p.lerp(d[idx + 2], 45 + noiseVal * 20, depth);
      }
    }
    compositeBuffer.updatePixels();
  }

  function drawAttractorLayer() {
    attractorBuffer.clear();
    attractorBuffer.background(0, 0, 0, 0);

    var numStrands = 6;
    for (var strand = 0; strand < numStrands; strand++) {
      var startX = p.random(p.width);
      var startY = p.random(p.height);
      var hue = strand * 30;

      attractorBuffer.stroke(200 + hue * 0.3, 220 + hue * 0.2, 255, 0.03);
      attractorBuffer.strokeWeight(0.8);

      attractorBuffer.beginShape();
      var px = startX, py = startY;

      for (var i = 0; i < 200; i++) {
        var flow = getFlowField(px, py);
        px += p.cos(flow.angle) * 2.5;
        py += p.sin(flow.angle) * 2.5;

        if (px < 0 || px > p.width || py < 0 || py > p.height) break;

        var brightness = p.map(flow.dist, 0, 200, 1, 0.02);
        attractorBuffer.stroke(180 + hue * 0.4, 200 + hue * 0.3, 255, brightness);
        attractorBuffer.vertex(px, py);
      }
      attractorBuffer.endShape();
    }

    for (var j = 0; j < attractorPoints.length; j += 50) {
      var pt = attractorPoints[j];
      var coreBright = p.noise(pt.x * 0.01, pt.y * 0.01, phase) * 0.5 + 0.5;
      var silver = 180 + coreBright * 75;
      var sulfur = 160 + coreBright * 95;

      attractorBuffer.fill(silver, sulfur, 255, 0.6 * coreBright);
      attractorBuffer.ellipse(pt.sx, pt.sy, 3 + coreBright * 4, 3 + coreBright * 4);
    }
  }

  function drawFlowFieldLayer() {
    flowBuffer.clear();
    flowBuffer.background(0, 0, 0, 0);

    flowBuffer.strokeWeight(0.5);
    var spacing = 18;

    for (var x = spacing/2; x < p.width; x += spacing) {
      for (var y = spacing/2; y < p.height; y += spacing) {
        var flow = getFlowField(x, y);
        var len = p.map(flow.dist, 0, 150, 12, 4);
        var brightness = p.map(flow.dist, 0, 150, 0.8, 0.05);

        var mx = (p.mouseX - x) * 0.03;
        var my = (p.mouseY - y) * 0.03;
        var angle = flow.angle + p.atan2(my, mx);

        var indigo = p.map(p.sin(phase * 2 + x * 0.02), -1, 1, 40, 80);
        var silver = p.map(p.cos(phase * 1.5 + y * 0.015), -1, 1, 160, 200);

        flowBuffer.stroke(silver, silver + 30, indigo, brightness * 0.4);

        flowBuffer.beginShape();
        flowBuffer.vertex(x, y);

        var x1 = x + p.cos(angle) * len * 0.3;
        var y1 = y + p.sin(angle) * len * 0.3;
        var x2 = x + p.cos(angle) * len * 0.7;
        var y2 = y + p.sin(angle) * len * 0.7;
        var x3 = x + p.cos(angle) * len;
        var y3 = y + p.sin(angle) * len;

        flowBuffer.bezierVertex(x1, y1, x2, y2, x3, y3);
        flowBuffer.endShape();
      }
    }
  }

  function drawSacredGeometry() {
    geometryBuffer.clear();
    geometryBuffer.background(0, 0, 0, 0);

    var cx = p.width / 2;
    var cy = p.height / 2;
    var phi = (1 + p.sqrt(5)) / 2;
    var goldenAngle = 137.508;

    geometryBuffer.stroke(220, 200, 100, 0.15);
    geometryBuffer.strokeWeight(0.5);

    for (var ring = 0; ring < 5; ring++) {
      var radius = 50 + ring * 80;
      geometryBuffer.noFill();

      geometryBuffer.beginShape();
      for (var t = 0; t <= p.TWO_PI; t += 0.01) {
        var goldenR = radius * p.pow(phi, t / p.TWO_PI);
        var gx = cx + p.cos(t) * goldenR * 0.15;
        var gy = cy + p.sin(t) * goldenR * 0.15;
        geometryBuffer.vertex(gx, gy);
      }
      geometryBuffer.endShape();
    }

    geometryBuffer.stroke(200, 180, 80, 0.1);
    for (var i = 0; i < 12; i++) {
      var angle = i * p.TWO_PI / 12 + phase * 0.3;
      var innerR = 40;
      var outerR = p.min(p.width, p.height) * 0.45;

      geometryBuffer.beginShape();
      geometryBuffer.vertex(cx + p.cos(angle) * innerR, cy + p.sin(angle) * innerR);

      var cp1x = cx + p.cos(angle + 0.2) * (innerR + outerR) * 0.5;
      var cp1y = cy + p.sin(angle + 0.2) * (innerR + outerR) * 0.5;
      var cp2x = cx + p.cos(angle - 0.2) * (innerR + outerR) * 0.5;
      var cp2y = cy + p.sin(angle - 0.2) * (innerR + outerR) * 0.5;
      var ex = cx + p.cos(angle) * outerR;
      var ey = cy + p.sin(angle) * outerR;

      geometryBuffer.bezierVertex(cp1x, cp1y, cp2x, cp2y, ex, ey);
      geometryBuffer.endShape();
    }

    var numSides = 6;
    for (var s = 0; s < 3; s++) {
      var polyR = 120 + s * 100;
      geometryBuffer.stroke(150 + s * 30, 160 + s * 20, 200, 0.12);
      geometryBuffer.noFill();

      geometryBuffer.beginShape();
      for (var j = 0; j <= numSides; j++) {
        var polyAngle = j * p.TWO_PI / numSides + phase * 0.1;
        var px = cx + p.cos(polyAngle) * polyR;
        var py = cy + p.sin(polyAngle) * polyR;
        geometryBuffer.curveVertex(px, py);
      }
      geometryBuffer.endShape();
    }

    geometryBuffer.fill(230, 210, 80, 0.3);
    geometryBuffer.noStroke();
    for (var seed = 0; seed < 37; seed++) {
      var seedAngle = seed * goldenAngle * p.PI / 180;
      var seedR = p.sqrt(seed) * 12;
      var seedX = cx + p.cos(seedAngle) * seedR;
      var seedY = cy + p.sin(seedAngle) * seedR;
      var seedSize = 2 + p.sin(seedAngle * 3 + phase) * 1.5;

      geometryBuffer.ellipse(seedX, seedY, seedSize, seedSize);
    }
  }

  function drawCosmicParticles() {
    compositeBuffer.blendMode(p.ADD);

    for (var i = 0; i < cosmicParticles.length; i++) {
      var pt = cosmicParticles[i];
      var flow = getFlowField(pt.x, pt.y);

      pt.vx = pt.vx * 0.95 + p.cos(flow.angle) * 0.08;
      pt.vy = pt.vy * 0.95 + p.sin(flow.angle) * 0.08;

      pt.vx += (p.mouseX - pt.x) * mouseInfluence * 0.0001;
      pt.vy += (p.mouseY - pt.y) * mouseInfluence * 0.0001;

      pt.x += pt.vx;
      pt.y += pt.vy;

      if (pt.x < 0) pt.x = p.width;
      if (pt.x > p.width) pt.x = 0;
      if (pt.y < 0) pt.y = p.height;
      if (pt.y > p.height) pt.y = 0;

      var brightness = pt.life * (1 - flow.dist / 200);
      var mercury = 180 + p.sin(pt.hueShift + phase) * 40;
      var sulfur = 160 + p.cos(pt.hueShift * 0.7 + phase * 1.3) * 60;
      var indigo = 80 + p.sin(phase + pt.x * 0.01) * 40;

      compositeBuffer.fill(mercury, sulfur, indigo, brightness * 0.6);
      compositeBuffer.ellipse(pt.x, pt.y, pt.size * (1 + brightness), pt.size * (1 + brightness));

      compositeBuffer.fill(255, 255, 255, brightness * 0.3 * pt.life);
      compositeBuffer.ellipse(pt.x, pt.y, pt.size * 0.3, pt.size * 0.3);
    }

    compositeBuffer.blendMode(p.BLEND);
  }

  function drawBurstEffect() {
    if (burstParticles.length === 0) return;

    compositeBuffer.blendMode(p.SCREEN);

    for (var i = burstParticles.length - 1; i >= 0; i--) {
      var bp = burstParticles[i];
      bp.x += bp.vx;
      bp.y += bp.vy;
      bp.vy += 0.05;
      bp.life -= 0.015;

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

      var burstSilver = 200 + bp.hueOffset;
      var burstSulfur = 220 - bp.hueOffset * 0.5;
      var burstIndigo = 100 + p.sin(bp.angle * 3) * 50;

      compositeBuffer.fill(burstSilver, burstSulfur, burstIndigo, bp.life * 0.8);
      compositeBuffer.noStroke();

      compositeBuffer.beginShape();
      compositeBuffer.vertex(bp.x, bp.y);
      compositeBuffer.vertex(bp.x + p.cos(bp.angle) * 20 * bp.life, bp.y + p.sin(bp.angle) * 20 * bp.life);
      compositeBuffer.vertex(bp.x + p.cos(bp.angle + 0.5) * 10 * bp.life, bp.y + p.sin(bp.angle + 0.5) * 10 * bp.life);
      compositeBuffer.endShape(p.CLOSE);

      compositeBuffer.fill(255, 255, 255, bp.life * 0.5);
      compositeBuffer.ellipse(bp.x, bp.y, 4 * bp.life, 4 * bp.life);
    }

    compositeBuffer.blendMode(p.BLEND);
  }

  function drawVignetteAndBloom() {
    compositeBuffer.loadPixels();
    var d = compositeBuffer.pixels;
    var step = 2;

    for (var x = 0; x < p.width; x += step) {
      for (var y = 0; y < p.height; y += step) {
        var dist = p.dist(x, y, p.width/2, p.height/2);
        var maxDist = p.dist(0, 0, p.width/2, p.height/2);
        var vignette = 1 - p.pow(dist / maxDist, 2) * 0.7;

        var idx = (x + y * p.width) * 4;
        d[idx] *= vignette;
        d[idx + 1] *= vignette;
        d[idx + 2] *= vignette;
      }
    }
    compositeBuffer.updatePixels();
  }

  p.draw = function() {
    phase += 0.008;
    mouseInfluence = p.min(1, p.dist(p.mouseX, p.mouseY, p.width/2, p.height/2) / 300);

    drawBackgroundLayer();
    drawAttractorLayer();
    drawFlowFieldLayer();
    drawSacredGeometry();

    compositeBuffer.blendMode(p.BLEND);
    compositeBuffer.image(flowBuffer, 0, 0);
    compositeBuffer.blendMode(p.ADD);
    compositeBuffer.image(attractorBuffer, 0, 0);
    compositeBuffer.image(geometryBuffer, 0, 0);
    compositeBuffer.blendMode(p.BLEND);

    drawCosmicParticles();
    drawBurstEffect();
    drawVignetteAndBloom();

    p.background(0);
    p.image(compositeBuffer, 0, 0);

    p.noStroke();
    p.fill(180, 200, 255, 0.5);
    p.textSize(10);
    p.textAlign(p.LEFT, p.BOTTOM);
    p.text('Orbital Strange Attractor Breeding Sacred Geometry', 10, p.height - 10);
  };

  p.mousePressed = function() {
    clickBurst = true;
    burstParticles = [];

    for (var i = 0; i < 60; i++) {
      var angle = p.random(p.TWO_PI);
      var speed = p.random(2, 8);
      burstParticles.push({
        x: p.mouseX, y: p.mouseY,
        vx: p.cos(angle) * speed,
        vy: p.sin(angle) * speed,
        life: 1,
        angle: angle,
        hueOffset: p.random(-30, 30)
      });
    }

    var tempA = a, tempB = b, tempC = c, tempD = d;
    a = seqA; b = seqB; c = seqC; d = seqD;
    seqA = tempA; seqB = tempB; seqC = tempC; seqD = tempD;
    attractorMode = (attractorMode + 1) % 2;
    generateAttractorPoints();
  };

  p.mouseMoved = function() {
    mouseInfluence = 1;
  };

  p.keyPressed = function() {
    if (p.key === ' ' || p.key === ' ') {
      a = p.random(-2.5, 2.5);
      b = p.random(-2.5, 2.5);
      c = p.random(-2.5, 2.5);
      d = p.random(-2.5, 2.5);
      generateAttractorPoints();
    } else if (p.key === 'r' || p.key === 'R') {
      initCosmicParticles();
      generateAttractorPoints();
    } else if (p.key === 'g' || p.key === 'G') {
      seqA = p.random(-2.5, 2.5);
      seqB = p.random(-2.5, 2.5);
      seqC = p.random(-2.5, 2.5);
      seqD = p.random(-2.5, 2.5);
      attractorMode = 1;
      generateAttractorPoints();
    }
  };

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

    attractorBuffer = p.createGraphics(p.width, p.height);
    flowBuffer = p.createGraphics(p.width, p.height);
    geometryBuffer = p.createGraphics(p.width, p.height);
    compositeBuffer = p.createGraphics(p.width, p.height);

    attractorBuffer.colorMode(p.RGB, 255, 255, 255, 1);
    flowBuffer.colorMode(p.RGB, 255, 255, 255, 1);
    geometryBuffer.colorMode(p.RGB, 255, 255, 255, 1);
    compositeBuffer.colorMode(p.RGB, 255, 255, 255, 1);

    attractorBuffer.noStroke();
    flowBuffer.noStroke();
    geometryBuffer.noStroke();
    compositeBuffer.noStroke();

    generateAttractorPoints();
  };
}; // p5 init stripped

✨ AI 艺术解读

This artwork manifests as a living simulation of orbital mechanics meeting esoteric geometry, where strange attractors from chaos theory become the invisible hand shaping cosmic flow fields. The alchemical palette of mercury silver, sulfur yellow, and deep indigo evokes transmutation rituals and the prima materia of creation. Viewers witness the breeding of parameters through interaction, triggering evolutionary jumps between attractor configurations while sacred geometry constellations shimmer in the background. The piece functions as a meditation on how deterministic chaos gives rise to beautiful patterns, suggesting that beneath apparent randomness lies an underlying mathematical order that mirrors ancient geometric truths.

📝 补充说明

  • Strange attractor parameter breeding on mouse click creates emergent visual mutations - users can explore the parameter space interactively
  • Multi-layer compositing with ADD blend mode creates the luminous, glowing effect that separates this from flat single-canvas work
  • Using nearest-neighbor flow field with step=8 for attractor points provides real-time interaction response without expensive iterations
  • Sacred geometry renders golden angle (137.5 degree) seed distribution which connects to sunflower patterns and Fibonacci sequences
  • Pixel-level vignette at step=2 balances visual quality with acceptable frame rates on modern hardware