Amal – Assignment 10

Concept

For this assignment, I explored how a structured geometric system can respond to external interaction using physics. I created a symmetrical pattern that extends across the canvas, composed of small elements that are held in place through soft constraints. The goal was to simulate a system that feels stable and balanced, but still capable of disruption.

As the user moves their mouse across the canvas, the pattern begins to distort. The elements are pushed away from the cursor, creating a temporary break in the symmetry. Once the mouse moves away, the system gradually restores itself, returning to its original configuration. This creates a continuous loop between order and disruption, where interaction introduces instability, and the system’s internal structure restores balance.

This project is loosely inspired by responsive systems and generative patterns where structure is not fixed, but maintained through underlying rules. I was particularly interested in how symmetry can be preserved even when temporarily disturbed, and how small forces can create large visual changes.

Code Highlight

One part of the code I focused on was how the particles return to their original positions. Instead of manually animating them back, I used constraints in Matter.js to connect each particle to a fixed anchor point. This allows the system to naturally restore itself after being disturbed.

let spring = Constraint.create({
  pointA: { x: x, y: y },
  bodyB: body,
  length: 0,
  stiffness: 0.06,
  damping: 0.08
});

This approach made the motion feel more organic, since the particles are not directly controlled but instead react to forces within the system.

Final Sketch

Milestones and Challenges

1. Building the initial pattern
The first step was creating a grid that felt structured but still visually interesting. I experimented with spacing and conditions to create a pattern that extends across the canvas while maintaining symmetry.

2. Introducing interaction through forces
I then added a repulsion force from the mouse. One challenge here was finding the right balance, since too much force made the system chaotic, while too little made the interaction barely noticeable.

3. Making the system return to form
A key part of the project was ensuring the pattern would restore itself. Using constraints instead of manual positioning allowed the system to behave more naturally and maintain consistency.

Reflection

This assignment helped me understand how physics engines can be used beyond simple motion. Instead of focusing on collisions or gravity alone, I explored how forces and constraints can create a system that feels both reactive and stable.

I found it interesting that the interaction is temporary, but the structure persists. This creates a dynamic where the user can influence the system, but not completely control it.

Future Improvements
  • Introduce more complex symmetrical structures
  • Add variation in particle size or behavior
  • Experiment with different types of forces (attraction instead of repulsion)
  • Refine the visual output to emphasize the symmetry more clearly

Buernortey – Assignment 10

Concept

Erosion is a physics simulation of a rocky mesa breaking apart under falling debris. The idea came from thinking about how landscapes that look permanent are always being shaped by small, repeated impacts over time. I wanted to use Matter.js not just to show objects falling but to model a process. The terrain starts whole and breaks down based on how hard things hit it.

Code I Am Proud Of

The collision event handler is the center of the piece. It does not react to every contact. It reads the speed of the incoming rock and only shatters a terrain block when the impact crosses a threshold. This makes the simulation feel grounded. Slow rocks bounce off. Fast rocks break things.

 

Events.on(engine, 'collisionStart', function(event) {
  for (let pair of event.pairs) {
    let { bodyA, bodyB } = pair;
    let rock = null, ter = null;

    if (bodyA.label === 'rock' && bodyB.label === 'terrain') { rock = bodyA; ter = bodyB; }
    if (bodyB.label === 'rock' && bodyA.label === 'terrain') { rock = bodyB; ter = bodyA; }

    if (rock && ter) {
      let impactSpeed = Vector.magnitude(rock.velocity);
      if (impactSpeed > 3.5) {
        let idx = terrain.findIndex(t => t.body === ter && !t.broken);
        if (idx !== -1) shatterTerrain(idx, impactSpeed);
      }
    }
  }
});

 

I am also proud of the shatterTerrain function because it does three things at once when a block breaks. It triggers a screen shake scaled to the impact force, spawns a flash at the contact point, and sends out a burst of dust particles that drift upward and fade out. Each of those effects runs from the same impact speed value, so they all feel connected.

 

Embedded Sketch

Milestones and Challenges

The first milestone was drawing the terrain. I wrote a heightmap function that builds a mesa shape, peaks in the center, and slopes toward the edges, with small random offsets per column to roughen the silhouette. I added a sky gradient and a highlight strip on the top face of each block so the structure looked like real layered rock before any physics was involved.

The second milestone was loading that terrain into Matter.js as static bodies. Each block became a rectangle body placed at the correct position. Drawing them back from their body positions confirmed the physics world and the visual layer matched.

The third milestone was getting rocks to fall with physical variety. Rocks now vary in size, fall speed, bounciness, friction, and spin. Density scales with size so large boulders hit harder. Wind drifts slowly over time toward a random target every three seconds, and the visual rain streaks angle to match. This step exposed the first real challenge: collision filters. Without explicit category and mask values set on each body type, rocks passed straight through the terrain. Setting category: 0x0002 on terrain and mask: 0x0001 on terrain fixed which bodies could interact with which.

