Saeed Lootah – Assignment 9

Concept

When I read thought about tension over time the visual that came to mind was that of a ball being squeezed until it ruptured. I originally wasn’t sure how I was going to fit that into the simulation and how I would incorporate flocking behavior but as I went through the the work of Robert Hodgin I had an idea.

I liked the look of the flocking behaviour in 3 dimensions as well as the red lighting. I thought about having it contained inside and that ball I had in mind upon rupture the flocks inside would escape rapidly and slow down over time.

Sketch

(orbit control is enabled, click and drag your mouse to view from different angles when viewing the sketch)

 

Highlight

function releaseBoids() {
  confinementActive = false;
  released = true;
  releaseFrame = frameCount;

  for (const boid of boids) {
    let outward = p5.Vector.sub(boid.pos, centerPoint);
    if (outward.magSq() < 0.0001) {
      outward = p5.Vector.random3D();
    }
    outward.setMag(random(5.5, 8.2));
    boid.vel.add(outward);
    boid.maxSpeed = RELEASE_SPEED_START + boid.speedBias;
  }
}

Once the circle reaches a certain threshold radius it vanishes and the function above is called. It’s only about 15 lines but in my opinion it creates the most interesting effect in the entire simulation.

What it does is simply give each boid an outward vector force of a random magnitude between 5.5 to 8.2. In my opinion that range and those values make it just right that the effect is not too strong that it’s overwhelming but is not too weak that its underwhelming but is instead in my opinion satisfying.

Milestones

The Humble Sphere

My first step after creating the WEBGL canvas was to make the sphere which decreases in size over time. I chose a black background to give the most contrast for any effects I add later on. For the sphere I chose a light-blueish color mostly because of personal preference. The color of the sphere itself is not meant to have much meaning instead I want the attention to be on the boids and the decreasing size of the sphere.

Boids

These are the boids travelling in 3 dimensions. At this point in time they did not have any special effects. I wanted them to be read since I imagined the effect of squeezing to be like that of increasing heat. In the real world particles as they are trapped in a volume that is decreasing increase the amount they vibrate by and the vibration also known as brownian motion is what we call temperature. It’s how combustion occurs in diesel engines whereby the volume decreases as the cylinder compresses the fuel air mixture and unlike gasoline there is no spark plug the combustion alone is enough to combust (this is known as compression ignition).

Boids + Sphere

The way I had the boids stay inside the sphere at this point was by hard limiting the position of the boids rather than manipulating the steering direction as well (I implemented that as well later on).

 

Final

In the final I made a few key improvements. I added multiple gradients and made the blendMode ADD: The color of the boids change based on their speed, at their fastest they are purple, at their slowest they are red, the radius of the boids change based on how close or far they are to the center of the sketch, bigger towards the center and smaller towards the edges, lastly blendMode(ADD) meant that with more boids overlapping the colors get added and make a whiter color this makes it easier to see when boids are more clumped up together especially at the beginning.

Reflection

I’m happy with how the effect turned out and I was surprised by the swirling effect that came about in the beginning. As the circle decreased the boids still moved as they would normally albeit constrained and this made it look like they were swirling around the circle.

Hodgin’s work was made in Houdini which utilized the GPU and made the effect of using point lights possible with large amounts of flying objects whereas in p5 I don’t think the same would be possible and still retain a high framerate. I found that for my simulation around 600 was the limit for the number of boids whilst still running fairly well and that was without any lighting effects the best I could do was add the blendMode(ADD) line to make things more aesthetically interesting.

Going forwards I would like to try out different software maybe openFrameworks to see what is possible and also I want to try out audio cues for when the sphere vanishes and for boids that are travelling close to the camera and based on how fast they are going.

assignment 9; flocking system

Concept + References

I didn’t want to make a “flocking simulation” in the traditional sense. I wanted something that feels alive but also unstable. Something that holds itself together, then loses control, then collapses.

The system is structured as a looped lifecycle with four distinct phases: organism, boil, shockwave, spores

Each phase shifts not just motion, but also energy, density, and emotional tone. It’s less about birds flocking and more about a body going through pressure, rupture, and release.

I was really inspired by Ryoichi Kurokawa’s work, especially how he uses temporal disruption instead of just spatial complexity. His visuals feel like they’re glitching in time, not just moving fast.

I was also thinking about Robert Hodgin’s particle systems, especially how they feel dense and intentional rather than random. His work made me care more about composition, not just behavior.

