Cellular Automaton Breeding the Flower of Life

📅 April 25, 2026 🏷️ art
L-system cellular-automaton flower-of-life bismuth-crystal recursive-geometry generative-art sacred-geometry neural-patterns interference-patterns multi-layer-compositing pending-review
Generated by GridFlow AI | Tags: L-system, cellular-automaton, flower-of-life, bismuth-crystal, recursive-geometry, generative-art, sacred-geometry, neural-patterns, interference-patterns, multi-layer-compositing

💡 AI 提示词

Cellular Automaton Breeding the Flower of Life rendered in bismuth crystal style — geometric pastel rainbow interference patterns on dark background. Using L-systems with extreme recursion depth simulating neural or fungal consciousness. Multi-layer offscreen compositing with ADD and SCREEN blend modes for luminous depth.

🔧 核心算法要点

  1. L-system generation with recursive growth rules simulating organic consciousness patterns
  2. Cellular automaton state propagation creating evolving wave interference across hexagonal grids
  3. Multi-layer offscreen buffer architecture for depth compositing with ADD and SCREEN blend modes
  4. Sacred geometry Flower of Life pattern with overlapping vesica piscis formations
  5. Pixel-level background void rendering with angular interference functions
  6. Mouse proximity influence affecting pattern scale, size, and growth dynamics
  7. Dynamic recursion depth modulation based on temporal phase and interaction intensity
  8. Recursive consciousness core with Metatron's Cube inspired geometric transformations
  9. Curve-based interference branches with sinusoidal wave displacement rendering
  10. Mode-based L-system parameter switching for visual diversity across 5 modes

🎨 原始代码

