xxxxxxxxxx
193
let particles = [];
const initialNumParticles = 9000;
let numParticles = initialNumParticles;
let noiseScale = 0.005; // adjust for smoother noise transitions
let speed = 0.1; // lower the speed multiplier to slow down particles
let particleSize = 4;
const maxParticles = 9000; // set the maximum number of particles
const maxSpeed = 0.5; // limit maximum speed for each particle
let colorPalette = []; // define a color palette
let targetFlow = false; // control if flow should go towards the mouse
let targetPosition; // position of the mouse when pressed
let explode = false; // control the explosion effect
let perli = true;
// variables for high-resolution export
let scaleRatio = 1;
let exportRatio = 4; // scale down by 4x for working, export at 4x full resolution
let buffer;
let canvas;
let a3Paper = {
width: 3508, // a3 width in pixels at 300 PPI
height: 4960 // a3 height in pixels at 300 PPI
};
// initialize a color palette (e.g., warm, cool, or any themed palette)
function createColorPalette() {
colorPalette = [
color(244, 67, 54), // red
color(255, 193, 7), // yellow
color(33, 150, 243), // blue
color(76, 175, 80), // green
color(156, 39, 176) // purple
];
}
// particle class definition using vector methods
class Particle {
constructor(x, y) {
this.position = createVector(x, y); // particle's position
this.velocity = createVector(random(-0.5 / 16, 0.5 / 16), random(-0.5 / 16, 0.5 / 16)); // smaller initial velocity
this.size = particleSize;
this.color = random(colorPalette); // assign color from the color palette
}
// update the position of the particle using Perlin noise or towards the mouse
update() {
if (explode && targetPosition) {
let repulsion = p5.Vector.sub(this.position, targetPosition).normalize().mult(0.3); // stronger repulsion force
this.velocity.add(repulsion);
} else if (targetFlow && targetPosition) {
let direction = p5.Vector.sub(targetPosition, this.position).normalize().mult(speed * 10); // stronger force towards the mouse
this.velocity.add(direction);
} else if (perli) {
let noiseVal = noise(this.position.x * noiseScale, this.position.y * noiseScale, noiseScale);
let angle = TAU * noiseVal;
let force = createVector(cos(angle), sin(angle)).normalize().mult(speed); // normal flow
this.velocity.add(force);
}
this.velocity.limit(maxSpeed);
this.position.add(this.velocity);
}
// respawn the particle if it hits the canvas edges
checkEdges() {
if (this.position.x >= width || this.position.x <= 0 || this.position.y >= height || this.position.y <= 0) {
this.position = createVector(random(width), random(height)); // respawn at a random position
this.velocity = createVector(random(-0.5 / 16, 0.5 / 16), random(-0.5 / 16, 0.5 / 16)); // reset velocity with lower values
}
}
// render the particle on the canvas
render() {
fill(this.color); // use the particle's color
noStroke();
ellipse(this.position.x, this.position.y, this.size * 2, this.size * 2); // draw particle as an ellipse
}
}
// setup function to initialize particles and canvas
function setup() {
let w = a3Paper.width / exportRatio; // scaled-down width
let h = a3Paper.height / exportRatio; // scaled-down height
buffer = createGraphics(w, h); // create off-screen buffer for scaled drawings
canvas = createCanvas(w, h); // create main canvas
exportRatio /= pixelDensity(); // adjust export ratio based on pixel density of screen
createColorPalette(); // initialize color palette
for (let i = 0; i < numParticles; i++) {
particles.push(new Particle(random(width), random(height))); // create particles
}
stroke(255);
background(0);
}
// draw function to update and render particles
function draw() {
background(0, 10); // lower opacity for longer fading trails
// clear buffer and render particles to buffer
buffer.clear();
for (let i = 0; i < numParticles; i++) {
particles[i].update();
particles[i].checkEdges();
particles[i].render();
}
// draw buffer to the canvas
image(buffer, 0, 0);
}
// add particles dynamically (with maximum threshold)
function addParticles(n) {
let newCount = numParticles + n;
if (newCount > maxParticles) {
n = maxParticles - numParticles; // limit to the maxParticles threshold
}
for (let i = 0; i < n; i++) {
particles.push(new Particle(random(width, height))); // add new particles
}
numParticles += n;
}
// remove particles dynamically
function removeParticles(n) {
numParticles = max(numParticles - n, 0); // prevent negative number of particles
particles.splice(numParticles, n); // remove particles
}
// key press handling for dynamic control
function keyPressed() {
if (key === 'a') {
addParticles(500); // add 500 particles
} else if (key === 'r') {
removeParticles(500); // remove 500 particles
} else if (key === 'p') {
perli = true;
explode = false;
targetFlow = false;
} else if (key === 's') {
save('Wagaye_FlowField.png'); // save canvas as PNG
} else if (key === 'e') {
exportHighResolution();
}
}
// mouse press handling to redirect flow towards mouse position
function mousePressed() {
targetFlow = true; // activate flow towards mouse
explode = false; // no explosion during mouse press
targetPosition = createVector(mouseX, mouseY); // set the target position to the mouse press location
}
// mouse release handling to trigger explosion
function mouseReleased() {
targetFlow = false; // disable flow towards mouse
explode = true; // trigger explosion effect
targetPosition = createVector(mouseX, mouseY); // use the mouse release position as the repulsion center
}
// export high-resolution A3 print
function exportHighResolution() {
scaleRatio = exportRatio; // set scaleRatio to the export size
// create a new buffer at the full A3 size
buffer = createGraphics(scaleRatio * width, scaleRatio * height);
// redraw everything at the export size
draw();
// get current timestamp for file naming
let timestamp = new Date().getTime();
// save the buffer as a PNG file
save(buffer, `A3_Print_${timestamp}`, 'png');
// reset scale ratio back to normal working size
scaleRatio = 1;
// re-create buffer at the original working size
buffer = createGraphics(width, height);
draw();
}
// handle key press for exporting
function keyReleased() {
if (key == 'e' || key == 'E') {
// press 'e' to export high resolution A3 print
}
}