So instead of just coding movement, I focused on how particles occupy space, how density creates visual tension, how color and blending create a kind of “liquid light”

Highlight of Code I’m Proud Of

I think the strongest part of my system is how the phases are structured and how each one completely redefines the physics:

function getPhase(t) {
  if (t < 13000) return 'organism';     
  if (t < 21000) return 'boil';         
  if (t < 24000) return 'shockwave';    
  return 'spores';                      
}

This simple structure lets the whole system evolve over time instead of staying static.

But what I’m most proud of is the shockwave phase. Instead of just pushing particles outward, I introduced a temporal glitch:

if (frameCount % 4 === 0) {
  this.vel.mult(0.1); 
} else {
  let blastAngle = random(TWO_PI);
  let blast = p5.Vector.fromAngle(blastAngle).mult(5);
  this.acc.add(blast);
}

This creates a stuttering effect where particles freeze and explode intermittently, which feels much more chaotic and alive than a smooth explosion. It’s not just movement, it’s disruption.

Embedded Sketch

Milestones 

Milestone 1: The Basic Flocking Organism

Before I could build a complex timeline, I needed a base system. I started by creating 1,000 particles and using Perlin noise to guide their movement. I added a gentle pull toward the center of the screen so they wouldn’t just scatter. I also drew a low-opacity background every frame to create soft motion trails.

Milestone 2: Introducing the Time Machine

Once I had my organism floating nicely, I wanted the environment to change over time. I created a 30-second loop using millis() and wrote a getPhase() function to track time. I then updated my particle’s physics engine to react completely differently depending on whether it was in the organism, boil, shockwave, or spores phase.

Milestone 3: The Final Visuals and Additive Blending

The physics were working perfectly, but it felt a little stiff visually. For my final step, I mapped specific colors to the timeline so the sketch would transition from cool cyan to boiling orange, into blinding white sparks, and fade out into grey dust.

To give it that volumetric, glowing liquid feel, I implemented blendMode(ADD) in the draw loop, and I instructed larger particles to draw a secondary, highly transparent circle behind them.

Reflection

I think what worked best in this piece is the sense of tension and release.

The “organism” phase feels calm but slightly eerie, like something is forming. Then the “boil” phase starts introducing discomfort and instability. The “shockwave” is the breaking point. And the “spores” phase feels like exhaustion, like everything just gives up and drifts.

I also paid a lot of attention to:

  • blending modes (ADD made everything feel volumetric and glowing)
  • motion blur through background fading
  • particle size variation to create depth

I didn’t want it to look like dots moving. I wanted it to feel like matter.

Future Improvements

If I were to push this further, I would:

  • Make transitions between phases more gradual instead of abrupt
  • Introduce sound and sync the phases to audio (especially inspired by Kurokawa)
  • Add interaction, maybe letting the mouse disturb the system
  • Experiment with depth or layering to make it feel even more spatial
  • Refine color transitions so they feel less mapped and more emergent

Also, I think there’s potential to push the narrative more. Right now it suggests a lifecycle, but it could become something more specific or symbolic.

Final Thoughts

This project made me realize that generative systems don’t need to just simulate nature. They can simulate states, emotions, or conditions.

It’s not about particles.
It’s about what they feel like together.

Salem Al Shamsi – Assignment 9

Habub — هبوب

Concept

I wanted to simulate a desert sandstorm, specifically a haboob, which comes from the Arabic word هبوب meaning “blasting wind.” The idea was simple: start calm, build slowly, hit a peak, then fade back to silence and repeat.

I looked into how sandstorms actually work. Turns out there are three types of particles in a real storm. Heavy grains that barely move on the ground, medium grains that bounce and leap, and fine dust that the wind just carries completely. That’s exactly what the three particle types in this sketch are based on.

For inspiration I looked at Ryoichi Kurokawa, he makes audiovisual pieces that build tension slowly and let silence do the work. And Robert Hodgin who has been making flocking simulations for over 20 years and finds something new in them every time.

Code I’m proud of

The part I like most is how new particles are born from existing ones. A sand grain on the ground gets knocked loose and becomes a bouncing grain. A bouncing grain kicks up dust. The storm builds itself, I didn’t script it, it just emerges.

let source = random(creeps);
flock.addBoid(new Boid(source.pos.x, source.pos.y, 'saltation'));

A new particle appears at the exact position of an existing one. That one line is basically the whole storm.

