Celestial Loom: Kinetic Resonance

📅 April 17, 2026 🏷️ art
generative gravity n-body orbital kinetic physics-art trails
Generated by GridFlow AI | Tags: generative, gravity, n-body, orbital, kinetic, physics-art, trails

📊 视觉感受量化评分

0
0
0
0

💡 AI 提示词

p5.js instance mode generative art simulating gravitational N-body systems with luminous trails, multi-attractor dynamics, responsive resizing, and kinetic color shifts.

🧠 核心算法要点

  • Initialize a swarm of 1200 particles with randomized starting vectors and individual color ranges.
  • Generate a set of invisible attractor points that exert an inverse-square law gravitational pull on the particles.
  • Calculate the force vector for each particle-attractor pair, using a softening constant to prevent infinite acceleration at zero distance.
  • Apply Newton's Second Law (F=ma) to derive acceleration, updating velocity and position per frame.
  • Use a recursive background fade (alpha transparency) to preserve path history, creating a motion blur or light-trail effect.
  • Map the magnitude of each particle's velocity to its stroke hue, shifting colors as particles accelerate toward masses.
  • Incorporate a dynamic user-controlled attractor linked to mouse coordinates for real-time orbital manipulation.

💻 原始 p5.js 代码

var sketch = function(p) {
    let particles = [];
    let attractors = [];
    const particleCount = 1200;
    const attractorCount = 4;
    let G = 1.2;

    p.setup = function() {
        let container = document.getElementById('p5-wrapper'); let canvas = p.createCanvas(container.offsetWidth, container.offsetHeight).parent('p5-wrapper');
        p.colorMode(p.HSB, 360, 100, 100, 1);
        p.background(240, 20, 5, 1);
        initSystem();
    };

    function initSystem() {
        particles = [];
        attractors = [];
        for (let i = 0; i < particleCount; i++) {
            particles.push(new Particle());
        }
        for (let i = 0; i < attractorCount; i++) {
            attractors.push(p.createVector(p.random(p.width), p.random(p.height)));
        }
    }

    p.draw = function() {
        // Low alpha background creates the long-exposure trail effect
        p.noStroke();
        p.fill(240, 30, 3, 0.04);
        p.rect(0, 0, p.width, p.height);

        // Update the first attractor to the mouse position
        if (p.mouseIsPressed) {
            attractors[0].set(p.mouseX, p.mouseY);
        } else {
            // Auto-orbiting movement for attractors when not interacting
            attractors[0].x = p.width/2 + p.sin(p.frameCount * 0.01) * (p.width * 0.3);
            attractors[0].y = p.height/2 + p.cos(p.frameCount * 0.015) * (p.height * 0.3);
        }

        particles.forEach(pt => {
            attractors.forEach(at => {
                pt.applyGravity(at);
            });
            pt.update();
            pt.display();
        });
    };

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

        reset() {
            this.pos = p.createVector(p.random(p.width), p.random(p.height));
            this.vel = p.createVector(p.random(-1, 1), p.random(-1, 1));
            this.acc = p.createVector(0, 0);
            this.maxSpeed = p.random(2, 5);
            this.hue = p.random(180, 300);
            this.history = [];
        }

        applyGravity(target) {
            let force = p5.Vector.sub(target, this.pos);
            let distanceSq = force.magSq();
            distanceSq = p.constrain(distanceSq, 100, 1500); // Softening parameter
            let strength = G / distanceSq;
            force.setMag(strength * 50);
            this.acc.add(force);
        }

        update() {
            this.vel.add(this.acc);
            this.vel.limit(this.maxSpeed);
            this.pos.add(this.vel);
            this.acc.mult(0);

            // Wrap around edges
            if (this.pos.x < 0) this.pos.x = p.width;
            if (this.pos.x > p.width) this.pos.x = 0;
            if (this.pos.y < 0) this.pos.y = p.height;
            if (this.pos.y > p.height) this.pos.y = 0;
        }

        display() {
            let speed = this.vel.mag();
            let dynamicHue = p.map(speed, 0, this.maxSpeed, this.hue, this.hue + 60);
            p.stroke(dynamicHue, 80, 100, 0.6);
            p.strokeWeight(1.5);
            p.point(this.pos.x, this.pos.y);
        }
    }

    p.windowResized = function() {
        let container = document.getElementById('p5-wrapper'); p.resizeCanvas(container.offsetWidth, container.offsetHeight);
        p.background(240, 20, 5, 1);
        initSystem();
    };
};
new p5(sketch);

🎨 AI 艺术解读

Celestial Loom explores the visualization of invisible forces that dictate the movement of the cosmos. By rendering gravitational interactions as neon light trails, the piece reveals the hidden geometric elegance of chaotic systems. Each particle's path is a unique reaction to a multi-body gravity field, showing how deterministic laws can lead to organic, unpredictable patterns. It invites the viewer to interact with the void, reshaping the 'loom' through touch and motion.

📝 补充说明

  • Distance squaring (magSq) is used instead of square roots for performance optimization during force calculation.
  • The softening parameter in the gravity formula (constrain) is vital to keep particles from being slingshot out of the viewport at extreme speeds.
  • HSB color mode is utilized to create a more natural transition between the cool violets of slow orbits and the hot teals of high-velocity passes.
  • The background clearing uses a very low alpha (0.04) which creates a 'memory' effect, where older paths slowly dissolve into the deep space background.