The fourth milestone was the full shattering system with visual feedback. When a collision event fires and the impact speed clears the threshold, the terrain block is removed, fragments spawn and tumble, dust particles burst outward, a flash appears at the contact point, and the canvas shakes. The main challenge here was performance. Without cleanup, thousands of fragment, dust, and rock bodies built up below the canvas over time and slowed the simulation. Adding a per-frame filter that removes any body or particle whose position exceeds the canvas height solved the problem completely.

Reflection

The piece works well as a slow process. Dropping one rock at a time and watching the terrain wear down has a satisfying quality. The storm mode makes the erosion visible in seconds and shows how the system handles high load. The wind system adds unpredictability without feeling random because it drifts gradually rather than jumping between values.

For future work I want to add water. Fragments that collect at the bottom could be slowly submerged as a rising water level fills the valleys left behind by the erosion. I also want to track how many blocks have been destroyed and show it as a live counter so the viewer has a sense of scale over the life of the simulation.

References

The Nature of Code, Chapter 6: Physics Libraries Matter.js documentation on collision events and body properties

Salem Al Shamsi – Assignment 10

Al Ghawwas — The Pearl Diver

Concept

Before oil, the Arabian Gulf had pearls. Every summer during Al Ghous Al Kabir (The Big Dive), fleets of wooden Dhows sailed out while divers plunged to the seafloor with nothing but a nose clip, a collection bag, and Al Zubail, a stone weight tied to the leg to help them sink. The only thing connecting them to the surface was Al Yada, a rope held by a crew member on the Dhow.

This sketch simulates that dive. The player controls a pearl diver descending from a Dhow into the Arabian Gulf, collecting pearls from the seabed before their breath runs out. The visual concept came from Xavi Bou’s Ornitographies, making invisible motion visible. Here, the diver’s path through the water is the thing being revealed.

Sketch

Code I’m Proud Of

The most interesting part is how forces stack underwater. Three things push against each other every frame:

// Dive toward mouse
Body.applyForce(diver, diver.position, { x: fx, y: fy });

// Tidal current fights you sideways
Body.applyForce(diver, diver.position, { x: currentX, y: currentY });

// Oxygen drains faster the deeper you go
let depthDrain = map(diver.position.y, MIN_DIVER_Y, 578, 0.1, 0.22);
oxygen -= depthDrain;

None of these forces work alone, they fight each other. That tension is what makes the dive feel hard, which felt true to the history. The current also shifts direction every few seconds, so the player can never fully settle.

Process and Challenges

The sketch was built in stages, each one adding a new layer of physics or visual detail.

Phase 1 — Engine and water

Just the physics engine running inside p5.js. Nothing moves yet, just proving the two libraries work together.

Phase 2 — First bodies: seafloor, dhow, diver

A circle for the diver, a rectangle for the seafloor, and one for the Dhow. The diver falls under gravity and lands on the floor. No control yet, just physics bodies existing in the world.

Phase 3 — Forces: buoyancy and diving

Gravity is turned off. Everything is now controlled through applyForce. Buoyancy pushes the diver up every frame. Holding the mouse pushes it toward the cursor. This is where it first felt like something underwater.

Phase 4 — Rope, Collision Events and Pearls

Oyster shells added as sensor bodies. A collisionStart event fires when the diver touches one, spawning a glowing pearl. The rope connects the diver to the Dhow using manual distance math, drawn as a bezier curve. A top boundary stops the diver from floating above the water surface.

Phase 5 — Final

Already embedded above. The final version added everything that made it feel like the Gulf: the drawn Dhow with sail and rigging, the pearl diver figure with Al Zubail stone weight, gradient sky, animated wave surface, sun, clouds, fish, seaweed, bubbles, splash on water entry, the two phase return journey, oxygen system draining faster with depth, and shifting underwater currents that push the diver off course every few seconds.

Reflection

What surprised me was how much the history shaped the design. The rope length, the oxygen mechanic, the stone weight, these are not decorative details. They are the actual constraints real divers worked within. Simulating even a simplified version of them made the difficulty feel earned, not arbitrary.

Things I would add with more time: varying pearl depths, a multi dive scoring system, and an automatic rope pull mechanic like the real Al Seib, pulling the diver up whether they are ready or not.

References

 

Assignment 10

Concept & Inspiration

This week, I wanted to recreate Tetris but with a chaotic twist: I wanted to see what happens when you take a perfectly organized game and throw it into a world of messy physics. Instead of blocks snapping into place on a grid, they are governed by gravity, friction, and torque, meaning a slightly off-center landing can topple your entire stack. I was inspired by the way Ryoichi Kurokawa and Robert Hodgin use digital systems to create organic, unpredictable structures. The challenge isn’t just about where the blocks go, but how they balance, shift, and compress as the pile grows.