Embedded sketch
Milestones

Milestone 1 — Stillness

Dark canvas, 28 tiny sand specks near the bottom barely moving.

Milestone 2 — Wind starts
Wind builds, first bouncing amber grains appear born from the sand grains below.

Milestone 3 — Three layers

Fine dust forms from bouncing grains and fills the entire canvas. Three layers, three speeds, that’s the haboob.

Milestone 4 — Peak and settling

Everything turns orange-red at the peak, wind stops, dust disappears first, then the bouncing grains slow down.

Milestone 5 — The loop
Screen fades to black, new grains fall from the top, storm restarts with grains in different positions. See the embedded sketch above.
Reflection
The arc feels right, calm, tension, peak, silence, reset. It reads like a real storm. If I were to push it further I’d add sound. Wind building, a deep rumble at the peak, then silence. I’d also experiment with a horizon line and different times of day; a golden hour haboob looks completely different from a midday one.

Buernortey – Assignment 9

Concept

In the deep ocean, bioluminescence is not just decoration. Many creatures glow brighter when threatened. Firefly squid, siphonophores, certain jellyfish species all do this. The light is involuntary. It is a biological fear signal, and every creature nearby can read it.

That is the idea behind this sketch. It is a flocking system where light and movement share the same variable. Each boid’s proximity to a descending predator controls both how hard it steers away and how brightly it glows. Fear is brightness. The swarm illuminates itself at the exact moment it is most in danger.

The piece moves through three acts. First, creatures drift in near-total darkness, sparse, slow, barely visible. Then a shadow descends from above. Not fast, not aggressive, just a pressure. The boids closest to it sense it first and begin moving away, the fear-glow spreading outward through the swarm. Finally the predator arrives fully and the swarm explodes outward in a burst of light. Then silence. The survivors scatter into the dark, dimmer than before.

Embedded Sketch

Code I’m Proud Of

The piece’s central idea lives in about ten lines inside the Boid class. this.fear is a single float between 0 and 1 computed from distance to the predator. It does two jobs at once: it scales the steering force pushing the boid away, and it is read by draw() to amplify the glow radius and opacity.

// Inside applyPhaseForces(), descend phase:
let toPred   = p5.Vector.sub(this.pos, createVector(pred.x, pred.y));
let d        = toPred.mag();
let fearZone = 280;

if (d < fearZone) {
  this.fear = map(d, 0, fearZone, 1.0, 0);
  toPred.normalize().mult(this.fear * 0.38);
  this.acc.add(toPred);
} else {
  this.fear = 0;
}

// Inside draw():
const baseAlpha = 0.60 + fearGlow * 0.40;
const glowR     = this.size * 2.2 + fearGlow * 5;

The same number that moves the creature also lights it up. I did not need a separate brightness system. That reduction felt like the sketch finding its own logic rather than me imposing one.

Milestones and Challenges

Milestone 1: Basic flocking

The first working version was just the three steering forces running on a plain black background. No phases, no predator, no glow. Getting alignment, cohesion, and separation balanced took more time than expected. At equal weights the boids collapsed into a tight unmoving ball. I had to bring cohesion down significantly and give separation more authority before the swarm started feeling alive.

Milestone 2: Adding bioluminescent glow

Once the flocking was stable I replaced the flat ellipse with a radial gradient halo drawn through drawingContext. This is where the creatures started feeling like they lived underwater rather than on a screen. I also added the teardrop body shape and started assigning each boid a random hue in the cyan-to-violet range.

Milestone 3: The predator as pressure, not shape

My first predator was a solid dark ellipse and it looked like a game obstacle. The fix was removing any hard edge entirely and replacing it with a radial gradient that fades to nothing — an absence of light rather than a presence of shape. This one change made the whole sketch feel more like an environment and less like a simulation.

Milestone 4: Fear driving both movement and light

This was the central technical challenge. Once the predator was descending I needed the boids to respond to it — not just steer away, but glow brighter as they got closer. The insight was that these could be the same number. I computed this.fear as a map() of distance and fed it into both the physics and the renderer simultaneously.

Reflection

The fear-as-light mechanism worked the way I hoped. Watching the swarm light up at the moment of greatest danger, because of the danger, gave the piece a logic that felt biological rather than programmed.

