Particle (class)
This class is the heart of the sketch - it packages a particle's data (position, velocity, acceleration, color) together with the behavior that moves it (update) and draws it (show). This pattern, common in creative coding, lets you manage thousands of independent objects with clean, reusable code instead of separate arrays for each property.
🔬 This wraps particles around the edges like Pac-Man. What happens if you delete these four lines entirely - where do all the particles eventually end up?
if (this.pos.x > width) this.pos.x = 0;
if (this.pos.x < 0) this.pos.x = width;
if (this.pos.y > height) this.pos.y = 0;
if (this.pos.y < 0) this.pos.y = height;
class Particle {
constructor() {
// Initialize particle position randomly across the canvas
this.pos = createVector(random(width), random(height));
// Initialize particle velocity with a random direction and small magnitude
this.vel = p5.Vector.random2D();
this.vel.mult(random(0.5, 1.5)); // Randomize initial speed slightly
// Initialize acceleration to zero
this.acc = createVector(0, 0);
// Assign a random color from our defined palette
this.color = colors[floor(random(colors.length))];
}
update() {
let angle = noise(this.pos.x * noiseScale, this.pos.y * noiseScale) * TWO_PI * 4;
let force = p5.Vector.fromAngle(angle);
force.mult(0.1);
this.acc.add(force);
this.vel.add(this.acc);
this.vel.limit(maxSpeed);
this.pos.add(this.vel);
this.acc.mult(0);
if (this.pos.x > width) this.pos.x = 0;
if (this.pos.x < 0) this.pos.x = width;
if (this.pos.y > height) this.pos.y = 0;
if (this.pos.y < 0) this.pos.y = height;
}
show() {
stroke(this.color);
strokeWeight(1.5);
point(this.pos.x, this.pos.y);
}
}
Line-by-line explanation (15 lines)
🔧 Subcomponents:
if (this.pos.x > width) this.pos.x = 0;
if (this.pos.x < 0) this.pos.x = width;
Teleports the particle to the opposite horizontal edge when it drifts off screen
if (this.pos.y > height) this.pos.y = 0;
if (this.pos.y < 0) this.pos.y = height;
Teleports the particle to the opposite vertical edge when it drifts off screen
let angle = noise(this.pos.x * noiseScale, this.pos.y * noiseScale) * TWO_PI * 4;
Turns a smooth noise value (0-1) into an angle that can span multiple full rotations, creating swirling directions
this.pos = createVector(random(width), random(height));- Creates a p5.Vector to store the particle's x,y position, starting at a random spot on the canvas
this.vel = p5.Vector.random2D();- Creates a vector pointing in a completely random direction with length 1, used as the initial velocity direction
this.vel.mult(random(0.5, 1.5));- Scales that random direction vector by a random amount between 0.5 and 1.5 so particles don't all start at the same speed
this.acc = createVector(0, 0);- Acceleration starts at zero - it will be recalculated fresh every frame from the noise field
this.color = colors[floor(random(colors.length))];- Picks a random index into the colors array; floor() rounds the random decimal down to a valid whole-number index
let angle = noise(this.pos.x * noiseScale, this.pos.y * noiseScale) * TWO_PI * 4;- Samples Perlin noise using the particle's own position (scaled small) as coordinates, then stretches the 0-1 result into an angle covering up to 4 full rotations for more swirl variety
let force = p5.Vector.fromAngle(angle);- Converts that angle into an actual 2D vector pointing in that direction with length 1
force.mult(0.1);- Shrinks the force so it nudges the particle gently instead of throwing it violently in a new direction
this.acc.add(force);- Adds the noise-based force to acceleration (in case other forces were added elsewhere, though here it's the only one)
this.vel.add(this.acc);- Classic physics integration step: acceleration changes velocity
this.vel.limit(maxSpeed);- Caps the velocity's length so particles never move faster than maxSpeed pixels per frame
this.pos.add(this.vel);- Velocity changes position - this is what actually moves the particle each frame
this.acc.mult(0);- Resets acceleration to zero so forces don't accumulate forever across frames
stroke(this.color);- Sets the outline/point color to this particle's assigned hex color string
point(this.pos.x, this.pos.y);- Draws a single point at the particle's current position using the current stroke color and weight