Since the blocks are no longer perfectly organized in a grid as in the game, which meant gaps are inevitable, I made it so that having a row 90% filled gets cleared.

Code Highlight

I am particularly proud of the checkRowsStrict() function. Because physics bodies don’t align to a grid, I divided the canvas into ten horizontal “bins” per slice. The system iterates through these sectors and uses Matter.Bounds.contains to verify if a physics body is physically occupying that space.

for (let i = 0; i < numBins; i++) {
  let binX = i * binWidth + binWidth / 2;
  // Check if any body in this slice covers this bin center
  let isOccupied = bodiesInSlice.some(b => Matter.Bounds.contains(b.bounds, { x: binX, y: y }));
  if (isOccupied) binsOccupied++;
}

if (binsOccupied / numBins >= 0.9) { // 90% threshold for a clear
  clearRow(bodiesInSlice);
}

This approach bridges the gap between free-form movement and structured gameplay, forcing the player to pack blocks efficiently to reach the 90% occupancy threshold.

Milestones & Challenges

In this version, I was just testing if I could spawn blocks and have them stack. The physics are broken here: they bounce too much, and they don’t lock into a pile properly, which was the first major challenge I had to overcome by learning more about the matter.js library.

This milestone shows the first attempt at clearing rows. I hadn’t implemented the row clearing algorithm yet. It simply looked at the total width of blocks in a zone. It was a breakthrough because it was the first time the game became playable, even if the clearing was a bit too easy and lucky.

After I got that figured out, I added diversity to the block shapes and colors, gave the user control with the arrows, and the game was ready.

Reflection and Improvements

This project shifted my perspective from seeing physics engines as simple simulators to seeing them as gameplay generators. The most rewarding aspect was observing how complex strategies emerged naturally from basic gravity and friction. For future iterations, I plan to integrate p5.sound to map collision impacts to percussive digital noises, further leaning into a glitchy aesthetic. Additionally, I hope to implement Dynamic Fragmentation, where high-velocity impacts can break blocks into smaller pieces, adding another layer of realism to the project.

