Aetheric Drift

📅 April 17, 2026 🏷️ art
atmospheric perlin-noise particles ethereal minimalist dynamic-flow generative
Generated by GridFlow AI | Tags: atmospheric, perlin-noise, particles, ethereal, minimalist, dynamic-flow, generative

📊 视觉感受量化评分

0
0
0
0

💡 AI 提示词

Create an atmospheric particle system in p5.js using Perlin noise flow fields, soft glow effects, and organic movement patterns that respond to the mouse.

🧠 核心算法要点

  • Initialize a particle system where each agent possesses position, velocity, and life properties.
  • Generate a flow field using 3D Perlin noise (x, y, and time) to dictate particle heading.
  • Apply a cumulative acceleration model to create smooth, fluid-like motion.
  • Implement a 'ghosting' effect by drawing a semi-transparent rectangle over the canvas each frame instead of clearing it.
  • Utilize the browser's native shadowBlur API via drawingContext for soft-light particle rendering.
  • Calculate particle lifespan decay and respawn agents to ensure a continuous, evolving atmosphere.
  • Incorporate a mouse-proximity repulsion force to allow users to 'brush' through the atmospheric dust.

💻 原始 p5.js 代码

var sketch = function(p) {
    let particles = [];
    const PARTICLE_COUNT = 150;
    const NOISE_SCALE = 0.002;
    let colorPalette;

    p.setup = function() {
        let container = document.getElementById('p5-wrapper'); let canvas = p.createCanvas(container.offsetWidth, container.offsetHeight).parent('p5-wrapper');
        p.background(10, 12, 18);
        colorPalette = [
            p.color(100, 150, 255, 150), // Soft Blue
            p.color(180, 100, 255, 120), // Ethereal Purple
            p.color(255, 255, 255, 80),  // Ghostly White
            p.color(50, 200, 220, 100)   // Teal Glow
        ];
        
        for (let i = 0; i < PARTICLE_COUNT; i++) {
            particles.push(new Particle());
        }
    };

    p.draw = function() {
        // Create a faint trail effect
        p.fill(10, 12, 18, 25);
        p.rect(0, 0, p.width, p.height);

        particles.forEach(part => {
            part.update();
            part.display();
        });
    };

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

    class Particle {
        constructor() {
            this.init();
        }

        init() {
            this.pos = p.createVector(p.random(p.width), p.random(p.height));
            this.vel = p.createVector(0, 0);
            this.acc = p.createVector(0, 0);
            this.maxSpeed = p.random(1, 3);
            this.size = p.random(2, 8);
            this.col = p.random(colorPalette);
            this.noiseOffset = p.random(1000);
            this.life = p.random(100, 255);
            this.decay = p.random(0.5, 2);
        }

        update() {
            // Perlin noise flow field movement
            let angle = p.noise(this.pos.x * NOISE_SCALE, this.pos.y * NOISE_SCALE, p.frameCount * 0.005) * p.TWO_PI * 2;
            let force = p5.Vector.fromAngle(angle);
            force.mult(0.1);
            this.acc.add(force);

            // Interaction with mouse
            let mouseDist = p.dist(p.mouseX, p.mouseY, this.pos.x, this.pos.y);
            if (mouseDist < 200) {
                let repulsion = p.createVector(this.pos.x - p.mouseX, this.pos.y - p.mouseY);
                repulsion.normalize();
                repulsion.mult(0.2);
                this.acc.add(repulsion);
            }

            this.vel.add(this.acc);
            this.vel.limit(this.maxSpeed);
            this.pos.add(this.vel);
            this.acc.mult(0);
            this.life -= this.decay;

            // Respawn logic
            if (this.life <= 0 || this.pos.x < 0 || this.pos.x > p.width || this.pos.y < 0 || this.pos.y > p.height) {
                this.init();
                this.pos = p.createVector(p.random(p.width), p.random(p.height));
            }
        }

        display() {
            p.push();
            p.noStroke();
            // Glow effect using shadowBlur
            p.drawingContext.shadowBlur = this.size * 2;
            p.drawingContext.shadowColor = this.col.toString();
            
            let currentAlpha = p.map(this.life, 0, 255, 0, p.alpha(this.col));
            let c = p.color(p.red(this.col), p.green(this.col), p.blue(this.col), currentAlpha);
            p.fill(c);
            p.ellipse(this.pos.x, this.pos.y, this.size);
            p.pop();
        }
    }
};
new p5(sketch);

🎨 AI 艺术解读

Aetheric Drift captures the sensation of microscopic dust motes suspended in a shaft of light. It represents the unseen currents of air and energy that surround us, turning cold mathematical noise into a warm, breathing environment. The soft glows and fading trails evoke a sense of memory and the transience of physical forms. By interacting with the piece, the viewer becomes a gust of wind, disrupting the silent harmony of the digital void.

📝 补充说明

  • The use of p.drawingContext.shadowBlur provides a high-quality glow but can be performance-heavy on older mobile devices.
  • Alpha blending in the background (p.fill(10, 12, 18, 25)) is what creates the long, wispy tails of the particles.
  • Instance mode is used to ensure the sketch can be safely embedded without polluting the global namespace.
  • The particles respawn with randomized life values to prevent them all disappearing and reappearing simultaneously.