Salem Al Shamsi – Assignment 3

Al-Muraud (The Chase)

A simulation of UAE falconry using flocking behavior and physics forces

Embedded Sketch

How to Interact

  1. Move your mouse : The falcon follows and birds run away
  2. Click : Creates a dive attack with spinning chaos
  3. Press +/- : Add or remove birds
  4. Press R : Reset everything
  5. Press S : See the invisible force circles (debug mode)

Concept & Inspiration

I wanted to create something connected to UAE culture, so I chose falconry the traditional hunting practice where falcons chase desert birds called Houbara Bustards. The idea is simple: you control a falcon (the mouse), and it hunts a flock of birds. The birds try to stick together for safety, but when the falcon gets close, they scatter. There are also two green “oasis” spots where birds naturally want to gather. When you click, the falcon does a dive attack that creates a spinning vortex.

My inspiration came from:

Code Organization & Variable Names

I organized my code into two main classes:

1- Houbara Class (The Prey)

Variables:

  • perceptionRadius – How far a bird can “see” neighbors
  • panicLevel – Maps speed to fear (0 = calm, 1 = terrified)
  • maxForce – How sharply a bird can turn

Methods that organize behavior:

  • cohesion() – Pull toward flock center
  • separation() – Avoid crashing into neighbors
  • flee() – Escape from predator
  • seekOasis() – Drift toward safe zones
  • turbulence() – Get caught in chaos vortex
  • flock() – Combines all forces with priorities

2-Falcon Class (The Predator)

Variables:

  • wingAngle – For flapping animation
  • sizeMultiplier – Grows when moving fast

Methods:

  • follow() – Smoothly chase mouse
  • show() – Draw with animated wings

Global Variables

Clear names that explain themselves:

  • diveActive – Is turbulence happening right now?
  • divePos – Where did the user click?
  • diveDuration – Countdown timer for chaos
  • showDebug – Toggle for seeing perception circles

Code Highlights

Here are three pieces of code I’m particularly proud of:

1. Panic Escalation System
// FLEE: Escape from predator
// Force strength increases as falcon gets closer (gradient of fear)
flee(target) {
  let perceptionRadius = 150; // How far bird can sense danger
  let desired = p5.Vector.sub(this.pos, target); // Point AWAY from falcon
  let d = desired.mag(); // Distance to falcon
  
  // Only flee if falcon is within perception range
  if (d < perceptionRadius) {
    desired.setMag(this.maxSpeed); // Set to maximum speed (fleeing urgently)
    let steer = p5.Vector.sub(desired, this.vel); // Steering = desired - current
    steer.limit(this.maxForce); // Don't turn impossibly sharp
    
    // KEY FEATURE: Map distance to force strength
    // Close (0px) = 2x force, Far (150px) = 0.5x force
    let strength = map(d, 0, perceptionRadius, 2, 0.5);
    steer.mult(strength);
    
    return steer;
  }
  return createVector(0, 0); // No force if falcon is far
}

The map() function creates a gradient of fear. At 0 distance = 2x force. At 150 pixels = 0.5x force. This makes the behavior feel natural instead of just on/off. Birds don’t just “run”, they panic MORE as danger gets closer.

2. Creating the Spinning Vortex
// Create spinning vortex force
let toCenter = p5.Vector.sub(diveCenter, this.pos);
let vortex = toCenter.copy();
vortex.rotate(HALF_PI); // KEY: Rotate 90° transforms "pull" into "orbit"

// Add random chaos
let chaos = p5.Vector.random2D();
chaos.mult(random(2, 5));

// Combine structured spin + random chaos
let turbulence = p5.Vector.add(vortex, chaos);

The key insight is that rotating a force 90 degrees turns “pull toward center” into “orbit around center”. Then adding random chaos makes it unpredictable but still structured. This one line vortex.rotate(HALF_PI) is the difference between an explosion and a whirlwind.

3. Weighted Separation Force
let diff = p5.Vector.sub(this.pos, other.pos); // Point away from neighbor
diff.div(d); // IMPORTANT: Closer neighbors create stronger push

Dividing by distance means: bird at 10px pushes 10x harder than bird at 100px. This single line creates realistic personal space. It’s elegant math that produces natural behavior.

Development Milestones & Challenges

I built this in 6 steps, adding one feature at a time:

Milestone 1: Basic Birds Moving Around

I started by creating a Houbara class with basic physics: position, velocity, and acceleration. At this point, birds just drifted randomly across the screen.

Challenge: Getting the triangle shape to point in the direction they’re moving using rotate(this.vel.heading()).

At first I tried rotating without translate() first, which made all the birds rotate around the canvas origin (0,0) instead of their own centers. Solution: Use push(), then translate() to the bird’s position, then rotate(), then draw the shape, then pop(). The order matters!

 

Milestone 2: Flocking Behavior

Added two forces based on Craig Reynolds’ Boids algorithm:

  • Cohesion – Birds want to move toward the center of the flock
  • Separation – Birds don’t want to crash into each other

Challenge: At first, all the birds just merged into one blob. They were stuck together in a tight cluster.

Solution: I made the separation force stronger (1.5x weight) and gave it a smaller radius (50px vs 100px for cohesion). This creates the “nervous flock” behavior they want to stay together but maintain personal space.

 

Milestone 3: Falcon Chases Birds

Made the mouse act like a predator using Reynolds’ Steering Behaviors. Birds flee when the falcon gets within 150 pixels.

Challenge: The flee force was either too weak (birds didn’t care about falcon) or too strong (birds shot off screen instantly).

Solution: I used map() to scale flee force from 0.5x to 2x based on distance. This creates realistic panic where birds freak out more when danger is right on top of them. It’s a gradient instead of binary.

 

Milestone 4: Dive Attack Turbulence

When you click, it creates chaos at that spot. The turbulence combines two things:

  • A vortex that spins birds in a circle (by rotating the force vector 90 degrees)
  • Random chaos pushing birds in unpredictable directions

Challenge: I initially just pushed birds away from the click point, which looked like an explosion. Boring.

Solution: The breakthrough was understanding that vortex.rotate(HALF_PI) turns a “push away” force into circular motion. This creates the spinning whirlwind effect.

 

Milestone 5: Making It Look Good

Added visual improvements:

  • Created an actual Falcon class with flapping wings
  • Added the two green oasis spots
  • Birds leave motion trails
  • Birds change color based on speed (tan → reddish)
  • Sand particles scatter during dive

Challenge: I accidentally put the seekOasis() function in the Falcon class instead of the Houbara class. Got error: TypeError: this.seekOasis is not a function

Solution: Read the error message carefully! It told me exactly what was wrong. Moved the method to the correct class (birds seek oases, not falcons).

 

Milestone 6: Polish & Controls

Final touches:

  • Designed the UI with desert colors (browns and golds)
  • Added keyboard controls (R, +, -, S)
  • Made the oases pulse using sin() animation
  • Changed edge wrapping to bouncing physics
  • Made the falcon grow bigger when moving fast

Challenge: The perception circle was appearing in the wrong spot because it was inside the falcon’s rotation transformation.

Solution: I moved the circle drawing from inside Falcon.show() to the main draw() function, before any transformations are applied. Now it uses absolute world coordinates instead of the falcon’s rotated local coordinates.

The final polished version with all features is available in the embedded sketch above.

How the Forces Work Together

Each bird calculates 5 forces every frame and combines them:

  1. cohesionForce.mult(1.0); // Want to stay with group
  2. separationForce.mult(1.5); // Don’t crash into neighbors
  3. fleeForce.mult(2.5); // RUN FROM DANGER (strongest)
  4. oasisForce.mult(0.8); // Drift toward safety
  5. turbulenceForce.mult(2.0); // Get caught in chaos

The weights create a priority system:

Survival > Safety > Chaos > Togetherness > Comfort

This matches how real animals behave: immediate threats override long-term goals.

Reflection

What I Learned

Simple rules create complex patterns. Each bird only knows about its nearby neighbors, yet the whole flock moves as one. This is called “emergent behavior.”

Small numbers matter.

Changing flee force from 2.0 to 2.5 completely changed how scared birds act. The difference between good and great simulation is often just finding the right numbers.

Building step-by-step works.

Adding one feature at a time made debugging way easier than trying to do everything at once.

Theme matters.

Framing this as falconry instead of “particles following forces” made it way more interesting.

What Worked Well

  • Force priority system feels natural (survival > safety > togetherness)
  • Visual feedback makes invisible forces visible (color changes, trails, size)
  • Keyboard controls make it interactive
  • Vortex turbulence looks really cool