A few directions I would take this further. Sound is the most obvious missing layer. The panic phase has a visual density that feels like it needs a corresponding audio response, something close to how Kurokawa synchronizes brightness and sound intensity. The predator could also be made reactive rather than scripted, hunting the brightest cluster in the swarm. This would create a feedback loop where fear-glow attracts the very thing the swarm is afraid of. Individual boid memory would also add depth. Creatures that were nearly caught could stay darker and more erratic for longer, while those that escaped early return to calm faster. Trauma as a behavioral variable rather than just a visual one.

References

Ryoichi Kurokawa’s audiovisual works were a direct influence, specifically how he treats light density as a rhythmic and emotional variable rather than aesthetic decoration. Robert Hodgin’s fluid creature systems shaped how I wanted the boids to feel: biological rather than mechanical. 

assignment 9

This project is inspired by murmuration by robert hodgin. It merges algorithmic plant growth with flocking mechanics. The project transitions particles between a structured tree form and a chaotic swarm. I also took inspiration from the reinforcement learning process which is where the idea of generations comes from.

 

I started by defining the base entity. I created the Boid class then I gave each boid standard steering behaviors. These include separate and align then I added the cohere function. These functions calculate vectors. The boids avoid crowding instead they match velocities with neighbors. Next, I tackled the structural element. I wrote a recursive function named genPts. This function calculates coordinates for a branching fractal tree. The function takes arguments for position and angle then it processes length and depth and it calculates segments using trigonometry. It pushes vectors into a global treePts array but I needed a system to alternate between the two behaviors so I implemented a time-based state machine inside the draw loop. Phase zero represents the growth phase. Boids use an arrive steering behavior to settle into specific coordinates along the fractal branches. Phase one represents the swarm phase. The boids break free. They apply flocking rules.

Particles

flocking

fractar tree generation

putting the particles together

the code i am proud of is regenTree function. It manages the visual evolution of the simulation across generations, then it scales the tree depth. It mutates the branching spread angle and dynamically links the boid objects to the newly generated tree points.

// rebuild tree by age/gen
function regenTree(g) {
  treePts = [];
  
  // scale depth/len by gen (cap depth 4 fps)
  let maxD = min(3 + floor(g / 2), 6); 
  let baseLen = min(height * 0.12 + g * 12, height * 0.3);
  
  // mut spread by gen
  let spread = PI / (5 + sin(g) * 1.5);

  genPts(width / 2, height - 30, -PI / 2, baseLen, maxD, spread);

  // sync boids to new pts
  for (let i = 0; i < treePts.length; i++) {
    if (i < boids.length) {
      boids[i].treePos = treePts[i].copy(); // assign new tgt
    } else {
      // spawn new boids at base to sim growth
      boids.push(new Boid(width / 2, height, treePts[i]));
    }
  }
  
  // trim excess (edge case)
  if (boids.length > treePts.length) {
    boids.splice(treePts.length);
  }
}

A specific challenge involved the arrive steering behavior. The boids would overshoot their target coordinates at high velocities. They would oscillate rapidly around the target point. I adjusted the distance threshold mapping by mapping the boid’s speed to decrease linearly when it enters a 100-pixel radius of its assigned treePos. This adjustment solved the jittering issue.

 

I plan to add interactive elements. Users will click to disrupt the swarm. I want to introduce a wind force variable. This force will push the boids horizontally. I will implement a visual trail system for the boids to emphasize their flight paths.

Assignment 9

Concept and Sketch

For this assignment, I wanted to explore the concept of tension and release within a biological system. I was inspired by the way starling murmurations move as a single, fluid organism, and how that harmony is momentarily shattered by external threats.

My visual goal was to move away from the triangle-boid aesthetic and create something more aetherial: bioluminescent beings. I drew inspiration from the use of additive blending and light trails to create volumetric glow that we’ve seen in our course before.

The sketch begins in a state of calm flocking. The beings move in a coordinated, rhythmic dance, glowing with soft blue hues. Their wings flap slowly, and they form dense, glowing clouds.

When the user clicks, a lightning strike occurs. A thunder crack sounds, the screen flashes, and the flock’s physics instantly shift into a scatter behaviour. They turn a fiery red, their wings flap frantically, and they fly away from each other in a panic. However, nature always finds its way back to balance; after five seconds, the storm passes, and the beings slowly regroup into their peaceful blue pulse.

Highlight

I am particularly proud of how I achieved the cloudy look of the swarm without using expensive blur filters. By using blendMode(ADD) and layering multiple ellipses with very low opacity, the light “stacks” wherever the beings are close together.