var sketch = function(p) {
  // Multi-layer buffer architecture for depth compositing
  let bgBuffer, layer1Buffer, layer2Buffer, layer3Buffer, compositeBuffer;
  let time = 0;
  let mode = 0;
  let mouseInfluence = 0;
  let lastMouseX = 0;
  let lastMouseY = 0;
  let interactionRadius = 200;
  let growthPhase = 0;
  let recursionDepth = 7;
  
  // Bismuth crystal color palette - geometric pastel rainbow
  let bismuthPalette = [];
  
  // L-System rules for consciousness-like growth patterns
  let lSysRules = {
    iterations: 6,
    angle: 25.7,
    startLength: 8,
    startX: 0,
    startY: 0,
    sentences: ['X', 'F'],
    rules: {}
  };
  
  p.setup = function() {
    let container = document.getElementById('p5-wrapper');
    p.createCanvas(container.offsetWidth, container.offsetHeight).parent(container);
    p.colorMode(p.RGB, 255, 255, 255, 1);
    p.noStroke();
    
    // Initialize bismuth crystal pastel palette
    bismuthPalette = [
      p.color(200, 180, 255, 0.6),  // Soft violet
      p.color(255, 200, 220, 0.6),  // Blush pink
      p.color(180, 230, 255, 0.6),  // Sky crystal
      p.color(220, 255, 200, 0.6),  // Mint shard
      p.color(255, 240, 180, 0.6),  // Golden facet
      p.color(200, 240, 255, 0.6),  // Ice blue
      p.color(255, 200, 200, 0.6),  // Rose quartz
      p.color(180, 200, 255, 0.6)   // Lavender layer
    ];
    
    // Create offscreen buffers for multi-layer compositing
    bgBuffer = p.createGraphics(p.width, p.height);
    layer1Buffer = p.createGraphics(p.width, p.height);
    layer2Buffer = p.createGraphics(p.width, p.height);
    layer3Buffer = p.createGraphics(p.width, p.height);
    compositeBuffer = p.createGraphics(p.width, p.height);
    
    initLSystemRules();
    drawBackground();
  };
  
  function initLSystemRules() {
    // Organic growth rules simulating neural/fungal consciousness
    lSysRules.rules = {
      'X': 'F+[[X]-X]-F[-FX]+X',
      'F': 'FF'
    };
    lSysRules.angle = 22.5 + p.sin(time * 0.001) * 5;
  }
  
  function drawBackground() {
    bgBuffer.background(8, 4, 15, 1);
    
    // Create dark void with subtle interference pattern
    bgBuffer.loadPixels();
    let step = 3;
    for (let x = 0; x < bgBuffer.width; x += step) {
      for (let y = 0; y < bgBuffer.height; y += step) {
        let centerX = bgBuffer.width / 2;
        let centerY = bgBuffer.height / 2;
        let dx = x - centerX;
        let dy = y - centerY;
        let dist = p.sqrt(dx * dx + dy * dy);
        let angle = p.atan2(dy, dx);
        
        let interference1 = p.sin(angle * 3 + dist * 0.02 + time * 0.5);
        let interference2 = p.cos(angle * 5 - dist * 0.015 + time * 0.3);
        let interference3 = p.sin((x + y) * 0.01 + time * 0.4);
        
        let combined = (interference1 + interference2 + interference3) / 3;
        let intensity = (combined + 1) * 0.5;
        
        let r = 8 + intensity * 12;
        let g = 4 + intensity * 8;
        let b = 15 + intensity * 20;
        
        // Add subtle gradient from center
        let radialGrad = 1 - (dist / (bgBuffer.width * 0.7));
        radialGrad = p.max(0, radialGrad);
        
        let idx = (x + y * bgBuffer.width) * 4;
        bgBuffer.pixels[idx] = r + radialGrad * 5;
        bgBuffer.pixels[idx + 1] = g + radialGrad * 3;
        bgBuffer.pixels[idx + 2] = b + radialGrad * 10;
        bgBuffer.pixels[idx + 3] = 255;
      }
    }
    bgBuffer.updatePixels();
  }
  
  function generateLSystemSentence(iterations) {
    let sentence = 'X';
    for (let i = 0; i < iterations; i++) {
      let nextSentence = '';
      for (let j = 0; j < sentence.length; j++) {
        let char = sentence.charAt(j);
        nextSentence += lSysRules.rules[char] || char;
      }
      sentence = nextSentence;
    }
    return sentence;
  }
  
  function drawLSystemToBuffer(buffer, cx, cy, sentence, maxDepth, paletteOffset) {
    buffer.push();
    buffer.translate(cx, cy);
    
    let len = lSysRules.startLength;
    let stack = [];
    let depth = 0;
    
    // Add rotation based on time for living quality
    buffer.rotate(time * 0.0005);
    
    for (let i = 0; i < sentence.length; i++) {
      let char = sentence.charAt(i);
      
      if (char === 'F') {
        // Draw with interference pattern
        let angle = buffer.atan2(0, 1) - buffer.rotation;
        let x2 = 0;
        let y2 = -len;
        
        // Rotate for actual drawing
        buffer.push();
        buffer.rotate(-buffer.rotation);
        
        let colorIdx = (depth + paletteOffset) % bismuthPalette.length;
        let col = bismuthPalette[colorIdx];
        
        // Create glow effect
        let glowAlpha = p.map(depth, 0, maxDepth, 0.4, 0.1);
        let baseAlpha = p.map(depth, 0, maxDepth, 0.8, 0.3);
        
        // Draw multiple layers for depth
        for (let g = 3; g >= 0; g--) {
          buffer.stroke(red(col), green(col), blue(col), baseAlpha * (1 - g * 0.2));
          buffer.strokeWeight(1 + g * 1.5);
          buffer.line(0, 0, x2, y2);
        }
        
        buffer.translate(x2, y2);
        buffer.pop();
        
      } else if (char === '+') {
        buffer.rotate(lSysRules.angle + p.sin(time * 0.002 + depth) * 3);
      } else if (char === '-') {
        buffer.rotate(-lSysRules.angle - p.cos(time * 0.002 + depth) * 3);
      } else if (char === '[') {
        stack.push({ x: buffer.translation.x, y: buffer.translation.y, r: buffer.rotation });
        len *= 0.7;
        depth++;
      } else if (char === ']') {
        if (stack.length > 0) {
          let state = stack.pop();
          buffer.translate(state.x - buffer.translation.x, state.y - buffer.translation.y);
          buffer.rotate(state.r - buffer.rotation);
          len /= 0.7;
          depth--;
        }
      }
    }
    
    buffer.pop();
  }
  
  function drawFlowerOfLifeLayer(buffer, cx, cy, radius, numCircles, alpha) {
    buffer.push();
    buffer.translate(cx, cy);
    buffer.rotate(time * 0.0008);
    
    // Interference pattern overlay
    let interferenceScale = 0.003 + p.sin(time * 0.001) * 0.001;
    
    for (let i = 0; i < numCircles; i++) {
      for (let j = 0; j < 6; j++) {
        let angle = (j / 6) * p.TWO_PI + (i * p.TWO_PI / numCircles) * 0.1;
        let px = p.cos(angle) * radius;
        let py = p.sin(angle) * radius;
        
        // Calculate interference for this position
        let distFromCenter = p.sqrt(px * px + py * py);
        let interferenceAngle = p.atan2(py, px);
        
        let wave1 = p.sin(distFromCenter * interferenceScale * 50 + time * 0.5);
        let wave2 = p.cos(interferenceAngle * 4 + distFromCenter * 0.01 + time * 0.3);
        let wave3 = p.sin((px + py) * interferenceScale * 30 + time * 0.4);
        
        let interference = (wave1 + wave2 + wave3) / 3;
        let colorIdx = ((i + j + Math.floor(time * 0.05)) * 17) % bismuthPalette.length;
        let col = bismuthPalette[colorIdx];
        
        // Draw with interference-based opacity
        let finalAlpha = alpha * (0.3 + interference * 0.4) * (0.5 + interference * 0.5);
        
        buffer.noFill();
        // Multiple stroke layers for crystal facet effect
        for (let layer = 0; layer < 4; layer++) {
          buffer.stroke(red(col), green(col), blue(col), finalAlpha * (1 - layer * 0.2));
          buffer.strokeWeight(0.5 + layer * 0.3 + interference * 0.5);
          buffer.ellipse(px, py, radius * (1.1 + layer * 0.15), radius * (1.1 + layer * 0.15));
        }
      }
    }
    
    buffer.pop();
  }
  
  function drawCellularAutomaton(buffer, cx, cy, radius) {
    buffer.push();
    buffer.translate(cx, cy);
    buffer.rotate(time * 0.001);
    
    // Draw cellular automaton grid as interference pattern
    let gridSize = 40;
    let cellSize = radius / gridSize;
    
    for (let i = -gridSize / 2; i < gridSize / 2; i++) {
      for (let j = -gridSize / 2; j < gridSize / 2; j++) {
        // Calculate cell state based on neighborhood (like cellular automaton)
        let x = i + gridSize / 2;
        let y = j + gridSize / 2;
        
        // Create propagating wave patterns
        let dist = p.sqrt(i * i + j * j);
        let angle = p.atan2(j, i);
        
        // Multiple wave sources for interference
        let wave1 = p.sin(dist * 0.5 - time * 0.8 + angle * 2);
        let wave2 = p.sin(dist * 0.3 + time * 0.6 - angle * 3);
        let wave3 = p.cos((i + j) * 0.2 + time * 0.4);
        
        let state = (wave1 + wave2 + wave3) / 3;
        state = (state + 1) * 0.5; // Normalize to 0-1
        
        // Create hexagonal cells
        let px = i * cellSize + cellSize / 2;
        let py = j * cellSize + cellSize / 2;
        
        // Only draw active cells
        if (state > 0.3) {
          let colorIdx = Math.floor(state * bismuthPalette.length * 1.5) % bismuthPalette.length;
          let col = bismuthPalette[colorIdx];
          let alpha = p.map(state, 0.3, 1, 0, 0.7);
          
          // Draw hexagonal cell
          buffer.fill(red(col), green(col), blue(col), alpha);
          buffer.noStroke();
          
          buffer.beginShape();
          for (let k = 0; k < 6; k++) {
            let a = k * p.TWO_PI / 6 + time * 0.01;
            let hx = px + p.cos(a) * cellSize * 0.4;
            let hy = py + p.sin(a) * cellSize * 0.4;
            buffer.vertex(hx, hy);
          }
          buffer.endShape(p.CLOSE);
        }
      }
    }
    
    buffer.pop();
  }
  
  function drawVesicaLayer(buffer, cx, cy, size, rotation) {
    buffer.push();
    buffer.translate(cx, cy);
    buffer.rotate(rotation + time * 0.0003);
    
    // Draw vesica piscis / seed of life pattern
    let petalCount = 6;
    let angleStep = p.TWO_PI / petalCount;
    
    for (let i = 0; i < petalCount; i++) {
      let angle = i * angleStep;
      let px = p.cos(angle) * size * 0.5;
      let py = p.sin(angle) * size * 0.5;
      
      // Interference calculation
      let interference1 = p.sin(angle * 4 + time * 0.3);
      let interference2 = p.cos(dist(0, 0, px, py) * 0.02 + time * 0.5);
      let interference = (interference1 + interference2) / 2;
      
      let colorIdx = (i + Math.floor(time * 0.02)) % bismuthPalette.length;
      let col = bismuthPalette[colorIdx];
      
      // Multiple overlapping ellipses for depth
      for (let layer = 0; layer < 3; layer++) {
        let layerAlpha = 0.3 - layer * 0.1;
        let layerSize = size * (0.3 + layer * 0.15);
        
        buffer.noFill();
        buffer.stroke(red(col), green(col), blue(col), layerAlpha * (0.5 + interference * 0.5));
        buffer.strokeWeight(0.5 + layer * 0.5);
        
        // Draw vesica shape
        let a = 0;
        buffer.beginShape();
        for (let t = 0; t <= 100; t++) {
          a = p.map(t, 0, 100, 0, p.PI);
          let vx = px + layerSize * 0.4 * p.sin(a);
          let vy = py + layerSize * p.cos(a) * p.sqrt(1 + p.sin(a) * p.sin(a) * 0.5);
          buffer.vertex(vx, vy);
        }
        buffer.endShape();
      }
    }
    
    buffer.pop();
  }
  
  p.draw = function() {
    time++;
    
    // Calculate mouse influence
    let dx = p.mouseX - lastMouseX;
    let dy = p.mouseY - lastMouseY;
    mouseInfluence = p.sqrt(dx * dx + dy * dy) * 0.1;
    mouseInfluence = p.constrain(mouseInfluence, 0, 50);
    lastMouseX = p.mouseX;
    lastMouseY = p.mouseY;
    
    // Update growth phase for evolving patterns
    growthPhase = (time * 0.002) % (p.TWO_PI * 2);
    
    // Dynamic recursion depth based on time and interaction
    recursionDepth = 5 + Math.floor(p.sin(time * 0.001) * 2) + Math.floor(mouseInfluence * 0.1);
    recursionDepth = p.constrain(recursionDepth, 4, 8);
    
    // Clear layers
    layer1Buffer.clear();
    layer2Buffer.clear();
    layer3Buffer.clear();
    compositeBuffer.clear();
    
    // Draw to layer buffers
    drawLayer1();
    drawLayer2();
    drawLayer3();
    
    // Composite all layers
    compositeBuffer.image(bgBuffer, 0, 0);
    compositeBuffer.blendMode(p.ADD);
    compositeBuffer.image(layer1Buffer, 0, 0);
    compositeBuffer.image(layer2Buffer, 0, 0);
    compositeBuffer.blendMode(p.BLEND);
    compositeBuffer.image(layer3Buffer, 0, 0);
    
    // Apply final compositing to main canvas
    p.image(bgBuffer, 0, 0);
    p.blendMode(p.ADD);
    p.image(layer1Buffer, 0, 0);
    p.image(layer2Buffer, 0, 0);
    p.blendMode(p.SCREEN);
    p.image(layer3Buffer, 0, 0);
    p.blendMode(p.BLEND);
    
    // Apply bloom effect via pixel manipulation
    applyBloomEffect();
    
    // Draw UI hint
    drawUIHints();
  };
  
  function drawLayer1() {
    layer1Buffer.noStroke();
    
    // Central Flower of Life pattern with interference
    let baseRadius = p.min(p.width, p.height) * 0.35;
    let numCircles = 7;
    
    // Draw multiple flower of life instances
    let flowerCenters = [
      { x: p.width / 2, y: p.height / 2, r: baseRadius, speed: 1 },
      { x: p.width * 0.3 + p.sin(time * 0.003) * 50, y: p.height * 0.35, r: baseRadius * 0.4, speed: 1.5 },
      { x: p.width * 0.7 + p.cos(time * 0.003) * 50, y: p.height * 0.65, r: baseRadius * 0.5, speed: 0.8 }
    ];
    
    for (let f = 0; f < flowerCenters.length; f++) {
      let fc = flowerCenters[f];
      
      // Apply mouse influence
      let mouseDist = p.dist(p.mouseX, p.mouseY, fc.x, fc.y);
      if (mouseDist < interactionRadius) {
        let influence = 1 - mouseDist / interactionRadius;
        fc.r *= (1 + influence * 0.2);
      }
      
      drawFlowerOfLifeLayer(layer1Buffer, fc.x, fc.y, fc.r, numCircles, 0.4 + p.sin(time * 0.01 + f) * 0.1);
    }
    
    // L-system growth patterns
    let sentence = generateLSystemSentence(recursionDepth);
    
    let lSysCenters = [
      { x: p.width * 0.2, y: p.height * 0.3 },
      { x: p.width * 0.8, y: p.height * 0.7 },
      { x: p.width * 0.5, y: p.height * 0.15 }
    ];
    
    for (let i = 0; i < lSysCenters.length; i++) {
      let lc = lSysCenters[i];
      let offset = i * 50 + Math.floor(time * 0.03) % 100;
      drawLSystemToBuffer(layer1Buffer, lc.x, lc.y, sentence, recursionDepth, offset);
    }
    
    // Add interference rings
    layer1Buffer.noFill();
    for (let i = 0; i < 5; i++) {
      let radius = p.min(p.width, p.height) * (0.2 + i * 0.15);
      let interference = p.sin(time * 0.02 + i * 0.5) * 0.5 + 0.5;
      let colorIdx = i % bismuthPalette.length;
      let col = bismuthPalette[colorIdx];
      
      layer1Buffer.stroke(red(col), green(col), blue(col), 0.15 * interference);
      layer1Buffer.strokeWeight(1 + interference);
      
      layer1Buffer.beginShape();
      for (let a = 0; a < p.TWO_PI; a += 0.05) {
        let wave = p.sin(a * 6 + time * 0.05 + i) * 10;
        let r = radius + wave;
        layer1Buffer.vertex(p.width / 2 + p.cos(a) * r, p.height / 2 + p.sin(a) * r);
      }
      layer1Buffer.endShape(p.CLOSE);
    }
    
    layer1Buffer.noStroke();
  }
  
  function drawLayer2() {
    layer2Buffer.noStroke();
    
    // Vesica layers with organic growth
    let numVesica = 8;
    for (let i = 0; i < numVesica; i++) {
      let angle = (i / numVesica) * p.TWO_PI + time * 0.001;
      let distance = p.min(p.width, p.height) * (0.2 + p.sin(time * 0.002 + i) * 0.1);
      let cx = p.width / 2 + p.cos(angle) * distance;
      let cy = p.height / 2 + p.sin(angle) * distance;
      let size = p.min(p.width, p.height) * (0.1 + i * 0.02);
      
      // Mouse interaction
      let mouseDist = p.dist(p.mouseX, p.mouseY, cx, cy);
      if (mouseDist < interactionRadius * 0.7) {
        size *= 1.3;
      }
      
      drawVesicaLayer(layer2Buffer, cx, cy, size, i * p.PI / 4);
    }
    
    // Cellular automaton grid pattern
    drawCellularAutomaton(layer2Buffer, p.width / 2, p.height / 2, p.min(p.width, p.height) * 0.3);
    
    // Fractal interference branches
    for (let i = 0; i < 6; i++) {
      let angle = (i / 6) * p.TWO_PI + time * 0.0008;
      let startX = p.width / 2 + p.cos(angle) * p.min(p.width, p.height) * 0.3;
      let startY = p.height / 2 + p.sin(angle) * p.min(p.height, p.width) * 0.3;
      
      drawInterferenceBranch(layer2Buffer, startX, startY, angle, 150, 5);
    }
  };
  
  function drawInterferenceBranch(buffer, x, y, angle, length, depth) {
    if (depth <= 0 || length < 5) return;
    
    let interference = p.sin(time * 0.03 + depth * 0.5) * 0.5 + 0.5;
    let colorIdx = depth % bismuthPalette.length;
    let col = bismuthPalette[colorIdx];
    
    let newLength = length * 0.7;
    
    // Draw main branch with interference wave
    let endX = x + p.cos(angle) * length;
    let endY = y + p.sin(angle) * length;
    
    buffer.stroke(red(col), green(col), blue(col), 0.3 * interference);
    buffer.strokeWeight(depth * 0.5);
    buffer.noFill();
    
    buffer.beginShape();
    for (let t = 0; t <= 1; t += 0.05) {
      let px = x + (endX - x) * t;
      let py = y + (endY - y) * t;
      let wave = p.sin(t * p.PI * 4 + time * 0.05) * 5 * interference;
      let perpX = -p.sin(angle) * wave;
      let perpY = p.cos(angle) * wave;
      buffer.vertex(px + perpX, py + perpY);
    }
    buffer.endShape();
    
    // Recursive branches
    let numBranches = 2 + Math.floor(interference * 2);
    for (let b = 0; b < numBranches; b++) {
      let branchAngle = angle + (b - numBranches / 2) * (p.PI / 6) + interference * 0.3;
      let branchStartRatio = 0.5 + p.random() * 0.3;
      let bx = x + (endX - x) * branchStartRatio;
      let by = y + (endY - y) * branchStartRatio;
      
      drawInterferenceBranch(buffer, bx, by, branchAngle, newLength, depth - 1);
    }
  }
  
  function drawLayer3() {
    layer3Buffer.noStroke();
    
    // Glowing focal points with interference halos
    let focalPoints = [
      { x: p.width * 0.25, y: p.height * 0.25, size: 30 },
      { x: p.width * 0.75, y: p.height * 0.75, size: 25 },
      { x: p.width * 0.7, y: p.height * 0.25, size: 35 },
      { x: p.width * 0.3, y: p.height * 0.75, size: 20 },
      { x: p.width * 0.5, y: p.height * 0.5, size: 40 }
    ];
    
    for (let fp of focalPoints) {
      // Apply mouse influence to size
      let mouseDist = p.dist(p.mouseX, p.mouseY, fp.x, fp.y);
      let sizeMultiplier = mouseDist < interactionRadius ? 1.5 : 1;
      let actualSize = fp.size * sizeMultiplier;
      
      // Draw interference halo rings
      for (let r = 5; r >= 0; r--) {
        let ringRadius = actualSize * (1 + r * 0.8);
        let interference = p.sin(time * 0.04 + r * 0.3) * 0.5 + 0.5;
        let alpha = 0.1 * interference / (r + 1);
        
        let colorIdx = (r + Math.floor(time * 0.02)) % bismuthPalette.length;
        let col = bismuthPalette[colorIdx];
        
        layer3Buffer.fill(red(col), green(col), blue(col), alpha);
        
        layer3Buffer.beginShape();
        for (let a = 0; a < p.TWO_PI; a += 0.1) {
          let wave = p.sin(a * 8 + time * 0.05 + r) * actualSize * 0.2;
          let rx = fp.x + p.cos(a) * (ringRadius + wave);
          let ry = fp.y + p.sin(a) * (ringRadius + wave);
          layer3Buffer.vertex(rx, ry);
        }
        layer3Buffer.endShape(p.CLOSE);
      }
      
      // Central glow point
      let centralInterference = p.sin(time * 0.06) * 0.5 + 0.5;
      for (let g = 4; g >= 0; g--) {
        let gSize = actualSize * (0.2 + g * 0.15);
        let gAlpha = 0.5 * centralInterference / (g + 1);
        
        let gc = bismuthPalette[Math.floor(time * 0.01 + g) % bismuthPalette.length];
        layer3Buffer.fill(red(gc), green(gc), blue(gc), gAlpha);
        layer3Buffer.ellipse(fp.x, fp.y, gSize, gSize);
      }
    }
    
    // Central consciousness core with recursive geometry
    drawConsciousnessCore(layer3Buffer, p.width / 2, p.height / 2, 80);
  }
  
  function drawConsciousnessCore(buffer, cx, cy, size) {
    buffer.push();
    buffer.translate(cx, cy);
    buffer.rotate(time * 0.001);
    
    // Recursive sacred geometry - Metatron's Cube inspired
    let layers = 4;
    for (let layer = 0; layer < layers; layer++) {
      let layerSize = size * (1 - layer * 0.2);
      let rotation = layer * p.PI / 8 + time * 0.002;
      
      // Draw geometric forms
      let interference = p.sin(time * 0.03 + layer * 0.5) * 0.5 + 0.5;
      let colorIdx = (layer + Math.floor(time * 0.015)) % bismuthPalette.length;
      let col = bismuthPalette[colorIdx];
      
      buffer.rotate(rotation);
      
      // Flower of life within each layer
      for (let i = 0; i < 6; i++) {
        let angle = (i / 6) * p.TWO_PI;
        let px = p.cos(angle) * layerSize * 0.5;
        let py = p.sin(angle) * layerSize * 0.5;
        
        buffer.noFill();
        buffer.stroke(red(col), green(col), blue(col), 0.2 * interference);
        buffer.strokeWeight(1 + layer * 0.5);
        
        let petalSize = layerSize * 0.4;
        buffer.ellipse(px, py, petalSize, petalSize * 1.5);
      }
      
      // Connect with lines
      buffer.stroke(red(col), green(col), blue(col), 0.15 * interference);
      buffer.strokeWeight(0.5);
      for (let i = 0; i < 6; i++) {
        let angle = (i / 6) * p.TWO_PI;
        let x1 = p.cos(angle) * layerSize * 0.5;
        let y1 = p.sin(angle) * layerSize * 0.5;
        
        for (let j = i + 1; j < 6; j++) {
          let angle2 = (j / 6) * p.TWO_PI;
          let x2 = p.cos(angle2) * layerSize * 0.5;
          let y2 = p.sin(angle2) * layerSize * 0.5;
          buffer.line(x1, y1, x2, y2);
        }
      }
      
      buffer.rotate(-rotation);
    }
    
    // Central vortex
    let vortexInterference = p.sin(time * 0.08) * 0.5 + 0.5;
    let vortexColor = bismuthPalette[Math.floor(time * 0.02) % bismuthPalette.length];
    
    buffer.noStroke();
    for (let i = 5; i >= 0; i--) {
      let spiralRadius = size * 0.15 * (1 - i * 0.15);
      buffer.fill(red(vortexColor), green(vortexColor), blue(vortexColor), 0.4 * vortexInterference / (i + 1));
      
      buffer.beginShape();
      for (let a = 0; a < p.TWO_PI * 2; a += 0.1) {
        let r = spiralRadius * (1 - a / (p.TWO_PI * 4));
        let x = p.cos(a + time * 0.02) * r;
        let y = p.sin(a + time * 0.02) * r;
        buffer.vertex(x, y);
      }
      buffer.endShape();
    }
    
    buffer.pop();
  }
  
  function applyBloomEffect() {
    // Apply subtle bloom via additive overlay
    p.blendMode(p.ADD);
    p.fill(255, 240, 200, 0.03);
    p.ellipse(p.width / 2, p.height / 2, p.min(p.width, p.height) * 0.8, p.min(p.width, p.height) * 0.8);
    p.blendMode(p.BLEND);
  }
  
  function drawUIHints() {
    // Subtle UI hints
    p.fill(255, 255, 255, 0.3);
    p.textSize(10);
    p.textAlign(p.LEFT, p.BOTTOM);
    p.text('Move: Influence patterns | Click: Pulse | 1-5: Modes | R: Reset', 10, p.height - 10);
  }
  
  // Mouse interaction - continuous influence on patterns
  p.mouseMoved = function() {
    // Continuous mouse influence handled in draw loop
  };
  
  // Mouse click - trigger distinct visual event (pulse burst)
  p.mousePressed = function() {
    // Create pulse effect at mouse position
    let pulseX = p.mouseX;
    let pulseY = p.mouseY;
    
    // Flash effect
    p.fill(255, 255, 255, 0.2);
    p.noStroke();
    p.ellipse(pulseX, pulseY, 100, 100);
    
    // Temporarily boost recursion depth
    recursionDepth = p.min(recursionDepth + 2, 9);
  };
  
  // Keyboard interaction - toggle modes and reset
  p.keyPressed = function() {
    if (p.key === '1') {
      mode = 0; // Standard
    } else if (p.key === '2') {
      mode = 1; // Intense
    } else if (p.key === '3') {
      mode = 2; // Flowing
    } else if (p.key === '4') {
      mode = 3; // Crystalline
    } else if (p.key === '5') {
      mode = 4; // Organic
    } else if (p.key === 'r' || p.key === 'R') {
      // Reset with flash
      time = 0;
      growthPhase = 0;
      initLSystemRules();
    }
    
    // Update L-system parameters based on mode
    updateModeParameters();
  };
  
  function updateModeParameters() {
    switch(mode) {
      case 0: // Standard
        lSysRules.angle = 25.7;
        lSysRules.startLength = 8;
        break;
      case 1: // Intense
        lSysRules.angle = 30;
        lSysRules.startLength = 10;
        break;
      case 2: // Flowing
        lSysRules.angle = 20;
        lSysRules.startLength = 6;
        break;
      case 3: // Crystalline
        lSysRules.angle = 36;
        lSysRules.startLength = 7;
        break;
      case 4: // Organic
        lSysRules.angle = 22.5;
        lSysRules.startLength = 9;
        break;
    }
  }
  
  // Responsive canvas sizing
  p.windowResized = function() {
    let container = document.getElementById('p5-wrapper');
    p.resizeCanvas(container.offsetWidth, container.offsetHeight);
    
    // Recreate buffers at new size
    bgBuffer = p.createGraphics(p.width, p.height);
    layer1Buffer = p.createGraphics(p.width, p.height);
    layer2Buffer = p.createGraphics(p.width, p.height);
    layer3Buffer = p.createGraphics(p.width, p.height);
    compositeBuffer = p.createGraphics(p.width, p.height);
    
    drawBackground();
  };
};

