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