Afra Binjerais – Assignment 3

Concept

For this assignment, I built a night-sky inspired sketch using attractors and movers. In class, we used the attractor/mover system to show motion and forces, and I kept thinking: if attractors “pull” and movers “orbit,” that feels a lot like stars/planets. So my concept became a stylized sky at night, with glowing star bodies and drifting trails.

To add a personal twist, I placed my initials (ABJ) in the center as a constellation-like pattern made from many tiny attractor/mover pairs. The initials stay readable, but still wobble and respond to the mouse so they feel “alive.” Also to be honest this assignment wasn’t the easiest for me and isn’t my favorite, but it’s the best I can do so far with attractors and movers and I learned a lot through iteration 🙂

Inspiration

My main inspiration is simply the sky at night: glowing points, soft halos, and a sense of motion even when things are calm. I didn’t copy a specific image but I had the starry night in mind by Van Gogh. 

Sketch

How the code is organized

The code is organized  sections so the behavior stays understandable even as the sketch becomes more complex. I use two main classes: Attractor and Moverwhere attractors apply a gravitational-style force and movers respond with velocity and acceleration. Several helper functions control additional forces: repelFromMouse() pushes movers away from the cursor to add interactivity, applyTurbulence() introduces Perlin-noise-based motion so the movement feels organic instead of mechanical, and springTo() pulls movers back toward a target position. Scene-building functions like addMainOrbitPairs(), addEdgeOrbitPairs(), and addInitialsABJ() handle different visual systems in the sketch, separating setup from animation logic.

Code highlight I’m proud of

The part I’m most proud of is how I built the ABJ initials using point generators + tiny attractor/mover pairs. Each point of each letter becomes a mini “star” that’s pulled into place, wiggles with turbulence, repels from the mouse, and springs back to stay readable:

// Build ABJ using many tiny attractor+mover pairs.
// Each letter point is a fixed attractor with a mover that wiggles around it.
function addInitialsABJ() {
  let cx = 200, cy = 200;
  let letterW = 32, letterH = 48, spacing = 38;

  let oxA = cx - spacing - letterW / 2;
  let oxB = cx - letterW / 2;
  let oxJ = cx + spacing - letterW / 2;
  let oy = cy - letterH / 2;

  let aPts = letterAPoints(0, 0);
  let bPts = letterBPoints(0, 0);
  let jPts = letterJPoints(0, 0);

  for (let [lx, ly] of aPts) {
    let ax = oxA + lx;
    let ay = oy + (letterH - ly); // A is flipped vertically
    initialsPairs.push({
      attractor: new Attractor(ax, ay, 40),
      mover: new Mover(ax + random(-4, 4), ay + random(-4, 4), 1.2, 2, 0.05, 0.05),
    });
  }

  for (let [lx, ly] of bPts) {
    let ax = oxB + lx;
    let ay = oy + ly;
    initialsPairs.push({
      attractor: new Attractor(ax, ay, 40),
      mover: new Mover(ax + random(-4, 4), ay + random(-4, 4), 1.2, 2, 0.05, 0.05),
    });
  }

  for (let [lx, ly] of jPts) {
    let ax = oxJ + lx;
    let ay = oy + ly;
    initialsPairs.push({
      attractor: new Attractor(ax, ay, 40),
      mover: new Mover(ax + random(-4, 4), ay + random(-4, 4), 1.2, 2, 0.05, 0.05),
    });
  }
}

// In draw(): update ABJ using multiple forces so it moves but stays readable.
for (let p of initialsPairs) {
  p.attractor.attract(p.mover);          // pulls toward letter point
  p.mover.applyTurbulence(t * 0.3);      // gentle wiggle
  repelFromMouse(p.mover, 0.6);          // weaker mouse repulsion
  springTo(p.mover, p.attractor.pos, 0.018); // snaps back to letter shape
  p.mover.update();
}

Milestones + challenges

  • My first idea was using an image background (like a starry-night painting) and layering moving stars on top of it. I got it working, but visually it felt more like “decorating an image” than building a system, so I scrapped that direction. 
  • I switched to a fully generated background with glows and stars, and started focusing on the attractor/mover motion as the main design elements

  • Adding the ABJ initials was the biggest step: it made the sketch feel personal and gave me a focal point.

  • Challenge: The hardest part was balancing turbulence. Too little and everything looked static; too much and the motion became chaotic and the initials stopped reading as letters. I had to iterate on turbulence strength and also add a spring force so the ABJ points could move while still returning to a clean letter structure.

