// Global variables let bodies = []; let shapes = []; let currentShape = 0; let nextShape = 1; let transition = 0; let trails = [[], [], []]; // Store trail history for each body const maxTrailLength = 400; // Length of visible trails const transitionSpeed = 0.0004; // Much slower transitions to see orbits develop const G = 10; // Simplified gravitational constant const dt = 0.0008; // Time step const scale = 130; // Scale for visualization const maxRadius = 2.5; // Maximum allowed radius from center function setup() { createCanvas(800, 600); shapes = [ // Original Shape 0: Figure-eight inspired [ { pos: createVector(-1, 0), vel: createVector(0, 0.5) }, { pos: createVector(1, 0), vel: createVector(0, -0.5) }, { pos: createVector(0, 0), vel: createVector(0.5, 0) } ], // Original Shape 1: Equilateral triangle [ { pos: createVector(-1, -0.577), vel: createVector(0, 0.5) }, { pos: createVector(1, -0.577), vel: createVector(0, 0.5) }, { pos: createVector(0, 1), vel: createVector(0, -1) } ], // Original Shape 2: Linear arrangement [ { pos: createVector(-1.5, 0), vel: createVector(0, 0.4) }, { pos: createVector(0, 0), vel: createVector(0, 0) }, { pos: createVector(1.5, 0), vel: createVector(0, -0.4) } ], // Original Shape 3: Tight triangle [ { pos: createVector(-0.5, -0.289), vel: createVector(0, 0.3) }, { pos: createVector(0.5, -0.289), vel: createVector(0, 0.3) }, { pos: createVector(0, 0.577), vel: createVector(0, -0.6) } ], // Original Shape 4: Wide figure-eight [ { pos: createVector(-1.5, 0), vel: createVector(0, 0.6) }, { pos: createVector(1.5, 0), vel: createVector(0, -0.6) }, { pos: createVector(0, 0.5), vel: createVector(0.6, 0) } ], // Original Shape 5: Scalene triangle [ { pos: createVector(-1, -0.3), vel: createVector(0, 0.4) }, { pos: createVector(0.8, -0.2), vel: createVector(0, 0.4) }, { pos: createVector(0, 0.8), vel: createVector(0, -0.8) } ], // Original Shape 6: Offset figure-eight [ { pos: createVector(-1.2, 0.2), vel: createVector(0, 0.5) }, { pos: createVector(1.2, 0.2), vel: createVector(0, -0.5) }, { pos: createVector(0, -0.4), vel: createVector(0.5, 0) } ], // Original Shape 7: Isosceles triangle [ { pos: createVector(-0.8, -0.4), vel: createVector(0, 0.5) }, { pos: createVector(0.8, -0.4), vel: createVector(0, 0.5) }, { pos: createVector(0, 0.8), vel: createVector(0, -1) } ], // Original Shape 8: Vertical alignment [ { pos: createVector(0, -1), vel: createVector(0.4, 0) }, { pos: createVector(0, 0), vel: createVector(0, 0) }, { pos: createVector(0, 1), vel: createVector(-0.4, 0) } ], // Original Shape 9: Wide triangle [ { pos: createVector(-1.2, -0.7), vel: createVector(0, 0.6) }, { pos: createVector(1.2, -0.7), vel: createVector(0, 0.6) }, { pos: createVector(0, 1.4), vel: createVector(0, -1.2) } ], // New Shape 10: Butterfly I inspired [ { pos: createVector(-1, 0), vel: createVector(0, 0.4) }, { pos: createVector(1, 0), vel: createVector(0, -0.4) }, { pos: createVector(0, 0.5), vel: createVector(0.5, 0) } ], // New Shape 11: Butterfly II inspired [ { pos: createVector(-1.1, 0.1), vel: createVector(0.1, 0.5) }, { pos: createVector(1.1, 0.1), vel: createVector(-0.1, -0.5) }, { pos: createVector(0, -0.5), vel: createVector(0.4, 0) } ], // New Shape 12: Dragonfly inspired [ { pos: createVector(-1.3, 0), vel: createVector(0, 0.6) }, { pos: createVector(1.3, 0), vel: createVector(0, -0.6) }, { pos: createVector(0, 0.3), vel: createVector(0.5, 0) } ], // New Shape 13: Yin-Yang I inspired [ { pos: createVector(-0.9, -0.5), vel: createVector(0.2, 0.4) }, { pos: createVector(0.9, -0.5), vel: createVector(-0.2, 0.4) }, { pos: createVector(0, 1.0), vel: createVector(0, -0.8) } ], // New Shape 14: Moth I inspired [ { pos: createVector(-1.0, -0.2), vel: createVector(0, 0.3) }, { pos: createVector(1.0, -0.2), vel: createVector(0, 0.3) }, { pos: createVector(0, 0.6), vel: createVector(0, -0.6) } ], // New Shape 15: Butterfly III inspired [ { pos: createVector(-1.4, 0.2), vel: createVector(0.1, 0.5) }, { pos: createVector(1.4, 0.2), vel: createVector(-0.1, -0.5) }, { pos: createVector(0, -0.6), vel: createVector(0.6, 0) } ], // New Shape 16: Moth III inspired [ { pos: createVector(-0.6, -0.3), vel: createVector(0, 0.4) }, { pos: createVector(0.6, -0.3), vel: createVector(0, 0.4) }, { pos: createVector(0, 0.7), vel: createVector(0, -0.8) } ], // New Shape 17: Yarn inspired [ { pos: createVector(-1.5, -0.1), vel: createVector(0, 0.5) }, { pos: createVector(1.5, -0.1), vel: createVector(0, -0.5) }, { pos: createVector(0, 0.4), vel: createVector(0.5, 0) } ], // New Shape 18: Yin-Yang II inspired [ { pos: createVector(-1.0, -0.6), vel: createVector(0.3, 0.5) }, { pos: createVector(1.0, -0.6), vel: createVector(-0.3, 0.5) }, { pos: createVector(0, 1.2), vel: createVector(0, -1.0) } ], // New Shape 19: Cloverleaf inspired [ { pos: createVector(-1.2, -0.4), vel: createVector(0, 0.4) }, { pos: createVector(1.2, -0.4), vel: createVector(0, 0.4) }, { pos: createVector(0, 0.8), vel: createVector(0, -0.8) } ], // New Shape 20: Goggles inspired [ { pos: createVector(-1.1, 0), vel: createVector(0, 0.5) }, { pos: createVector(1.1, 0), vel: createVector(0, -0.5) }, { pos: createVector(0, 0.2), vel: createVector(0.4, 0) } ], // New Shape 21: Broucke inspired [ { pos: createVector(-1.3, 0.3), vel: createVector(0.2, 0.4) }, { pos: createVector(1.3, 0.3), vel: createVector(-0.2, -0.4) }, { pos: createVector(0, -0.6), vel: createVector(0.5, 0) } ], // New Shape 22: Hénon inspired [ { pos: createVector(-0.8, -0.5), vel: createVector(0, 0.6) }, { pos: createVector(0.8, -0.5), vel: createVector(0, 0.6) }, { pos: createVector(0, 1.0), vel: createVector(0, -1.2) } ], // New Shape 23: Circular orbit inspired [ { pos: createVector(-1, 0), vel: createVector(0, 0.577) }, { pos: createVector(0.5, 0.866), vel: createVector(-0.5, -0.289) }, { pos: createVector(0.5, -0.866), vel: createVector(0.5, -0.289) } ], // New Shape 24: Collinear Euler 1 inspired [ { pos: createVector(-1.5, 0), vel: createVector(0, 0) }, { pos: createVector(0, 0), vel: createVector(0, 0) }, { pos: createVector(1.5, 0), vel: createVector(0, 0) } ], // New Shape 25: Collinear Euler 2 inspired [ { pos: createVector(-1.2, 0), vel: createVector(0, 0) }, { pos: createVector(-0.3, 0), vel: createVector(0, 0) }, { pos: createVector(1.5, 0), vel: createVector(0, 0) } ], // New Shape 26: Collinear Euler 3 inspired [ { pos: createVector(-1.0, 0), vel: createVector(0, 0) }, { pos: createVector(0.5, 0), vel: createVector(0, 0) }, { pos: createVector(1.5, 0), vel: createVector(0, 0) } ], // New Shape 27: Halo orbit inspired [ { pos: createVector(-0.8, -0.2), vel: createVector(0.1, 0.3) }, { pos: createVector(0.8, -0.2), vel: createVector(-0.1, 0.3) }, { pos: createVector(0, 0.5), vel: createVector(0, -0.6) } ], // New Shape 28: Lyapunov orbit inspired [ { pos: createVector(-1.0, 0.1), vel: createVector(0, 0.4) }, { pos: createVector(1.0, 0.1), vel: createVector(0, -0.4) }, { pos: createVector(0, -0.3), vel: createVector(0.4, 0) } ], // New Shape 29: Pretzel inspired [ { pos: createVector(-1.4, 0), vel: createVector(0, 0.5) }, { pos: createVector(1.4, 0), vel: createVector(0, -0.5) }, { pos: createVector(0, 0.4), vel: createVector(0.5, 0) } ], // NEW RANDOM Shape 30: Asymmetric spiral [ { pos: createVector(-1.3, -0.8), vel: createVector(0.3, 0.6) }, { pos: createVector(0.7, 0.9), vel: createVector(-0.4, -0.3) }, { pos: createVector(0.6, -0.4), vel: createVector(0.2, 0.5) } ], // NEW RANDOM Shape 31: Chaotic triangle [ { pos: createVector(-1.6, 0.3), vel: createVector(0.1, 0.7) }, { pos: createVector(1.4, -0.5), vel: createVector(-0.3, 0.4) }, { pos: createVector(0.2, 1.1), vel: createVector(0.4, -0.9) } ], // NEW RANDOM Shape 32: Offset orbit [ { pos: createVector(-0.7, 1.2), vel: createVector(0.5, -0.2) }, { pos: createVector(1.3, -0.3), vel: createVector(-0.6, 0.5) }, { pos: createVector(-0.4, -0.9), vel: createVector(0.3, 0.4) } ], // NEW RANDOM Shape 33: Wild dance [ { pos: createVector(-1.1, -1.0), vel: createVector(0.6, 0.3) }, { pos: createVector(0.9, 0.8), vel: createVector(-0.2, -0.6) }, { pos: createVector(0.3, 0.2), vel: createVector(0.4, 0.5) } ], // NEW RANDOM Shape 34: Eccentric orbit [ { pos: createVector(-1.5, 0.6), vel: createVector(0.2, 0.5) }, { pos: createVector(1.2, 0.4), vel: createVector(-0.5, -0.4) }, { pos: createVector(0.1, -1.0), vel: createVector(0.6, 0.3) } ], // NEW RANDOM Shape 35: Twisted path [ { pos: createVector(-0.9, -0.7), vel: createVector(0.4, 0.7) }, { pos: createVector(1.1, 0.5), vel: createVector(-0.3, -0.5) }, { pos: createVector(-0.2, 0.9), vel: createVector(0.5, -0.4) } ], // NEW RANDOM Shape 36: Diagonal sweep [ { pos: createVector(-1.4, -0.9), vel: createVector(0.5, 0.5) }, { pos: createVector(0.8, 1.0), vel: createVector(-0.4, -0.6) }, { pos: createVector(0.5, -0.3), vel: createVector(0.3, 0.6) } ], // NEW RANDOM Shape 37: Random chaos [ { pos: createVector(-1.0, 0.8), vel: createVector(0.6, -0.3) }, { pos: createVector(1.3, -0.7), vel: createVector(-0.5, 0.6) }, { pos: createVector(-0.5, -0.2), vel: createVector(0.4, 0.4) } ], // NEW RANDOM Shape 38: Scattered formation [ { pos: createVector(-1.2, 1.1), vel: createVector(0.3, -0.5) }, { pos: createVector(1.5, 0.2), vel: createVector(-0.6, 0.3) }, { pos: createVector(-0.3, -1.2), vel: createVector(0.5, 0.7) } ], // NEW RANDOM Shape 39: Extreme orbit [ { pos: createVector(-1.6, -0.4), vel: createVector(0.7, 0.4) }, { pos: createVector(0.9, 1.2), vel: createVector(-0.3, -0.7) }, { pos: createVector(0.4, -0.8), vel: createVector(0.5, 0.6) } ], // NEW FLOWER Shape 40: Petal Dance [ { pos: createVector(-0.7, -0.7), vel: createVector(0.3, 0.5) }, { pos: createVector(0.7, -0.7), vel: createVector(-0.3, 0.5) }, { pos: createVector(0, 1.0), vel: createVector(0, -0.7) } ], // NEW FLOWER Shape 41: Rose Spiral [ { pos: createVector(-1.0, 0.3), vel: createVector(0.4, 0.3) }, { pos: createVector(0.5, -0.9), vel: createVector(-0.2, 0.6) }, { pos: createVector(0.5, 0.6), vel: createVector(-0.3, -0.5) } ], // NEW FLOWER Shape 42: Lotus Bloom [ { pos: createVector(-0.6, 0), vel: createVector(0.2, 0.6) }, { pos: createVector(0.6, 0), vel: createVector(-0.2, 0.6) }, { pos: createVector(0, -0.8), vel: createVector(0, -0.8) } ], // NEW CALLIGRAPHY Shape 43: Brush Stroke Flow [ { pos: createVector(-1.2, 0.5), vel: createVector(0.5, 0.2) }, { pos: createVector(0, -0.8), vel: createVector(0, 0.7) }, { pos: createVector(1.2, 0.3), vel: createVector(-0.5, 0.3) } ], // NEW FLOWER Shape 44: Orchid Grace [ { pos: createVector(-0.8, 0.6), vel: createVector(0.3, -0.4) }, { pos: createVector(0.8, 0.6), vel: createVector(-0.3, -0.4) }, { pos: createVector(0, -0.9), vel: createVector(0, 0.8) } ], // NEW CALLIGRAPHY Shape 45: Zen Circle [ { pos: createVector(-0.9, 0), vel: createVector(0, 0.6) }, { pos: createVector(0.45, 0.78), vel: createVector(-0.52, -0.3) }, { pos: createVector(0.45, -0.78), vel: createVector(0.52, -0.3) } ], // NEW FLOWER Shape 46: Tulip Sway [ { pos: createVector(-0.5, -0.8), vel: createVector(0.2, 0.6) }, { pos: createVector(0.5, -0.8), vel: createVector(-0.2, 0.6) }, { pos: createVector(0, 0.9), vel: createVector(0, -0.9) } ], // NEW CALLIGRAPHY Shape 47: Dragon Curve [ { pos: createVector(-1.3, -0.3), vel: createVector(0.6, 0.4) }, { pos: createVector(0.4, 1.0), vel: createVector(-0.3, -0.6) }, { pos: createVector(0.9, -0.7), vel: createVector(-0.4, 0.5) } ], // NEW FLOWER Shape 48: Cherry Blossom [ { pos: createVector(-0.7, 0.4), vel: createVector(0.4, 0.3) }, { pos: createVector(0.7, 0.4), vel: createVector(-0.4, 0.3) }, { pos: createVector(0, -0.7), vel: createVector(0, -0.6) } ], // NEW CALLIGRAPHY Shape 49: Infinity Flow [ { pos: createVector(-1.1, 0), vel: createVector(0, 0.5) }, { pos: createVector(1.1, 0), vel: createVector(0, -0.5) }, { pos: createVector(0, 0), vel: createVector(0.6, 0) } ] ]; // Initialize bodies with the first shape for (let i = 0; i < 3; i++) { bodies.push({ pos: shapes[0][i].pos.copy(), vel: shapes[0][i].vel.copy(), acc: createVector(0, 0), mass: 1 }); } } function draw() { background(0, 0, 0, 30); // Fading background for trail effect translate(width / 2, height / 2); // Update positions and velocities updateBodies(); // Constrain bodies to stay within circular boundary for (let body of bodies) { let dist = body.pos.mag(); if (dist > maxRadius) { // Bounce off circular boundary body.pos.normalize(); body.pos.mult(maxRadius); // Reflect velocity let normal = body.pos.copy().normalize(); let dotProduct = body.vel.dot(normal); let reflection = p5.Vector.mult(normal, 2 * dotProduct); body.vel.sub(reflection); body.vel.mult(0.9); // Dampen velocity on bounce } } // Draw circular boundary noFill(); stroke(100, 100, 100, 100); strokeWeight(2); //circle(0, 0, maxRadius * 2 * scale); // Store positions in trails for (let i = 0; i < bodies.length; i++) { trails[i].push(bodies[i].pos.copy()); if (trails[i].length > maxTrailLength) { trails[i].shift(); } } // Draw trails with colors const colors = [ [255, 100, 100], // Red for body 1 [100, 255, 100], // Green for body 2 [100, 100, 255] // Blue for body 3 ]; for (let i = 0; i < trails.length; i++) { noFill(); stroke(colors[i][0], colors[i][1], colors[i][2], 150); strokeWeight(2); beginShape(); for (let pos of trails[i]) { vertex(pos.x * scale, pos.y * scale); } endShape(); } // Draw bodies with colors for (let i = 0; i < bodies.length; i++) { fill(colors[i][0], colors[i][1], colors[i][2]); noStroke(); circle(bodies[i].pos.x * scale, bodies[i].pos.y * scale, 12); // Add a white center glow fill(255, 200); circle(bodies[i].pos.x * scale, bodies[i].pos.y * scale, 6); } // Update transition between shapes transition += transitionSpeed; if (transition >= 1) { transition = 0; currentShape = (currentShape + 1) % shapes.length; nextShape = (currentShape + 1) % shapes.length; // Clear trails when transitioning to new shape trails = [[], [], []]; } // Display current shape name fill(255); noStroke(); textAlign(LEFT, TOP); textSize(16); text(`Configuration ${currentShape + 1}/${shapes.length}`, -width/2 + 10, -height/2 + 10); } function updateBodies() { // Only interpolate during the first part of transition if (transition < 0.1) { let t = transition / 0.1; // Normalize to 0-1 for first 10% for (let i = 0; i < bodies.length; i++) { let currentPos = shapes[currentShape][i].pos; let nextPos = shapes[nextShape][i].pos; let currentVel = shapes[currentShape][i].vel; let nextVel = shapes[nextShape][i].vel; bodies[i].pos = p5.Vector.lerp(currentPos, nextPos, t); bodies[i].vel = p5.Vector.lerp(currentVel, nextVel, t); } } else { // Let physics take over for 90% of the time // Calculate gravitational forces for (let i = 0; i < bodies.length; i++) { bodies[i].acc.set(0, 0); for (let j = 0; j < bodies.length; j++) { if (i !== j) { let r = p5.Vector.sub(bodies[j].pos, bodies[i].pos); let dist = r.mag(); if (dist > 0.01) { let force = G * bodies[i].mass * bodies[j].mass / (dist * dist); r.normalize(); r.mult(force / bodies[i].mass); bodies[i].acc.add(r); } } } } // Update velocities and positions for (let body of bodies) { body.vel.add(p5.Vector.mult(body.acc, dt)); body.pos.add(p5.Vector.mult(body.vel, dt)); } } }