`

Saeed Lootah – Assignment 10

Concept

My concept is inspired by the red explosive barrels from the Half-Life video game series. I wanted to recreate that same mechanic of an exploding barrel using matter.js where objects can collide with a barrel, build up damage, and trigger an explosion. The idea of explosive barrels spread into other video games with objects that explode either on impact or as it builds up damage and growing up I always enjoyed playing games with destructible elements.

Code Highlight

explode(allBoxes) {
    if (this.isExploded) {
      return;
    }

    const center = this.body.position;

    for (let i = 0; i < allBoxes.length; i++) {
      const currentBox = allBoxes[i];
      if (!currentBox || currentBox.body.isStatic) {
        continue;
      }

      const boxPos = currentBox.body.position;
      const delta = Vector.sub(boxPos, center);
      const distance = Vector.magnitude(delta);

      if (distance <= 0 || distance > EXPLOSION_RADIUS) {
        continue;
      }

      const direction = Vector.normalise(delta);
      const falloff = 1 - distance / EXPLOSION_RADIUS;
      const totalForce = max(EXPLOSION_MIN_FORCE, EXPLOSION_FORCE * falloff);
      const force = Vector.mult(direction, totalForce);
      Body.applyForce(currentBox.body, boxPos, force);

      // Add a direct velocity impulse so the explosion is always visible.
      Body.setVelocity(currentBox.body, {
        x: currentBox.body.velocity.x + direction.x * EXPLOSION_VELOCITY_BOOST,
        y: currentBox.body.velocity.y + direction.y * EXPLOSION_VELOCITY_BOOST
      });
    }

    Composite.remove(world, this.body);
    this.isExploded = true;
  }

The part of the code I am most proud of is the explosion function. I track the number of collisions for the barrel, change the barrel color from gray toward red as damage increases, and once it reaches the hit limit which I defined as a global variable I remove the barrel body and apply outward force and increase the initial velocity to nearby boxes.

Embedded Sketch

Milestones and Challenges

Stage 1:

Stage 1 screenshot

 

Focused on getting the core interaction working by spawning rectangles with the mouse, and getting used to coding with matter.js.

Stage 2:

Stage 2 screenshot

Added a grounded barrel in the center area to establish the main object of the simulation and changed the background color to something I liked. At this point I began thinking about aesthetics.

Stage 3:

Stage 3 screenshot 1

Stage 3 screenshot 2

Introduced the damage mechanic where the barrel changes from gray toward red with each hit. A key challenge was collision handling, especially making sure hits were counted reliably and visual feedback was clear.

Stage 4:

Stage 4 screenshot

Finally I combined everything and added the final explosion behavior after the hit threshold. I had to tune radius, force, and velocity boost values so the explosion effect was strong and readable without becoming too chaotic. I found that the force value was not as important as the initial velocity boost because of air resistance. Then I added text to show the controls and allowed the user to drag their mouse to spawn squares rather than only clicking and made the boundary cover the sides and not only the ground.

Reflection and Future Improvements

If I continue this project, I want to replace simple shapes with sprite-based visuals so the barrel and debris feel more game-like. I also want to explore whether Matter.js can be combined with a 3D workflow or whether a different engine would be better for a full 3D version. Future improvements could include sound effects, particle debris, and different barrel types with unique blast strengths.

Afra Binjerais – Assignment 10

Concept 

 The concept is recreating Newton’s Cradle using the Matter.js physics engine. The goal is to duplicate how a real Newton’s Cradle works, where a series of suspended balls transfer energy through collisions when one ball is pulled back and released. I aimed to simulate this behavior by using physics-based properties like gravity, restitution, and constraints to make the motion feel as realistic as possible. Instead of manually animating the movement, the project relies on the physics engine to naturally calculate how the balls swing and interact, allowing me to explore how energy and motion behave in a simulated environment.

Highlight of some code

A part of the code I’m particularly proud of is the way I created Newton’s Cradle using a loop to generate both the balls and their constraints. Instead of manually placing each ball, I used a loop to calculate their positions and connect them dynamically, which made the code cleaner and easier to adjust.

const startX = CENTER_X - ((BALL_COUNT - 1) * SPACING) / 2;

for (let i = 0; i < BALL_COUNT; i++) {
  const anchorX = startX + i * SPACING;
  const anchorY = TOP_Y;

  const ball = Bodies.circle(anchorX, anchorY + STRING_LENGTH, BALL_RADIUS, {
    restitution: 1,
    friction: 0,
    frictionAir: 0.0005
  });

  const rope = Constraint.create({
    pointA: { x: anchorX, y: anchorY },
    bodyB: ball,
    length: STRING_LENGTH,
    stiffness: 0.9
  });

  balls.push(ball);
  ropes.push(rope);
}

Sketch

Milestones: 

  • This stage is the very first version of Newton’s Cradle where the main goal was just to get the physics working. I created the balls and connected them with constraints so they hang and swing like a real cradle. I also set up gravity and collision so the motion looks natural and the energy transfers from one ball to another. There’s no interaction yet in this version it just runs on its own.

https://youtube.com/shorts/ISYsv6YzDNg?si=kNVKaXBV6mP5ucq0

The focus was on building the core physical system by creating circular bodies connected with constraints to simulate suspended balls and realistic energy transfer during collisions. Basic interactivity was introduced by allowing the user to click and drag individual balls, giving control over how motion is initiated, similar to a real cradle.

Challenges: 

A difficulty was understanding how Matter.js handles physics, since the motion is not directly controlled but calculated by the engine, which made debugging harder. It also took time to properly connect the balls with constraints so they would swing correctly without breaking the structure. AI was very handy with this specific assignment as it was my first time using physics libraries. 

Reflection

This project is based on the concept of recreating a Newton’s Cradle using the Matter.js physics engine. The goal is to duplicate how a real Newton’s Cradle works, where a series of suspended balls transfer energy through collisions when one ball is pulled back and released. I aimed to simulate this behavior by using physics-based properties like gravity, restitution, and constraints to make the motion feel as realistic as possible. Instead of manually animating the movement, the project relies on the physics engine to naturally calculate how the balls swing and interact, allowing me to explore how energy and motion behave in a simulated environment.

Haris – Assignment 10

Concept

For this assignment I was thinking of different ways I could implement the physics engine into some real world examples. One of the first things that came to mind was the pinball game. I remember when I was a kid and my dad bought me a small pinball machine I spent hours playing on it. Since the game is basically pushing a ball and letting it interact with paddles and bumpers it was perfect for this project and the use of Matter.js library.

The concept is similar to the normal pinball game, there is a ball on the far right and in the beginning you have to hit space to push it out of the starting position and then your goal is to control the paddles with the left and right arrows to score as many points as possible by hitting the bumpers until the ball inevitably hits the ground. Since I was working off of personal reference my game had 3 balls per round so I decided to add 3 lives to the game so the user can try to get the highest score.

Since the game elements take a lot of room of the canvas I had to make the canvas pretty big so I would recommend opening the sketch in the new window.

Process

I started the project by first creating an open canvas and just adding the bumpers and the spinner. The bumpers are the key component of the game so I believe the “world” should be created around them and not force them to fit into the “world”.

Once the spinner was working it was time to add the walls and the ball.

function updateSpinner() {
  Body.setAngle(spinner, spinner.angle + 0.04);
}

Making the spinner spin was quite simple and didn’t give me any issues. But then it was time to add the paddles and the collision with the ball.

For this I decided to use the Collision Events:

Events.on(engine, "collisionStart", function (event) {
  for (let pair of event.pairs) {
    let a = pair.bodyA;
    let b = pair.bodyB;

    // Ball + bumper
    if (
      (a.label === "ball" && b.label === "bumper") ||
      (a.label === "bumper" && b.label === "ball")
    ) {
      score += 10;
      collisionFlash = 10;
      shake = 10;

      let bumper = a.label === "bumper" ? a : b;
      bumper.hitTimer = 12;

      let currentBall = a.label === "ball" ? a : b;
      Body.applyForce(currentBall, currentBall.position, {
        x: random(-0.01, 0.01),
        y: -0.015,
      });
    }

After that was done it was time to move to the walls.

This was my original idea. In reference to what I remember my old pinball machine looking like I wanted to create a small opening where the ball would slide out of. But there was one huge issue with this that I overlooked at the time. If you notice 2 of the walls are overlapping which I didn’t think would be an issue but it proved to be a major one. The bug that kept happening is that because of the overlap the ball kept hitting an invisible wall and kept just bouncing back straight to the beginning. This is obviously a game breaking bug so it needed to be fixed. I tried lowering and raising the angled wall but nothing seemed to fix it because overlapping was the only way of keeping the ball from getting stuck between the 2 walls so I came up with an alternate position for the angled wall so it wouldn’t have to overlap.

By placing it in the top it didn’t overlap with anything and it also added some diversity to the game as the ball could bounce off of it and create different plays each game.

Another challenge that occurred was that the ball would move too fast and would thus phase through the walls and the paddles which would make the user lose points for doing nothing wrong. So I decided to limit the ball speed.

function limitBallSpeed() {
  let maxSpeed = 16;

  let vx = ball.velocity.x;
  let vy = ball.velocity.y;
  let speed = sqrt(vx * vx + vy * vy);

  if (speed > maxSpeed) {
    let scale = maxSpeed / speed;
    Body.setVelocity(ball, {
      x: vx * scale,
      y: vy * scale,
    });
  }
}

This fixed the issue and made the game much more enjotable.

After that it was time for some style changes and just adding the score and lives and game over screen which were quite simple and I also decided to add a screen shake feature when the bumpers are hit for some extra depth. And thus we have the final product.

Code Highlight

One of the most interesting parts of the project is how the paddles are implemented using constraints and controlled rotation, rather than simple position changes.

paddleLeftPivot = Constraint.create({
  bodyA: paddleLeft,
  pointB: { x: 270, y: 610 },
  pointA: { x: -50, y: 0 },
  stiffness: 1,
  length: 0,
});

paddleRightPivot = Constraint.create({
  bodyA: paddleRight,
  pointB: { x: 630, y: 610 },
  pointA: { x: 50, y: 0 },
  stiffness: 1,
  length: 0,
});

This code creates a pivot system, anchoring each paddle to a fixed point in the world. Instead of freely moving, the paddles rotate around these anchor points, similar to real pinball machines.

To control the paddles, I use angular velocity:

// Left paddle
if (keyCode === LEFT_ARROW) {
  Body.setAngularVelocity(paddleLeft, -0.35);
}

// Right paddle
if (keyCode === RIGHT_ARROW) {
  Body.setAngularVelocity(paddleRight, 0.35);
}

And then limit their rotation:

let leftAngle = constrain(paddleLeft.angle, -0.9, 0.25);
let rightAngle = constrain(paddleRight.angle, -0.25, 0.9);

Future Improvements

Overall I am really happy with how the project turned out. I have learned so much about the Matter.js physics system and I am eager to learn more and explore using it in my future projects. As for the improvements and future features I would really like to maybe add music and sound effects to the game as I believe that is a one of the core parts of the original arcade pinball machines. I would also like to maybe add some background images instead of just a gradient background. My pinball machine was green with some cartoon characters on it and many online I have seen have some cartoonish design so maybe exploring that would be the next step, but I don’t want to make it hard to focus on the game so it will need some testing.

Yash – Assignment 10

Vintage Pachinko Arcade Simulation

1. Concept & Inspiration

For this assignment, I wanted to go beyond a standard Plinko board and create a vibrant, interactive simulation of a vintage arcade Pachinko machine. My primary inspiration was a video of a Vintage Nishijin Pachinko machine (Thunderbird model).

I carefully studied the aesthetics of the machine in the video and aimed to recreate its distinctive look and feel. Key features I implemented based on this reference include:

  • Color Palette: The distinct vintage teal/cyan background with a thick wooden and chrome-style outer cabinet.

  • Mechanical Elements: A pull-down spring lever that shoots the balls, rather than a simple mouse click.

  • The “Thunderbird” Bumper: A central, highly bouncy bumper (restitution set to 1.5) modeled after the colorful centerpiece in the real machine.

  • Arcade Atmosphere: Blinking perimeter lights, a 30-second countdown timer, and flashing “INSERT COIN” / “GAME OVER” text to give it an authentic retro arcade feel.

2. Embedded Sketch

 

 

3. Code Highlight

I am particularly proud of how I integrated Matter.js physics with p5.js visual UI states, specifically in the creation of the interactive spring lever.

Creating a lever required mapping mouse interactions to specific coordinate constraints, allowing the user to pull the lever down to build “tension” and releasing it to trigger the ball drop. I also added a bouncing UI indicator using a sine wave function to guide the user.

// From drawLever() function
if (gameState === "START") {
  // Uses a sine wave based on frameCount to make the arrow bounce smoothly
  let bounce = sin(frameCount * 0.1) * 10;
  
  fill(255, 255, 0);
  noStroke();
  drawingContext.shadowBlur = 15;
  drawingContext.shadowColor = color(255, 255, 0);
  
  // Glowing Arrow pointing to lever
  triangle(
    lever.x - 15, lever.baseY - 40 + bounce, 
    lever.x + 15, lever.baseY - 40 + bounce, 
    lever.x, lever.baseY - 20 + bounce
  );
  rect(lever.x - 5, lever.baseY - 60 + bounce, 10, 20);
  
  textSize(14);
  textStyle(BOLD);
  textAlign(CENTER);
  text("PULL DOWN", lever.x, lever.baseY - 70 + bounce);
}

4. Milestones and Challenges

Challenge 1: Setting up Matter.js Geometry and Pins

The first major challenge was simply moving away from standard p5.js coordinates to the Matter.js physics world. I had to learn how to create static boundaries and an array of static pins, and then render their vertices correctly.

Challenge 2: Creating Pockets and Collision Sensors

The next big hurdle was figuring out how to register a “score”. I couldn’t just use standard p5.js distance (dist()) checks because the balls are governed by the physics engine. I had to build a custom Pocket class that grouped three physical walls together to form a U-shape, and then add an invisible isSensor: true physical body inside it. Finally, I used Matter.Events.on(‘collisionStart’) to detect when a ball entered that sensor.

Challenge 3: Adding Game States and Audio

Integrating audio with p5.sound introduced a new challenge: browser autoplay policies. I had to restructure the start of the game so that the background music and sounds only triggered after the user’s first click on the lever (userStartAudio()). Managing the 30-second timer alongside the physics engine updates also required careful state management (“START”, “PLAYING”, “GAMEOVER”).

5. Reflection and Future Work

Balancing the physics was much harder than I expected. Tweaking gravity, density, and friction (restitution) took hours of trial and error to make the balls feel like real glass/steel arcade marbles rather than floaty balloons or heavy rocks.

Future Improvements:

  • Local High Scores: I would love to use localStorage to save the highest score so players can compete.

  • Particle Effects: When a ball lands in a pocket, it would be amazing to trigger a burst of p5.js particles (confetti) alongside the sound effect.

  • Dynamic Obstacles: Adding moving platforms or spinning wheels powered by Matter.js constraints to make the board more chaotic over time.

Assignment 10- Bee swarm

ConceptThis project explores swarm behavior as something emotional rather than purely biological. I was interested in how a group can move together without ever fully becoming one thing. Instead of treating the bees as literal insects, I approached them more like particles of attention or energy that are constantly negotiating space, attraction, and distance.

The interaction is centered around the mouse, which acts almost like a shifting force field. The bees are drawn toward it, but never fully settle. They resist each other through separation forces, creating a constant tension between clustering and dispersing. I wanted the movement to feel alive, slightly unpredictable, and never static.

Visually, the hexagonal grid references a honeycomb structure, but it is not rigid or dominant. It behaves more like a responsive environment. When collisions happen, the grid lights up and ripples expand outward, turning invisible physics interactions into visible traces. This transforms collisions from purely mechanical events into something more atmospheric and expressive.

Inspiration came loosely from flocking systems, especially murmuration patterns, as well as particle simulations that feel soft and organic rather than rigid. I was also thinking about systems where small interactions leave temporary marks in space.

Code Highlight (What I’m Proud Of)

One part of the code I’m particularly proud of is the behavior system where multiple forces are layered together to create the swarm effect:

// SEEK MOUSE
let seek = p5.Vector.sub(mouseVec, pos);
seek.normalize();

Body.applyForce(b, b.position, {
  x: seek.x * strength,
  y: seek.y * strength
});

// SEPARATION
if (d < 25) {
  let escape = p5.Vector.sub(pos, otherPos);
  escape.normalize();
  escape.mult(0.0002);
  Body.applyForce(b, b.position, { x: escape.x, y: escape.y });
}

What I like about this is that the motion is not coming from one rule, but from multiple competing forces. The bees are simultaneously being pulled, pushed, and slightly randomized through noise. That layering makes the system feel less artificial and more like something emergent.

Embedded Sketch

Milestones and Challenges

Milestone 1: The Hexagonal Environment

Setting up the basic p5.js canvas and draw the background pattern. I didn’t add physics yet, just using math to tile a grid of hexagons.

Milestone 2: Introducing Physics & Spawning Bees

Bringing in Matter.js. I created the physics engine, turn off gravity so things float, and spawn our “bees” (physical circles) into the world.

Milestone 3: Following the Cursor

Applying physical forces to make the bees seek the mouse. I also added a speed limiter so they don’t accelerate infinitely and fly off the screen.

Milestone 4: Organic Swarm Movement (Separation & Wiggle)

I added a “Separation” force that pushes the bees away from each other if they get too close, and Perlin noise to make them wiggle like real insects.

Milestone 5: Detecting Collisions & Drawing Ripples

I Introduced the Events.on() listener. Whenever the Matter.js engine detects two bees colliding, it spawns a new Ripple object at that exact coordinate, which expands and fades away.

Milestone 6: The Final Polish (Hexagon Glow)

During collisions, I now check the distance between the collision point and our grid of hexagons. If a hexagon is close, its glow value is set to 1. In drawHexGrid, this glow translates to opacity, fading out slowly over time using h.glow *= 0.96.

Reflection and Future Improvements

Looking back, the project successfully explores how forces can be layered to produce emergent behavior. The combination of attraction, separation, and noise creates a system that feels alive and responsive rather than scripted.

The collision system works well visually, but it is currently limited to collisionStart. If I were to develop this further, I would explore additional collision events like collisionActive and collisionEnd to create more sustained or evolving effects, such as continuous glowing or gradual decay tied to contact duration.

I am also interested in pushing the visual language further. Right now, the bees are quite minimal. There is potential to experiment with scale, transparency, or trails to make the swarm feel even more atmospheric.

Another direction would be to shift the interaction away from the mouse and explore autonomous behaviors, where the system evolves on its own or responds to less direct inputs.

I feel like this project helped me think of physics not just as simulation, but as a design tool for shaping movement, interaction, and visual rhythm.

Assignment 10 – Giuseppe

My main inspiration came from my dear friend Youssab William’s midterm project ASCENT. I love the idea of platformers and honestly Youssab inspired me to make something on p5 that has platformer mechanics.

As an act of creative freedom and my usual obsession with ownership, I want to call this project Giuseppe.

soooo here’s the sketch. Use Arrows or WASD to move

 

but wait. this isn’t a platformer. not even close actually. so what happened? we will explore that in this documentation

Before writing a single line, I mapped out what matter.js actually needed to do for this to work.  I created a simple platformer and saw how things will go from there.

Well…yeah.. this wasnt what I expected. I don’t know what I expected hoenstly. Just not something… this bad?

I immediately scrapped the idea after this video. But before pulling out my hair and making yet another 17th sketch trying to think for a concept for this assignment, I noticed that the little red cube sticks on the sides of the platforms. This sparked an idea in me, a parkour-like game that a ninja (later simplified to a cube) jumping from wall to wall to avoid the lava. Just like those old mobile games. Then Giuseppe was born.

The concept is a vertical survival game. You wall-jump up an endless shaft while lava rises beneath you. There are zones. There are coins. There is a freaking lava floor that will inevitably come and get you.

The player body never has velocity set directly except during wall jumps. Everything else is force application. Horizontal movement applies a constant force every frame:

let moveForce = 0.0012;
if (keyIsDown(LEFT_ARROW) || keyIsDown(65))
  Body.applyForce(playerBody, playerBody.position, { x: -moveForce, y: 0 });
if (keyIsDown(RIGHT_ARROW) || keyIsDown(68))
  Body.applyForce(playerBody, playerBody.position, { x: moveForce, y: 0 });

if (playerBody.velocity.x > 5)
  Body.setVelocity(playerBody, { x: 5, y: playerBody.velocity.y });
if (playerBody.velocity.x < -5)
  Body.setVelocity(playerBody, { x: -5, y: playerBody.velocity.y });

The speed cap is load-bearing. Without it the player accelerates forever and becomes impossible to control in about four seconds. The cap is also what makes the movement feel snappy rather than floaty, because the player reaches max speed almost immediately and stays there. Force application without a cap is just a slow velocity set with extra steps

I then entered my usual 3 am flowstate and I reached this position.

[im trying to upload but facing issues so i cant really upload attachments]

Thr wall grip part is the part I’m most proud of, and also the part that took the longest to not be horrible.

The grip has two phases. When the player first touches a wall, the engine fires a counter-force upward that decays linearly to zero over 4000ms. At t=0 the counter-force exactly cancels gravity so the player feels weightless on the wall. By t=4000ms it’s gone and the player slides off. After the grip expires there’s a 500ms push-off phase where a small lateral force nudges the player away from the wall and canjump is set to false, so you can’t wall-jump from a dead grip.

if (contactAge < GRIP_DURATION) {
  let t = contactAge / GRIP_DURATION;
  let counterForce = lerp(0.0012, 0, t);
  Body.applyForce(playerBody, playerBody.position, {
    x: 0,
    y: -counterForce,
  });
} else if (contactAge < GRIP_DURATION + PUSH_DURATION) {
  Body.applyForce(playerBody, playerBody.position, {
    x: -wallSide * 0.0015,
    y: 0,
  });
  canJump = false;
}

The 0.0012 is not random. matter.js default gravity produces a downward acceleration of 0.001 per update tick at default settings. The counter-force matches it exactly so the player hovers. I lied, AI found that value for me when I asked it why the player was either rocketing upward or sliding instantly. The fix was embarrassingly simple once I knew what to look for.

The grip timer also renders as a visual bar on the wall panel. The bar height shrinks as grip time expires and turns red during the push-off phase so you always know exactly how much time you have left. I added that late and it completely changed how readable the game was.

The collision architecture has three events all running simultaneously.

beforeUpdate resets canJump, wallSide, and touchingWall to false/zero every single frame before any collision detection runs. This is important because matter.js collision events only fire when contact is active, which means if nothing fires this frame, the flags stay false. No ghost jumps. No lingering wall contact.

collisionActive runs every frame the player overlaps any surface and handles all the grip logic above. It’s also where wallSide gets set, by comparing the player’s x position to the wall body’s x position to determine which side the wall is on.

collisionStart handles orb collection as a one-shot event. Orbs are sensor bodies so they have zero physical response, but they still fire collision events. When an orb-player pair is detected, collectOrb() removes the body from the world, increments the coin count, and spawns a particle burst.

Events.on(physEngine, "collisionStart", function (event) {
  for (let pair of event.pairs) {
    let bodyA = pair.bodyA, bodyB = pair.bodyB;
    if (
      (bodyA.label === "Orb" || bodyB.label === "Orb") &&
      (bodyA.label === "Player" || bodyB.label === "Player")
    ) {
      collectOrb(bodyA.label === "Orb" ? bodyA : bodyB);
    }
  }
});

The game has five zones that unlock at ascending height thresholds. Each zone changes the wall color, background color, and lava color simultaneously. The transition happens in one line: currentZone = newZoneIdx, and a banner fades in with the zone name then dissipates over about 100 frames.

The zone palette design was fun. I wanted each zone to feel like a different biosphere. SURFACE is warm red on near-black. THE CAVERNS goes amber on deep brown. CRYSTAL DEEP goes cold blue on dark navy. THE STORM goes violet on almost-black. THE VOID goes teal on pure void. The lava color shifts with the zone too, so in CRYSTAL DEEP the rising floor is a cold electric blue rather than orange, which is a detail I’m very happy with and nobody will probably notice.

The first working version was a flat canvas with a rectangle and a ground. No camera, no walls, just a box with gravity and a jump. That worked in maybe 30 minutes. Everything after that was a long series of things that almost worked.

The wall detection broke me for a while. The original approach used collisionActive to detect wall contact but I kept getting canJump = true from the ground at the same time as wallSide = 1 from a wall, which meant ground jumps sometimes registered as wall jumps and gave you the kick-off velocity by accident. The fix was the label check: if (surfaceBody.label !== "Wall" && surfaceBody.label !== "Ground") continue gates everything behind identity. The floor has label “Ground” and never sets wallSide. Walls have label “Wall” and never set canJump during push-off. Clean separation.

The camera also gave me problems. My first implementation was camY = CANVAS_H/2 - playerBody.position.y with no lerp, which meant the camera snapped instantly to the player position and the whole canvas strobed. Adding the lerp (camY = lerp(camY, camYTarget, 0.1)) was one line and made the whole thing feel like a proper game. That 0.1 lerp factor took me a while to find. At 0.05 the camera felt detached. At 0.2 it still twitched. 0.1 was the number.

The game is more playable than I expected at this stage. The wall jump interaction teaches itself within about three or four deaths, which is a good sign. Players understand immediately that the walls are grippable and that the lava is not.

The zone system adds something I wasn’t sure would land. The color transitions give the game a sense of depth even though the gameplay is identical in every zone. There’s something psychologically effective about a wall turning violet that makes you feel like you’ve gone somewhere.

Two things I’m not settled about. The lava speed is constant right now and it should probably accelerate as you get deeper into the game. A flat rise rate means the game’s difficulty is almost entirely dependent on your wall jump skill, which is fine but I think a rising speed floor would create more interesting decision moments. The second thing is audio. The game is very silent and I think a low bass rumble that rises in pitch as the lava approaches would communicate danger in a way the red vignette edge alone doesn’t quite reach. The vignette is good. Sound would make it visceral.

I also want to revisit the particle burst on wall jump. Right now it’s an orange burst at the jump origin, which looks fine. I think making it directional, so the particles kick backward from the wall jump direction, would make the jump feel more physically grounded without any extra complexity.