Reflection + future improvements

If I continued this project, I would improve the “sky” depth by adding multiple layers of stars that move at different speeds (parallax). I’d also experiment with making the attractors slowly drift so the whole constellation system evolves over time. Also, in this assignment you get the nature of the sky, but it doesn’t feel natural, so that’s something that I need to keep in mind.

Amal – Assignment 3

Concept

This project explores how small particles in nature respond to invisible forces in their environment. I was inspired by drifting pollen, spores, and algae suspended in water. These natural elements do not move randomly. They respond to forces such as gravity, air currents, and nearby bodies.

Using the attractor and mover structure introduced in class, I reinterpreted the system as an ecological field. The attractors function as environmental centers of influence. The movers behave like pollen particles that continuously respond to these forces. Instead of presenting a physics demonstration, the system is used to generate an evolving visual pattern.

The visual accumulation of trails transforms the physical simulation into a generative design.

Code Highlight

One section I am particularly proud of is the gravitational force calculation inside the attractor. This formula controls how each particle responds to distance and mass, and it was important to balance it so that movement felt stable but still dynamic.

This part connects directly to the force and acceleration principles explored in class.

let force = p5.Vector.sub(this.pos, mover.pos);

let distance = constrain(force.mag(), 20, 250);
force.normalize();

let strength = (this.G * this.mass * mover.mass) / (distance * distance);
force.mult(strength);

return force;
Code

Milestones and Challenges

Scaling the system from a single mover to many movers was an important milestone, as it shifted the focus from isolated motion to collective behavior. Maintaining stability while multiple forces acted simultaneously required careful adjustment, especially to ensure smooth and continuous motion across the canvas. Refining the visual output so that movement accumulated into a coherent pattern was also part of the development process. The main challenge was balancing the strength of attraction. When the force was too strong, particles collapsed into tight clusters, and when it was too weak, the system lost cohesion. Fine tuning the relationship between force strength and distance was necessary to achieve controlled but organic motion.

Reflection and Future Improvements

This project demonstrates how simple force based rules can generate complex collective behavior. Even though each particle follows the same physical logic, their interactions create layered and evolving patterns.

In the future, I would explore introducing interaction or additional forces to create more spatial variation. I am also interested in experimenting with alternative visual mappings to further strengthen the natural aesthetic.

Saeed Lootah – Slime Mold

I was inspired by this which I saw a while ago when looking at the discord channel of the class. It was sent by Professor Aaron Sherwood and it was an animation of some kind but not in p5js but rather in openFrameworks.

https://cargocollective.com/sagejenson/physarum

I didn’t really understand what I was looking at or how it was worked. I chose not to look at it too closely for now so that I could come up with my own rules.

I knew it was based off of a slime mold called Physarum. It again reminded me about a slime mold being used to replicate make the Tokyo subway system and when I searched online I found this:

 

The slime expands in all directions then when it reaches the nutrients the path connecting it to the center gets strengthened. Slime as far as I know doesn’t have any kind of central intelligence, instead each particle or unit (whatever its called) acts independently.

I thought back to Conway’s Game of Life. Made by the mathematician John Horton Conway it is meant to resemble cellular life. It consists of a grid where each cell can be considered either dead or alive. The user can turn a cell to be either dead or alive and then start the simulation. The simulation consists of simple rules:

(Taken from Wikipedia)

  1. Any live cell with fewer than two live neighbours dies, as if by underpopulation.
  2. Any live cell with two or three live neighbours lives on to the next generation.
  3. Any live cell with more than three live neighbours dies, as if by overpopulation.
  4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

Note that each rule is not based on where in the grid a cell is but rather is only based on the surroundings of each cell. I knew for my slime mold simulation to be passable as a simulation it would need to follow a similar ruleset / a similar philosophy.

This was what I came up with:

The way it works is that there are multiple what I called Cells which step outwards from the center of the canvas. Each cell’s movement is slightly randomized in that it has its intended direction say 45 degrees. But using a gaussian distribution and by setting the standard deviation to be some value say 5 degrees then adding the value to the intended direction so most values would be between 50 to 40 degrees. Here’s the corresponding function:

My Personal Highlight

vector_gaussian_heading(standard_deviation) {
    let new_vector;
    let current_heading = this.direction_vector.heading()
    let random_gaussian = randomGaussian(0, standard_deviation)
    // Constrain the value because it can in theory be any number albeit low chance
    random_gaussian = constrain(random_gaussian, -standard_deviation * 2, standard_deviation * 2)

    // Add the randomness to the heading but without updating the initial desired heading
    let random_heading = current_heading + random_gaussian;
    new_vector = createVector(this.direction_vector.x, this.direction_vector.y) // Note: I tried ... = this.direction_vector but it would update this.direction_vector as well :/
    new_vector.setHeading(random_heading)

    return new_vector;
  }

When first creating the code I got confused why at one point the cell would move in all kinds of random directions rather than sticking to a single direction and only deviating a small amount like I intended.

I originally wrote new_vector = this.direction_vector I believed that new_vector would be given the value of this.direction_vector but it would not change this.direction_vector. I was used to the equals sign meaning that what’s on the left would have the value of what’s on the right but not both.

My Progress

Randomly moving cells was not my only problem.

After implementing the slight randomness I began to add more than one Cell. In the screenshot above I believe that was around 10 of them. There’s a for loop in the setup() function within which I initialized all of the Cell classes and wanted to get the initial directions of the cells to span all 360 degrees evenly using a map function but for some reason I couldn’t get it to work.  Instead I kept it simple and used a random() function.

This is what it looked like afterwards.

Salem Al Shamsi – Assignment 2

Saharan Dust to the Amazon

 

 Concept:

At first, I planned to simulate a palm tree frond moving in the wind, but it started to feel like the project was only about appearance. While researching movement in nature, I found something more surprising: dust from the Sahara can travel across the Atlantic and help fertilize the Amazon rainforest. I chose this idea because it shows how tiny particles can move huge distances and create real environmental change. My sketch simulates dust being lifted, carried by wind, and settling in the Amazon, using simple physics rules (acceleration, velocity, and Perlin noise wind).

Reference video showing Saharan dust traveling from Africa to the Amazon rainforest (NASA).

Rules / How the Simulation Works:

  1. Dust particles are released in short bursts, representing real dust storms.
  2. Wind pushes the particles using smooth Perlin noise, so the motion feels natural.
  3. All motion is controlled by acceleration, not by directly changing position.
  4. When particles reach the Amazon side, a downward settling force pulls them down.
  5. As dust settles, the Amazon area slowly becomes greener.
  6. After one dust event (a “season”), the system fades out and restarts.

Code Highlight:

function drawBackground(season) {
  let desertCol = color(220, 200, 150);

  // Amazon color changes depending on fertility
  let amazonStart = color(55, 75, 55);   // dull green
  let amazonEnd   = color(35, 165, 80);  // vivid green
  let amazonCol   = lerpColor(amazonStart, amazonEnd, fertility);

  // 0) Fill whole canvas first (prevents any 1px gaps)
  noStroke();
  fill(desertCol);
  rect(0, 0, width, height);

  // 1) Draw smooth left→right gradient
  // Using 1px rectangles helps avoid “brown seam” line
  for (let x = 0; x < width; x++) {
    let t = x / (width - 1);
    let col = lerpColor(desertCol, amazonCol, t);
    fill(col);
    rect(x, 0, 1, height);
  }

  // 2) Fertility overlay on the Amazon side (soft edge)
  let startX = width * 0.6;
  for (let x = startX; x < width; x++) {
    let tt = map(x, startX, width, 0, 1);
    let a = tt * lerp(0, 200, fertility);
    stroke(20, lerp(70, 210, fertility), 60, a);
    line(x, 0, x, height);
  }

  // 3) Small warm tint that increases when season is “strong”
  noStroke();
  fill(255, 220, 180, 12 * season);
  rect(0, 0, width, height);
}

I chose this part of the code because it represents a decision I struggled with the most. I initially tried to use maps and detailed visuals to show Africa and South America, but they distracted from the movement of the dust. This background uses simple color transitions instead, allowing the particles’ behavior to tell the story. The Amazon only becomes greener when dust settles and increases the fertility value, which connects the visual change directly to the simulation rules.