✨ AI 艺术解读

This artwork represents the emergence of consciousness from simple cellular rules into complex sacred geometry — the digital equivalent of bismuth crystal formation where ordered patterns arise from chaotic growth. The Flower of Life motif emerges organically from recursive L-system iterations, suggesting that fundamental geometric truths are bred into reality through iterative processes. The interference patterns create a visual metaphor for how individual consciousness threads combine into collective understanding, while the dark void background evokes the infinite potential from which all form emerges. The piece invites contemplation on the recursive nature of existence itself.

📝 补充说明

  • L-system sentences are pre-generated once per mode change, not per frame, for computational efficiency
  • Interference calculations use multiple overlapping wave functions to create organic, non-repetitive patterns
  • Mouse influence uses distance-based falloff with configurable radius for smooth interaction gradients
  • Blend modes (ADD, SCREEN) create luminous depth impossible with single-layer alpha blending
  • Recursion depth dynamically adjusts between 4-9 levels based on time phase and user interaction intensity
  • Buffer clearing uses p.clear() instead of background() to preserve transparency for compositing
  • Keyboard modes 1-5 change L-system angle (20-36 degrees) and segment length (6-10 pixels) for visual variety
  • Flower of Life centers placed at golden ratio distances for aesthetically pleasing composition
  • Hexagonal cell grid simulates cellular automaton behavior with multi-source wave propagation
  • Each layer uses different drawing primitives (ellipse, beginShape, line) for visual diversity within unified palette