pbnj

snippet #6

 
    // 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));
        }
      }
    }