Embedded Sketch:

 

Reflection and Future Work:

The hardest part of this project was choosing the topic and figuring out how to represent it visually. I explored many different natural movements and phenomena from around the world before settling on this one, and deciding how to deliver the idea took a lot of time and thinking. Through this process, I learned that simple rules and forces like wind, gravity, and acceleration can be enough to communicate complex natural systems. This project made me realize how interesting it is to study invisible movements in nature, and in the future I would like to explore other global phenomena or experiment with different environmental conditions to see how the behavior changes.

Sun Bleached Flies – Assignment 2

Concept

Inspired by the swarming, atmospheric soundscapes of Ethel Cain’s Preacher’s Daughter, I wanted to recreate the jittery and unsettling movement of flies in nature.

Rather than just having objects fly randomly around the screen, I wanted to simulate the urge of a fly to either be stationary on the ground or burst into a manic, erratic flight. I focused on manipulating acceleration to distinguish between these two states: the heavy pull of landing and the weightless jitter of flying in the air.

Sketch

Highlight

I’m particularly proud of the state-switching logic within the update() function. It allows the fly to exist in two completely different physical modes (perched vs. flying) and uses a conditional check to ensure that the transition to landing only happens when the fly is actually descending toward the ground:

// Only force landing if they are below the line AND moving downwards
if (this.isFlying && this.pos.y >= height - 20 && this.vel.y > 0) {
  this.isFlying = false;
}

This bit of logic was crucial because it prevents the flies from accidentally tripping over the ground while they are trying to take off.

Reflection

Initially, the flies were ghosting through the floor. Even though I had a ground line, they would keep flying below it because their state was still set to “flying.” When I first tried to fix the ground collision, the flies became permanently stuck. Because they started on the ground, the force landing rule triggered at the exact same time as the take off urge, pinning them to the floor. I solved this by adding a grace rule: the ground check only applies if the fly is moving downwards (vel.y > 0). This finally allowed them to pop off the floor and enter their erratic flying state properly.

This assignment made me think back to the Flake reading about how simple rules create complex behaviors. By just giving the flies a 1% chance to change their mind, the screen starts to look like a living swarm. In the future, I want to replace the black circles with a PNG of a fly and potentially add a buzzing sound (like what you can faintly hear in the song “Family Tree“) that increases in volume or pitch based on the magnitude of the fly’s acceleration.

I’d also like to try making them avoid the mouse, simulating a swatting reaction using repulsive forces.

Amal – Assignment 2

Inspiration

Concept

For this assignment, I chose to simulate the movement of a moth attracted to a lamp, inspired by how insects behave around light sources in nature. When observing moths, their motion is rarely direct or smooth; instead, it feels hesitant, wobbly, and slightly chaotic.

The goal of this sketch was to recreate that behavior using only acceleration-based forces, without relying on complex visuals. The personality of the moth comes entirely from how it moves rather than how it looks.

The lamp acts as a constant attractor, while a subtle wobble force gives the moth an organic, fluttering quality.

Code Highlight

The part of the code I am most proud of is the wobble (flutter) force, which adds personality to the moth’s movement without making it feel random:

this.wobble += 0.1;
let flutter = createVector(
  cos(this.wobble),
  sin(this.wobble)
);
flutter.mult(0.03);
this.applyForce(flutter);

This small oscillating acceleration creates a natural, insect-like flutter. Combined with the attraction to the lamp, it makes the moth feel alive and slightly unpredictable, rather than robotic. And, this is where I used ChatGPT’s to help.

The Code

Reflection & Future Work

This project helped me better understand how simple rules can create believable natural motion. Using acceleration alone forced me to think carefully about how each force affects the behavior over time.

What worked well:

  • The combination of attraction and wobble felt natural and readable.
  • Limiting speed and force helped keep the movement smooth.
  • Keeping visuals simple allowed the motion to stand out.

If I were to continue developing this sketch, I would:

  • Add a “panic zone” near the lamp where the moth starts circling instead of approaching directly.
  • Introduce multiple moths with slightly different parameters to give each one a unique personality.
  • Experiment with a pulsing or moving light source to see how the behavior adapts.

Assignment 2

Concept