What I’d Improve

  • Plan UI design earlier instead of adding it last
  • Use systematic testing for force weights instead of random tweaking
  • Add sounds (wing flaps, bird chirps, dive whoosh)
  • Implement energy system (birds get tired, need to rest)
  • Create visual dive animation (falcon swoops before turbulence)

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.

Reading Reflection – Week 1

Reading Reflection on The Computational Beauty of Nature by Gary William Flake

Before reading The Computational Beauty of Nature by Gary William Flake, I honestly never connected nature to computer programs at all. In my mind, computers were something artificial that humans fully control, while nature was something completely different and separate. For example, when I write code, I usually think about building apps or solving clear technical problems, not about how birds move, how ants organize, or how weather behaves. This reading changed the way I see that. The author explains that we should focus “not with ‘What is X?’ but with ‘What will X do?’” (p. 5), and this made me realize that code can be used to study real life behavior, not just screens. He also says, “The goal of this book is to highlight the computational beauty found in nature’s programs” (p. 5), which helped me understand that many natural systems follow rules, just like programs. The idea that “simple units… when combined, form a more complex whole” (p. 4) made me think of things I see every day, like how traffic in Abu Dhabi sometimes looks chaotic even though each driver is just following simple rules. I do not feel the author is biased, because he supports his ideas using examples from many different fields like biology, economics, and computing. This also made me wonder how far we can really simulate nature before systems become too complex to fully control.

Another part that affected me was the discussion of reductionism and holism. The author defines reductionism as the idea that “a system can be understood by examining its individual parts” (p. 2), but he also explains that “the whole of the system [can be] greater than the sum of the parts” (p. 4), which is what holism means. This really connects to how I usually solve problems by breaking them into pieces, especially in programming, but it also shows why that is sometimes not enough. The ideas of agents and interactions also made a lot of sense to me, especially when the book explains that scientists study “agents … and interactions of agents” (p. 3). For example, one person in a group project is simple, but when many people work together, the result can become very different and sometimes unpredictable. The book also says, “Interesting systems can change and adapt” (p. 5), and this reminded me of how humans, over many years, gain experience, learn from their mistakes, and slowly improve. This reading even made me rethink my capstone idea. Instead of only building something purely technical, I started thinking about working on a project related to nature or real life systems, something that can actually make life easier or better, not just something that runs on a screen.

 

Assignment 1a – Code

Concept : My sketch simulates one simple agent moving over time, like one driver moving through traffic. The agent switches between two behaviors: random drifting and following the mouse. The switch happens only when a time cycle ends, and probability decides which behavior will happen next. The agent leaves a fading trail so we can see its full path and how small decisions over time create a larger pattern. The trail color changes using HSB color space, which means the color slowly moves through different hues instead of using fixed RGB values. In this version, the color also responds to the agent’s movement speed, so faster motion causes quicker hue changes and stronger saturation and brightness. A timer bar on top shows how close the system is to switching behaviors.

Code Highlight : One part of the code I am proud of is the visual timer bar at the top of the screen. It shows the passage of time before the agent switches behavior, and it also changes color from green to red as the end of the cycle approaches. This makes the system easier to understand instead of hiding the logic.

// "timer" increases every frame
// "currentLimit" is how long the current mode should last

// Convert timer into a value between 0 and 1
let p = timer / currentLimit;

// Change color based on progress:
// 120 = green at start, 0 = red at end
let barHue = map(p, 0, 1, 120, 0);

// Set the fill color using HSB
fill(barHue, 90, 100);

// Draw the bar:
// barW * p makes the bar grow as time passes
rect(barX, barY, barW * p, barH, 7);

Embedded Sketch:

Reflection / Future Ideas : This project helped me understand how a very simple rule and one agent can create a long and interesting path over time. Instead of only seeing the current position of the agent, the fading trail shows the history of its movement, which made me think more about time and process, not just results. I also understood better how systems work in cycles, using a timer, and how behavior changes depending on simple conditions.

In the future, I would like to add more than one agent and see how their paths interact. I am especially interested in trying an example similar to traffic, where one agent (one driver) can create a big effect on the whole system, even though it is only one small part of it. I also want to experiment with different types of movement, like smoother motion or more natural behavior, and see how that changes the overall pattern.