// This creates the "Nebula" effect when birds cluster
fill(h, 90, 100, 3); // Only 3% opacity
ellipse(0, 0, this.bodySize * 7, this.bodySize * 5);

// The "Hot Core" stays visible in the center
fill(h, 15, 100, 85);
ellipse(0, 0, this.bodySize, this.bodySize * 0.5);

This means a single bird looks like a faint spark, but a cluster of fifty birds creates a brilliant, white-hot center that fades into a saturated blue aura.

Milestones and Challenges

The first step was getting the math right. I started with simple, non-glowing circles to ensure the Separation, Alignment, and Cohesion forces were balanced. The challenge here was making the movement feel organic rather than robotic.

Once the movement was smooth, I replaced the circles with layered ellipses and enabled blendMode(ADD), and it transformed the dots into a cohesive, glowing nebula.

To make the agents feel like beings rather than particles, I added wings. I used a sin() wave to oscillate the position of two side-ellipses. Matching the flap speed to the flock’s velocity made a huge difference in the realism of the motion.

The biggest logic challenge was creating the Auto-Revert system. I had to implement a timer using millis() so that the scatter state wasn’t permanent. I also added the lightning flash and the thunder sound to turn the state change into a sensory event.

Reflection

This project taught me again how small changes in physics parameters (like increasing separation while decreasing cohesion) can completely change the emotional tone of a piece. Thematically, it was a reminder of something we often forget: this too shall pass. Working on this sketch reminded me of an Urdu quote from the legend Faiz Ahmed Faiz: “لمبی ہے غم کی شام مگر شام ہی تو ہے”. Translated, it means: “The night of sorrow is long, but it is still just a night.

The storm will clear. The sun will rise!

Afra Binjerais – Assignment 9

Concept

reference: https://muslimmatters.org/2012/11/15/ten-things-you-didnt-know-about-the-kaaba/

My concept for the flocking system is inspired by the sacred ritual of Umrah. I wanted to explore flocking in a different way where movement is not random or purely emergent, but organized around a central point. In Umrah, Muslims perform a ritual in which they circle the Kaaba seven times. I was interested in translating this idea into a computational system, where agents revolve around a central structure. In this project, I aimed to reflect that circular, collective movement in an abstract and respectful way, without directly representing people. Instead, I used simplified forms to suggest a crowd while keeping the focus on motion and spatial relationships. My visual inspiration also comes from a drawing of the Kaaba displayed in the art center, located beside the lift on the right side. Although I do not have an image of it, the composition and presence of that piece influenced how I approached the central structure in my work.

A highlight of some code 

orbitForce() {
let center = createVector(width / 2, height / 2);
let radial = p5.Vector.sub(this.pos, center);

if (radial.mag() === 0) return createVector(0, 0);

// convert radial direction into circular motion
let tangent = createVector(-radial.y, radial.x);
tangent.normalize();
tangent.mult(this.maxSpeed);

let steering = p5.Vector.sub(tangent, this.vel);
steering.limit(this.maxForce * 1.3);
return steering;
}

One part of the code I am particularly proud of is the orbit behavior. Instead of having agents move randomly or only react to nearby neighbors, I introduced a force that converts their position relative to the center into a tangential direction. This allows the agents to move in a circular path around the central square. This was important to my concept, as it transforms a typical flocking system into a structured, collective movement organized around a focal point.

Sketch

Milestone

https://youtube.com/shorts/Aij4knx0vcE?feature=share

  • Here I was exploring how a flocking system could revolve around a central structure. I combined basic flocking behaviors with a simple orbit force to create circular movement. At this stage, the system is intentionally minimal, focusing on testing the core idea before adding complexity like time-based changes or refined visuals.

https://youtube.com/shorts/de8Qt2qCW88?feature=share

  • In this video, I wanted to highlight the interaction of dragging the mouse to generate agents in the system. As more agents are added, the movement becomes slower and more dense. This reflects how, in Umrah, movement naturally slows down as the crowd becomes more crowded, creating a more compressed and collective flow.

Challenge

One of the main challenges in this project was balancing control and emergence. While flocking systems are naturally unpredictable, I needed the agents to consistently move in a circular path around the central square without losing the organic quality of the motion. Another challenge was achieving the right level of simplicity in the visuals, ensuring the system remained clear and readable without becoming overly complex or decorative.

Reflection and ideas for future work or improvements