For this project, I wanted to simulate how moths fly around a porch light. I noticed that real bugs are chaotic. They don’t fly in straight lines, and they are all different sizes. I created a system where every moth tries to fly toward the mouse (the light), but they are constantly pushed around by a “jitter” force that makes them flutter. I also gave each moth a specific weight where big moths are heavy and slow to turn, while small moths are hyperactive and fast.

Code Highlight

I chose this function because it acts as the “brain” of the moth. It uses a physics formula to calculate exactly how to steer toward the light. When the user clicks, the code multiplies the allowed acceleration by 5, instantly transforming the moth from a lazy flyer into a chaotic one.

seek(target) {
    // 1. Find the direction pointing to the light
    let desired = p5.Vector.sub(target, this.pos);
    desired.normalize();
    
    // 2. Set the speed: If clicking, double the top speed!
    let speedLimit = mouseIsPressed ? this.maxSpeed * 2 : this.maxSpeed;
    desired.mult(speedLimit);

    // 3. Calculate steering (Desired velocity minus Current velocity)
    let steer = p5.Vector.sub(desired, this.vel);
    
    // 4. Limit the turning power: If clicking, allow 5x more force
    let currentForceLimit = mouseIsPressed ? this.maxForce * 5 : this.maxForce;
    steer.limit(currentForceLimit); 
    
    // 5. Apply this steering force 
    this.applyForce(steer);
  }

 

Reflection and Future Work

I was surprised by how realistic the movement felt, especially when the moths reach the light source and begin orbiting around it. It created a very organic, feeling without complex animation code. For future improvements, I would like somehow make them bump into each other so they don’t overlap.

 

Assignment 2

Concept

For this assignment, I chose to simulate drifting clouds moving across a sky. I was inspired by how clouds move so peacefully yet unpredictably – they have a gentle, steady drift from wind, but also bob up and down with air currents and occasionally get pushed by gusts. The challenge was to recreate this serene, organic movement using only acceleration to control the motion. No directly setting velocities or positions – everything had to come from forces acting on the clouds: wind, air currents, drag, and occasional gusts. Each cloud has its own “personality” through variations in drift speed, bobbing frequency, and size, making the scene feel more natural and alive rather than mechanical.

Code Highlight

In my implementation, a section of my code that i am proud of is below:

// Vertical bobbing using perlin noise for smooth, natural variation
this.time += 0.01;
let bobForce = map(noise(this.time), 0, 1, -this.bobFrequency, this.bobFrequency);
let bob = createVector(0, bobForce);
this.applyForce(bob);

This creates the gentle up-and-down bobbing motion of the clouds. Instead of using random() which would make the clouds jitter, I used Perlin noise which gives smooth, organic transitions. Each cloud has its own time value that increments, creating unique but natural bobbing patterns. The bobFrequency variable gives each cloud a different personality – some bob more dramatically while others are more subtle. I am also proud of this snippet that creates creates air resistance, that opposes the cloud’s velocity, preventing it from accelerating infinitely and giving it that slow, peaceful drift. It’s a small detail but makes a huge difference in the realism.

// Air resistance (drag)
let drag = this.vel.copy();
drag.mult(-0.05); // Drag coefficient
this.applyForce(drag);

Embedded Sketch

Reflections and Future Improvements

Through this assignment, I discovered that subtle forces acting over time can generate intricate, lifelike movement. In nature, nothing moves in perfectly straight lines or at constant speeds – everything is constantly being pushed and pulled by multiple forces. By combining simple acceleration vectors (wind, drag, turbulence), I could create movement that felt surprisingly alive and organic. My biggest takeaway is personality, which comes from imperfection and variation. Making every cloud slightly different in how it responds to forces was what made the scene feel natural rather than computational. Below are some ideas i would implement in the future for improvement of what i have currently:

  1. Multiple cloud layers – Add parallax depth by having clouds at different “distances” moving at different speeds.
  2. Dynamic wind – Instead of constant wind, have the wind direction and strength change slowly over time.
  3. Cloud morphing – Make clouds gradually change shape as they drift, growing and shrinking.
  4. Weather transitions – Clouds could darken and speed up before “rain,” then slow down and lighten afterward.
  5. Interactive elements – Mouse interaction could create temporary wind forces that push clouds around.
  6. Better visual design – Use gradients and transparency to make clouds look more three-dimensional and fluffy.
  7. Sound – Add gentle wind sounds that change based on cloud speed.

