xxxxxxxxxx
240
let drops = [];
let r = 1;
let a = 0;
let palette;
let bk;
let newDrop = true;
let currentColor;
let agents = [];
// Control Variables
const AGENT_SPEED = 5; // Speed of agents
const AGENT_COUNT = 4; // Number of agents
const DROP_SIZE = 60; // Base size of drops
const DROP_VARIANCE = 4; // Random variance in drop size
const DROP_FREQ = 150; // Milliseconds between drops
const COLOR_SHIFT_SPEED = 0.2; // Slower for sunset feel
let colorPhase = 0; // For color evolution
// Sunset color generation
function generateSunsetColor(phase) {
// Base sunset colors (Vancouver-inspired)
const sunsetHues = [
15, // Warm orange
35, // Golden yellow
280, // Purple mountain
20, // Ocean blue
320, // Pink clouds
260 // Twilight purple
];
// Get two adjacent colors to blend between
let index = floor(phase * sunsetHues.length) % sunsetHues.length;
let nextIndex = (index + 1) % sunsetHues.length;
let blend = (phase * sunsetHues.length) % 1;
let h = lerp(sunsetHues[index], sunsetHues[nextIndex], blend);
let s = map(sin(phase * PI), -1, 1, 70, 90); // Rich saturation
let b = map(cos(phase * PI * 1.5), -1, 1, 60, 95); // Varying brightness
colorMode(HSB);
let c = color(h, s, b);
colorMode(RGB);
return c;
}
function updatePalette() {
palette = [];
// Create a sunset gradient palette
for (let i = 0; i < 9; i++) {
let phaseOffset = (colorPhase + (i * 0.1)) % 1;
palette.push(generateSunsetColor(phaseOffset));
}
}
class Drop {
constructor(x, y, r, col) {
this.center = createVector(x, y);
this.r = r;
this.circleDetail = 200;
this.vertices = [];
for (let i = 0; i < this.circleDetail; i++) {
let angle = map(i, 0, this.circleDetail, 0, TWO_PI);
let v = createVector(cos(angle), sin(angle));
v.mult(this.r);
v.add(this.center);
this.vertices[i] = v;
}
this.col = col;
}
tine(m, x, y, z, c) {
let u = 1 / pow(2, 1 / c);
let b = createVector(x, y);
for (let v of this.vertices) {
let pb = p5.Vector.sub(v, b);
let n = m.copy().rotate(HALF_PI);
let d = abs(pb.dot(n));
let mag = z * pow(u, d);
v.add(m.copy().mult(mag));
}
}
marble(other) {
for (let v of this.vertices) {
let c = other.center;
let r = other.r;
let p = v.copy();
p.sub(c);
let m = p.mag();
let root = sqrt(1 + (r * r) / (m * m));
p.mult(root);
p.add(c);
v.set(p);
}
}
show() {
fill(this.col);
noStroke();
beginShape();
for (let v of this.vertices) {
vertex(v.x, v.y);
}
endShape(CLOSE);
}
}
class Agent {
constructor(x, y) {
this.pos = createVector(x, y);
this.vel = p5.Vector.random2D();
this.vel.mult(AGENT_SPEED);
this.size = 30;
this.lastDrop = 0;
}
update() {
this.pos.add(this.vel);
if (this.pos.x < this.size || this.pos.x > width - this.size) {
this.vel.x *= -1;
this.createDrop();
}
if (this.pos.y < this.size || this.pos.y > height - this.size) {
this.vel.y *= -1;
this.createDrop();
}
this.pos.x = constrain(this.pos.x, this.size, width - this.size);
this.pos.y = constrain(this.pos.y, this.size, height - this.size);
}
createDrop() {
if (millis() - this.lastDrop > DROP_FREQ) {
addInk(this.pos.x, this.pos.y,
DROP_SIZE + random(-DROP_VARIANCE, DROP_VARIANCE),
random(palette));
this.lastDrop = millis();
}
}
checkCollision(other) {
let d = dist(this.pos.x, this.pos.y, other.pos.x, other.pos.y);
if (d < this.size + other.size) {
let midX = (this.pos.x + other.pos.x) / 2;
let midY = (this.pos.y + other.pos.y) / 2;
addInk(midX, midY,
DROP_SIZE + random(-DROP_VARIANCE, DROP_VARIANCE),
random(palette));
let angle = atan2(other.pos.y - this.pos.y, other.pos.x - this.pos.x);
let temp = this.vel.copy();
this.vel = other.vel.copy();
other.vel = temp;
}
}
show() {
fill(255, 100);
noStroke();
ellipse(this.pos.x, this.pos.y, this.size * 2);
}
}
function setup() {
createCanvas(416, 720);
updatePalette();
currentColor = random(palette);
for (let i = 0; i < AGENT_COUNT; i++) {
agents.push(new Agent(random(width), random(height)));
}
}
function tineLine(v, x, y, z, c) {
for (let drop of drops) {
drop.tine(v, x, y, z, c);
}
}
function addInk(x, y, r, col) {
let drop = new Drop(x, y, r, col);
for (let other of drops) {
other.marble(drop);
}
drops.push(drop);
}
function mouseReleased() {
newDrop = true;
}
let val = 4;
let counter = 1;
function draw() {
// Evolve colors
colorPhase += COLOR_SHIFT_SPEED;
updatePalette();
// Update agents
for (let i = 0; i < agents.length; i++) {
agents[i].update();
for (let j = i + 1; j < agents.length; j++) {
agents[i].checkCollision(agents[j]);
}
}
// Mouse interaction
if (mouseIsPressed) {
let v1 = createVector(pmouseX, pmouseY);
let v2 = createVector(mouseX, mouseY);
v2.sub(v1);
if (v2.mag() > 0.1) {
v2.normalize();
tineLine(v2, mouseX, mouseY, 2, 16);
}
}
if (mouseIsPressed) {
if (newDrop) {
currentColor = palette[counter % palette.length];
newDrop = false;
counter++;
}
addInk(mouseX, mouseY, DROP_SIZE, currentColor);
}
background(0);
// Show all drops (no removal)
for (let drop of drops) {
drop.show();
}
// Show agents
for (let agent of agents) {
agent.show();
}
}