I developed a better understanding of how simple rules can produce complex and meaningful collective behavior. I learned how to balance structure and emergence. For future work, I would explore making the movement more varied and responsive, such as introducing different types of agents or layering multiple rings of circulation. 

Haris – Assignment 9

Concept

After working on the flocking system for the assignment 8 I wanted to do something similar but also structurally different for this assignment. I wanted to make a collective behavior of the flock, or in this case, the school of fish which changes under extreme circumstances. The system begins in a calm state where fish move in cohesion in a fluid formation until the system is disturbed by a shark that comes to a random vertical point of the screen which makes the fish swim in different directions thus breaking the formation and the flocking system for a shirt period of time.

The project focuses on tension and release, where the calm flock represents order, the shark introduces disruption, and the recovery phase reflects reformation. Rather than presenting a literal narrative, the work aims to explore how collective systems respond to external pressure and how coherence can break and re-emerge over time.

Process

In the beginning my goal was to just add the fish and implement simple movement and flock behavior so I didn’t really focus too much on the look of the fish.

After the flocking behavior was working it was time to add the shark spawning and the fish avoiding it.

Again I was just testing things out so the shark looks more like an ellipse than a fish. But since everything was working correctly it was time to add the colors to the fish and some more details to the shark to get the final design.

Code Highlights

// different phase transition
if (phase === "calm" && phaseTimer > 300) {
  phase = "warning";
  phaseTimer = 0;
  shark.activate();
} else if (phase === "warning" && phaseTimer > 90) {
  phase = "panic";
  phaseTimer = 0;
} else if (phase === "panic" && shark.offscreen()) {
  phase = "recovery";
  phaseTimer = 0;
} else if (phase === "recovery" && phaseTimer > 300) {
  phase = "calm";
  phaseTimer = 0;
  shark.reset(); // prepare for next cycle
}

The structure converts the flocking algorithm into a time-dependent dance routine, in which different algorithms and parameters are used depending on the stage of the process. The system does not remain fixed with one behavioral pattern but moves through various stages without necessarily programming an event sequence.

I also played a bit with linear interpolation (lerp) to make the shift between the calm mode and the panic mode feel more natural rather than abrupt.

this.maxSpeed = lerp(this.maxSpeed, this.baseMaxSpeed, 0.03);
this.maxForce = lerp(this.maxForce, this.baseMaxForce, 0.03);

Future improvements

I am very happy with how the project turned out. I think it demonstrates well the tension and release part of the assignment and I think that choosing to give fish different colors was the right move artistically as it makes the assignment more visually appealing. If I was to add anything to the assignment that would definitely be sound. I believe that maybe different sound depending on the tension or if the shark is in sight would work really well for the overall project. But overall I am happy with the final result and am glad I got to work on flocking mechanism even more.

Saeed Lootah – Assignment 7

Concept

When looking through the teamLab installations the one I found the most visually striking was the Koi fish installation:

I unfortunately wasn’t able to attend the trip to teamLab but regardless I found this image from which I took inspiration.

Milestones

Unfortunately because of the dark background it is hard to see some of the smaller details I’m referring to but it should be possible to see.

Stage 1

Although this step is fairly basic in my opinion it is still worth mentioning. At the very beginning I made the canvas render using WEBGL and added orbitcontrol() this would be useful for all of the following steps.

Stage 2 – Koi Fish (Random Motion)

At this point I created the Koi fish class. It’s called Koi but really the logic is like the vehicles we discussed in class. At this point in time the motion was fairly random but later the motion would become more fluid and they would travel in flocks using boid logic.

I thought about using more intricate fish models rather than simple dots and trails but I felt that strayed too far from the original installation since I didn’t get the impression that it was about the aesthetics of the fish but rather the movement and colors.

Stage 3 – Trails + Boid Movement

Now each ‘fish’ had a trail to make it’s movement more apparent. This also came with a surprising feature. To make sure that the fish would not go too far I had it so that at a certain distance it would return back to the opposite side but this had an unintended effect of this line that would go across the canvas (one can be seen at the back). I liked the look of it so I decided to keep it.

Boid movement refers to movement that replicates the movement of birds. Although it would normally be used to simulate birds moving in flocks I decided it could work in this sketch since I wanted them to move in flocks. In this screenshot the cohesion was set to a lower value but I would later try out different settings.

Stage 4 – 3D Player + Light Interaction + Avoidance