With my implementation so far some feature i believe work very well include, the drag force, bobbing through perlin noise, personality traits of each cloud and the combination of multiple forces which created complex behaviours from simple rules.

Assignment 1

Concept

For this assignment, just like the description suggested, I combined:

    • LIST 1: Random walker with motion experimentation
    • LIST 2: Walking through RGB color space

My sketch features a simple random walker that moves in four directions (up, down, left, right) across the canvas. Instead of being a fixed color, the walker’s color is determined by its position in space, creating a direct mapping between XY coordinates and RGB color values:

Red channel = X position (left edge = 0, right edge = 255)
Green channel = Y position (top edge = 0, bottom edge = 255)
Blue channel = Distance from center (center = 255, edges = 0)

As the walker moves randomly, it paints a trail of colors that visualize its journey through both physical space and color space simultaneously.

Code Highlight

Throughout my code, I am most proud of this snippet where I map the walker’s position to RGB values.

// Map position to RGB color
let r = map(x, 0, width, 0, 255);
let g = map(y, 0, height, 0, 255);

// Blue based on distance from center
let centerX = width / 2;
let centerY = height / 2;
let distFromCenter = dist(x, y, centerX, centerY);
let maximumDist = dist(0, 0, centerX, centerY);  // Changed from maxDist
let b = map(distFromCenter, 0, maximumDist, 255, 0);

// Set the color and draw
fill(r, g, b);
noStroke();
circle(x, y, 10);

In the code, the map() function translates position into color. The blue channel calculation is especially interesting because it uses the Pythagorean distance from the center, creating a radial gradient effect. When the walker is near the center, it’s more blue; when it’s at the edges, it loses blue and becomes more red/green/yellow.

Embedded Sketch

Reflection and Future Work

This project was a great way to visualize the connection between position and color. Watching the walker create organic, colorful patterns by pure randomness is mesmerizing! The RGB color space creates interesting gradients naturally – reds in the upper right, greens in the lower right, blues in the center. Ideas for future improvements:

  1. Add diagonal movement – Currently limited to 4 directions; adding diagonals would create smoother, more varied paths.
  2. Implement Gaussian random walk – Instead of equal probability in all directions, use a normal distribution for step sizes to create more organic movement patterns.
  3. Try HSB color mode – Experiment with Hue-Saturation-Brightness instead of RGB for different color relationships.
  4. Multiple walkers – Have several walkers moving simultaneously, each leaving their own colored trail.
  5. Fade trail effect – Instead of permanent marks, make older circles fade away over time for a ghostly trail effect.
  6. Add 50% mouse attraction – Implement the probability-based walker that has a 50% chance of moving toward the mouse (combining two LIST 1 options).
  7. Step size control – Add a slider to adjust how fast/far the walker moves.

Assignment 1

Concept

For the first assignment, I decided to make a random walker using the Levy Flight algorithm. Additionally, I tweaked the motion so that the walker has a small chance of making a huge leap instead of always making small leaps, just to make it a bit different. It reminds me of how fast moving objects seem to us (such as how the Flash or Quicksilver seem to move in movies). I also mapped movement to scale, where the distance of the jump determines the thickness of the walker’s line and the size of the line’s head. Just to make it visually more appealing, I also decided to change the color of the head based on where it is on the sketch, such that it creates a nice looking color gradient.

Sketch:

Highlight

Even though it’s pretty simple, I was proud of how I decided between small and big leaps using a probability threshold. Here is the code:

let r = random(1);
if (r < 0.05) {
  step.mult(random(25, 100)); // Big leap 5% of the times
} else {
  step.mult(2); // Small leap otherwise
}

Reflection (Milestones, Challenges, Ideas)

An important milestone was successfully implementing the map() function to link two different mediums: spatial distance and visual scale. One challenge was figuring out the right reset interaction, before I settled on simply using a mouse click to leave it up to the viewer.

This sketch could be expanded on by maybe only changing the head’s color when a big leap is made, to signify the walker moving into a new “environment”, like stages of its life, or seasons of a show. It could also be made more visually appealing, but I’m not your guy for that (not yet, at least).