Afterwards I decided to add the ‘player’. In the original picture there are two people and I’m unsure how the fish act around the two people whether they follow them or always circle them but I decided to do something similar by having the fish avoid the player. In addition the color from the fish would illuminate the player accordingly.
The player can move around using either WASD, or the arrow keys and using shift/control to move up and down respectively.

Stage 5 – HTML UI Controls

Lastly, I added UI controls. You can edit the settings in real time by adjusting the sliders. I coded this part using html so that the UI would be 2D since the WEBGL sketch is 3D the UI wouldn’t follow the camera view. I am sure there is a way to still use p5 to achieve the same effect but I think this turned out well regardless.

Code Highlight

avoidPlayer(actor) {
    const off = wrappedOffset(this.pos, actor.pos);
    const d = off.mag();
    if (d > actor.fleeRadius || d < 0.0001) return;

    const strength = map(d, actor.fleeRadius, actor.radius, 0.0, 1.0, true);
    const flee = off.mult(-1);
    flee.normalize();
    flee.mult(this.maxSpeed * (0.8 + strength));
    flee.sub(this.vel);
    flee.limit(this.maxForce * (1.6 + strength));
    this.applyForce(flee);
  }

I highlighted this code because it makes each koi fish avoid the player in an organic way. When the player enters the fish’s flee radius, the fish measures that distance, converts it into a stronger or weaker escape response, and then applies a limited steering force so it turns away smoothly instead of abruptly.

Embedded Sketch

Viewing the sketch directly through the web editor and in window size achieves the best effect.

Reflection and Ideas for Future Work

I’m happy with the movement of the fish and the minimalistic aesthetic but there’s still room for improvement in the future. The following is what I would add in the future if I were to continue on this project or do something similar.

  • Add optional shader-based water caustics and soft volumetric fog.
  • Introduce seasonal color palettes as a toggleable mode.

Assignment 9

Concept:

For this assignment, I was influenced by the glitch-aesthetic of Ryoichi Kurokawa and the organic precision of Robert Hodgin. The project tells a visual story of a digital organism struggling to maintain its structural integrity, moving through a scripted cycle of Crystalline Order, Kinetic Chaos, and Digital Decay. I was able to do this by layering standard flocking rules with a custom “Glitch” variable.

There are three modes you can switch through by pressing the spacebar, which I called Order (Cohesion high), Chaos (Wander & Flee high), and Decay (Fading trails).

Code Highlight:

I am particularly proud of the State-Dependent Steering Logic within the flock() method. This snippet acts as the nervous system of the simulation, allowing the agents to instantly reconfigure their behavior based on the current global state. By using vectors and dynamically shifting the weights of Cohesion, Wander, and Separation, I can transition the entire system.

if (state === 0) { // ORDER: High Cohesion to center
  let center = createVector(width/2, height/2);
  coh = this.seek(center).mult(2.5); // Force into a rigid cluster
  this.maxSpeed = 1.8;
} else if (state === 1) { // CHAOS: High Velocity & Randomness
  glitch = p5.Vector.random2D().mult(6.0); // Introduce erratic energy
  this.maxSpeed = 7;
  this.maxForce = 0.6;
} else { // DECAY: High Separation & Drifting
  sep.mult(5.0); // Force agents apart
  this.maxSpeed = 0.8;
}

Milestone 1:

This milestone focused on the mathematical accuracy of the core steering behaviors. At this stage, there was no tension and release or interactivity. The agents simply moved in a continuous, unchanging loop. The visual was kept basic to ensure the Separation, Alignment, and Cohesion logic was solid.
Milestone 2:

In this milestone, I shifted from representational triangles to the Kurokawa-inspired line aesthetic. I introduced the “Nearest Neighbor” logic, where agents “reach out” to one another to create a web-like structure. I also added low-alpha background clearing to create the smoky history trails seen in Robert Hodgin’s work.

Final Sketch:

Reflection and ideas for future work or improvements:

This project taught me that compelling generative art often emerges from the disruption of rules. This shift, combined with a low-alpha background, transformed a simple steering simulation into a smoky, ethereal system that bridges the gap between predictable math and the emotional tension seen in the works of Kurokawa and Hodgin. Moving forward, I plan to integrate p5.sound to map the “Chaos” phase to granular synthesis and implement Obstacle Avoidance using invisible voids to force agents into even more intricate woven patterns possibly within a 3D WebGL environment.