The Stride Part Two

Storytelling midterm first draft

Marcus Thomas

Dec 21, 2024

In 2124, Paris hosts the Olympic Games, an event that mirrors the evolving tension between human ability and technological advancement. The city is a beacon of innovation, blending its rich cultural heritage with cutting-edge design. Mia, a 25-year-old track and field athlete, prepares for the competition of her life. Mia has hemophilia, and while she trains with the same intensity and drive as her peers, she depends on the VitaGuard, a medical patch that monitors her blood flow and automatically delivers clotting factors when necessary. This small device, affixed to her arm, is both a lifeline and a source of scrutiny. While the VitaGuard enables Mia to compete safely, it also sparks controversy over whether technology like this has a place in elite sports.

Mia’s reliance on the a sets her apart, not only from her competitors but from society’s expectations of what it means to compete. Technology is omnipresent in daily life, but in the realm of sports, it remains contested territory. The public is divided as some see Mia as a symbol of perseverance and of technology leveling the playing field for athletes who would otherwise be sidelined. Others, however, question whether her success is truly her own. Is she competing, or is it the device competing for her? This debate intensifies when Lena’s coach formally challenges Mia’s place in the competition, arguing that the VitaGuard offers her an unfair advantage.

Lena, Mia’s childhood friend and fellow competitor, is caught in the middle. As a young runner, Lena would often outpace Mia, not out of superior skill but simply because Mia’s condition held her back. With the VitaGuard, Mia is finally running at the level she has always aspired to, but this achievement comes with new challenges. Lena privately supports Mia’s right to compete but remains publicly silent, aware of the controversy her coach has sparked. This silence weighs heavily on Mia, amplifying her sense of isolation.

The track where Mia hopes to compete

As the pressure mounts, Mia grapples with the growing conflict between her reliance on the VitaGuard and her own sense of self. The technology that keeps her safe on the track also fuels her deepest doubts—does the device diminish her achievements, making her victories seem less earned? In quieter moments, Mia questions whether her hard work and determination will ever be recognized without the shadow of the VitaGuard looming over her.

The tension reaches a peak when Mia is called before the Olympic committee to defend her use of the patch. In a carefully measured argument, she explains that the VitaGuard does not give her an edge—it merely allows her to compete on equal terms with athletes whose bodies don’t require such interventions. The device does not make her faster or stronger; it simply ensures her survival. Yet, beyond this public defense, Mia faces a more personal reckoning. She must decide for herself whether the device defines her success or if it is her dedication, skill, and resilience that carry her forward.

Mia overlooks Paris, anxious about whether she'll get her shot at The Gold

The committee ultimately rules in Mia’s favor, setting a precedent for athletes who rely on medical technology to compete. But for Mia, the victory is more than a legal or ethical triumph, it's a moment of profound self-realization. As she steps onto the track for the final race, Mia runs not just to win but to reclaim her sense of agency. The VitaGuard is there, quietly doing its job, but it no longer represents the doubts that once haunted her. Mia finishes the race knowing that the patch, though vital to her health, is not what defines her. Her strength, both physical and emotional, transcends the technology that supports her.

In the end, Mia’s journey challenges the notion of what it means to compete. Her story is not just about navigating public perception or technological controversy; it is about the internal struggle to embrace one’s abilities, with or without assistance. Through Mia, the world of 2124 must confront its evolving relationship with technology and question where the line between fairness and enhancement truly lies.

Mia runs towards a future as an inspiration to the world

Code Breakdown

Figure 8 Track

We draw the track as a polyline (sampled points) and orient all glyphs by rotating to the tangent (rotate(p.ang)).

// Parametric curve + tangent
x = a * sin(t),  y = (b/2) * sin(2t)

function infinityPoint(tau, a, b) {
  const x = a * sin(tau);
  const y = (b * 0.5) * sin(2 * tau);
  const dx = a * cos(tau);
  const dy = b * cos(2 * tau);
  const ang = atan2(dy, dx); // tangent angle
  return { x, y, ang };
}

4-Behaviors

Seasons = Turtle feeding cycles

Fin Strokes = Distance Measuring

Breath = Religious Timing/Calendar

Blink = Day/Night Cycle

// Parametric curve + tangent
x = a * sin(t),  y = (b/2) * sin(2t)

function infinityPoint(tau, a, b) {
  const x = a * sin(tau);
  const y = (b * 0.5) * sin(2 * tau);
  const dx = a * cos(tau);
  const dy = b * cos(2 * tau);
  const ang = atan2(dy, dx); // tangent angle
  return { x, y, ang };
}

Visual Language

Track Color Season color slowly shifts via four stops using seasonalHue() and wrap-aware lerpHue()

const seasonHue = seasonalHue(seasonCyc); // amber → green → violet → cyan
stroke(seasonHue, …); drawInfinityPolyline(...);


Track Color:
Season color slowly shifts via four stops using seasonalHue() and wrap-aware lerpHue()

const seasonHue = seasonalHue(seasonCyc); // amber → green → violet → cyan
stroke(seasonHue, …); drawInfinityPolyline(...);

An image of MF DOOM's iconic mask is divided into a grid of tiles. When a button is pressed, random hidden tiles are revealed, and newly revealed tiles briefly glow in response to the sound.

revealed[r][c] = true;

Reflection

This project sits somewhere between an instrument, a game, and a piece of interactive visual art.

It asks a simple question:

What if making music wasn’t about building something new — but revealing something that already exists?

By tying sound, touch, and imagery together, the machine transforms rhythm into progress.

Sometimes, the beat isn’t the point. Sometimes, the beat is the key.

The Stride Part Two

Storytelling midterm first draft

Marcus Thomas

Dec 21, 2024

In 2124, Paris hosts the Olympic Games, an event that mirrors the evolving tension between human ability and technological advancement. The city is a beacon of innovation, blending its rich cultural heritage with cutting-edge design. Mia, a 25-year-old track and field athlete, prepares for the competition of her life. Mia has hemophilia, and while she trains with the same intensity and drive as her peers, she depends on the VitaGuard, a medical patch that monitors her blood flow and automatically delivers clotting factors when necessary. This small device, affixed to her arm, is both a lifeline and a source of scrutiny. While the VitaGuard enables Mia to compete safely, it also sparks controversy over whether technology like this has a place in elite sports.

Mia’s reliance on the a sets her apart, not only from her competitors but from society’s expectations of what it means to compete. Technology is omnipresent in daily life, but in the realm of sports, it remains contested territory. The public is divided as some see Mia as a symbol of perseverance and of technology leveling the playing field for athletes who would otherwise be sidelined. Others, however, question whether her success is truly her own. Is she competing, or is it the device competing for her? This debate intensifies when Lena’s coach formally challenges Mia’s place in the competition, arguing that the VitaGuard offers her an unfair advantage.

Lena, Mia’s childhood friend and fellow competitor, is caught in the middle. As a young runner, Lena would often outpace Mia, not out of superior skill but simply because Mia’s condition held her back. With the VitaGuard, Mia is finally running at the level she has always aspired to, but this achievement comes with new challenges. Lena privately supports Mia’s right to compete but remains publicly silent, aware of the controversy her coach has sparked. This silence weighs heavily on Mia, amplifying her sense of isolation.

The track where Mia hopes to compete

As the pressure mounts, Mia grapples with the growing conflict between her reliance on the VitaGuard and her own sense of self. The technology that keeps her safe on the track also fuels her deepest doubts—does the device diminish her achievements, making her victories seem less earned? In quieter moments, Mia questions whether her hard work and determination will ever be recognized without the shadow of the VitaGuard looming over her.

The tension reaches a peak when Mia is called before the Olympic committee to defend her use of the patch. In a carefully measured argument, she explains that the VitaGuard does not give her an edge—it merely allows her to compete on equal terms with athletes whose bodies don’t require such interventions. The device does not make her faster or stronger; it simply ensures her survival. Yet, beyond this public defense, Mia faces a more personal reckoning. She must decide for herself whether the device defines her success or if it is her dedication, skill, and resilience that carry her forward.

Mia overlooks Paris, anxious about whether she'll get her shot at The Gold

The committee ultimately rules in Mia’s favor, setting a precedent for athletes who rely on medical technology to compete. But for Mia, the victory is more than a legal or ethical triumph, it's a moment of profound self-realization. As she steps onto the track for the final race, Mia runs not just to win but to reclaim her sense of agency. The VitaGuard is there, quietly doing its job, but it no longer represents the doubts that once haunted her. Mia finishes the race knowing that the patch, though vital to her health, is not what defines her. Her strength, both physical and emotional, transcends the technology that supports her.

In the end, Mia’s journey challenges the notion of what it means to compete. Her story is not just about navigating public perception or technological controversy; it is about the internal struggle to embrace one’s abilities, with or without assistance. Through Mia, the world of 2124 must confront its evolving relationship with technology and question where the line between fairness and enhancement truly lies.

Mia runs towards a future as an inspiration to the world

The Stride Part Two

Storytelling midterm first draft

Marcus Thomas

Dec 21, 2024

In 2124, Paris hosts the Olympic Games, an event that mirrors the evolving tension between human ability and technological advancement. The city is a beacon of innovation, blending its rich cultural heritage with cutting-edge design. Mia, a 25-year-old track and field athlete, prepares for the competition of her life. Mia has hemophilia, and while she trains with the same intensity and drive as her peers, she depends on the VitaGuard, a medical patch that monitors her blood flow and automatically delivers clotting factors when necessary. This small device, affixed to her arm, is both a lifeline and a source of scrutiny. While the VitaGuard enables Mia to compete safely, it also sparks controversy over whether technology like this has a place in elite sports.

Mia’s reliance on the a sets her apart, not only from her competitors but from society’s expectations of what it means to compete. Technology is omnipresent in daily life, but in the realm of sports, it remains contested territory. The public is divided as some see Mia as a symbol of perseverance and of technology leveling the playing field for athletes who would otherwise be sidelined. Others, however, question whether her success is truly her own. Is she competing, or is it the device competing for her? This debate intensifies when Lena’s coach formally challenges Mia’s place in the competition, arguing that the VitaGuard offers her an unfair advantage.

Lena, Mia’s childhood friend and fellow competitor, is caught in the middle. As a young runner, Lena would often outpace Mia, not out of superior skill but simply because Mia’s condition held her back. With the VitaGuard, Mia is finally running at the level she has always aspired to, but this achievement comes with new challenges. Lena privately supports Mia’s right to compete but remains publicly silent, aware of the controversy her coach has sparked. This silence weighs heavily on Mia, amplifying her sense of isolation.

The track where Mia hopes to compete

As the pressure mounts, Mia grapples with the growing conflict between her reliance on the VitaGuard and her own sense of self. The technology that keeps her safe on the track also fuels her deepest doubts—does the device diminish her achievements, making her victories seem less earned? In quieter moments, Mia questions whether her hard work and determination will ever be recognized without the shadow of the VitaGuard looming over her.

The tension reaches a peak when Mia is called before the Olympic committee to defend her use of the patch. In a carefully measured argument, she explains that the VitaGuard does not give her an edge—it merely allows her to compete on equal terms with athletes whose bodies don’t require such interventions. The device does not make her faster or stronger; it simply ensures her survival. Yet, beyond this public defense, Mia faces a more personal reckoning. She must decide for herself whether the device defines her success or if it is her dedication, skill, and resilience that carry her forward.

Mia overlooks Paris, anxious about whether she'll get her shot at The Gold

The committee ultimately rules in Mia’s favor, setting a precedent for athletes who rely on medical technology to compete. But for Mia, the victory is more than a legal or ethical triumph, it's a moment of profound self-realization. As she steps onto the track for the final race, Mia runs not just to win but to reclaim her sense of agency. The VitaGuard is there, quietly doing its job, but it no longer represents the doubts that once haunted her. Mia finishes the race knowing that the patch, though vital to her health, is not what defines her. Her strength, both physical and emotional, transcends the technology that supports her.

In the end, Mia’s journey challenges the notion of what it means to compete. Her story is not just about navigating public perception or technological controversy; it is about the internal struggle to embrace one’s abilities, with or without assistance. Through Mia, the world of 2124 must confront its evolving relationship with technology and question where the line between fairness and enhancement truly lies.

Mia runs towards a future as an inspiration to the world

Process

Physical Interface

At the heart of the system is a custom-built controller powered by an Arduino ESP32 Feather housed in a cardboard enclosure.

The interface includes:

  • Four physical buttons
    • Each button triggers a different sound sample and reveals tiles from a specific region of the image.
  • One slide potentiometer
    • The slider controls pitch, shifting the musical mood from low and heavy to sharp and elevated. It also acts as a modifier, changing how the sounds feel without changing how they’re played.

Breadboard with inputs

Full view + Slide Potentiometer

DOOMBOX Exterior Housing

Arduino IDE: Reading the Interface

On the hardware side, the ESP32 reads four buttons and a B10K slide potentiometer. Each loop, it sends their values as a single line of comma-separated data over USB serial.

#define B1 13
#define B2 12
#define B3 27
#define B4 33
#define POT_PIN 32

void loop() {
  Serial.print(digitalRead(B1));
  Serial.print(',');
  Serial.print(digitalRead(B2));
  Serial.print(',');
  Serial.print(digitalRead(B3));
  Serial.print(',');
  Serial.print(digitalRead(B4));
  Serial.print(',');
  Serial.println(analogRead(POT_PIN));
}

Processing: Sound Playback and Pitch Control

In Processing, serial data is parsed and mapped to musical behavior. Each button triggers a drum sample, while the slider controls pitch by adjusting playback rate.

pitchRate = map(potRaw, 0, 4095, 0.5, 2.0);
pitchRate = constrain(pitchRate, 0.5, 2.0);

drums[i].rate(pitchRate);
drums[i].play();

Processing: Image Reveal

An image of MF DOOM's iconic mask is divided into a grid of tiles. When a button is pressed, random hidden tiles are revealed, and newly revealed tiles briefly glow in response to the sound.

revealed[r][c] = true;

Processing: Image Reveal

On the hardware side, the ESP32 reads four buttons and a B10K slide potentiometer. Each loop, it sends their values as a single line of comma-separated data over USB serial.

#define B1 13
#define B2 12
#define B3 27
#define B4 33
#define POT_PIN 32

void loop() {
  Serial.print(digitalRead(B1));
  Serial.print(',');
  Serial.print(digitalRead(B2));
  Serial.print(',');
  Serial.print(digitalRead(B3));
  Serial.print(',');
  Serial.print(digitalRead(B4));
  Serial.print(',');
  Serial.println(analogRead(POT_PIN));
}

Reflection

This project sits somewhere between an instrument, a game, and a piece of interactive visual art.

It asks a simple question:

What if making music wasn’t about building something new — but revealing something that already exists?

By tying sound, touch, and imagery together, the machine transforms rhythm into progress.

Sometimes, the beat isn’t the point. Sometimes, the beat is the key.

Logic be Dammed:
Representing Forces and Nature in Code

Storytelling midterm first draft

Marcus Thomas

Dec 21, 2024

In 2124, Paris hosts the Olympic Games, an event that mirrors the evolving tension between human ability and technological advancement. The city is a beacon of innovation, blending its rich cultural heritage with cutting-edge design. Mia, a 25-year-old track and field athlete, prepares for the competition of her life. Mia has hemophilia, and while she trains with the same intensity and drive as her peers, she depends on the VitaGuard, a medical patch that monitors her blood flow and automatically delivers clotting factors when necessary. This small device, affixed to her arm, is both a lifeline and a source of scrutiny. While the VitaGuard enables Mia to compete safely, it also sparks controversy over whether technology like this has a place in elite sports.

Mia’s reliance on the a sets her apart, not only from her competitors but from society’s expectations of what it means to compete. Technology is omnipresent in daily life, but in the realm of sports, it remains contested territory. The public is divided as some see Mia as a symbol of perseverance and of technology leveling the playing field for athletes who would otherwise be sidelined. Others, however, question whether her success is truly her own. Is she competing, or is it the device competing for her? This debate intensifies when Lena’s coach formally challenges Mia’s place in the competition, arguing that the VitaGuard offers her an unfair advantage.

Lena, Mia’s childhood friend and fellow competitor, is caught in the middle. As a young runner, Lena would often outpace Mia, not out of superior skill but simply because Mia’s condition held her back. With the VitaGuard, Mia is finally running at the level she has always aspired to, but this achievement comes with new challenges. Lena privately supports Mia’s right to compete but remains publicly silent, aware of the controversy her coach has sparked. This silence weighs heavily on Mia, amplifying her sense of isolation.

The track where Mia hopes to compete

As the pressure mounts, Mia grapples with the growing conflict between her reliance on the VitaGuard and her own sense of self. The technology that keeps her safe on the track also fuels her deepest doubts—does the device diminish her achievements, making her victories seem less earned? In quieter moments, Mia questions whether her hard work and determination will ever be recognized without the shadow of the VitaGuard looming over her.

The tension reaches a peak when Mia is called before the Olympic committee to defend her use of the patch. In a carefully measured argument, she explains that the VitaGuard does not give her an edge—it merely allows her to compete on equal terms with athletes whose bodies don’t require such interventions. The device does not make her faster or stronger; it simply ensures her survival. Yet, beyond this public defense, Mia faces a more personal reckoning. She must decide for herself whether the device defines her success or if it is her dedication, skill, and resilience that carry her forward.

Mia overlooks Paris, anxious about whether she'll get her shot at The Gold

The committee ultimately rules in Mia’s favor, setting a precedent for athletes who rely on medical technology to compete. But for Mia, the victory is more than a legal or ethical triumph, it's a moment of profound self-realization. As she steps onto the track for the final race, Mia runs not just to win but to reclaim her sense of agency. The VitaGuard is there, quietly doing its job, but it no longer represents the doubts that once haunted her. Mia finishes the race knowing that the patch, though vital to her health, is not what defines her. Her strength, both physical and emotional, transcends the technology that supports her.

In the end, Mia’s journey challenges the notion of what it means to compete. Her story is not just about navigating public perception or technological controversy; it is about the internal struggle to embrace one’s abilities, with or without assistance. Through Mia, the world of 2124 must confront its evolving relationship with technology and question where the line between fairness and enhancement truly lies.

Mia runs towards a future as an inspiration to the world

Code Breakdown

Classes

  • Hydro – tile grids for water, target, age, barren; column arrays for velCol, noiseCol
    • Builds trunk + branches with Perlin noise and stochastic jitter.
    • Spawns new estuaries on a timer; widens old undammed channels; applies right-side desiccation and water-adjacent recovery.
  • Forest – 2D fields for willow and aspen (0–1). Growth moves toward a cap reduced by barren; blocked under lodges; harvest() does a ring search for richest patch.
  • DamSpans – spans are {row, cL, cR, integrity} across a gap bounded by land. Integrity decays with time and high flow; collapsed spans are removed.
  • Colony, Beaver – array of agents; mortality filter; metrics; per-beaver FSM with vector steering.
  • Lodge – simple sprite; count tied to population

Making the world

Why this order: environment first, then resources, then structures that shape flow, then agents reacting to the current state.

Creates subsystems and enforces the following update order (water → resources → structures → agents).

class World {
  constructor(hud){
    this.hud=hud;
    this.hydro=new Hydro(hud);
    this.forest=new Forest(hud,this.hydro);
    this.dams=new DamSpans(hud,this.hydro);
    this.colony=new Colony(hud,this.hydro,this.dams,this.forest);
    this.lodges=[]; this.updateLodges(true);
  }
  update(){
    this.hydro.update();                     // rivers grow/branch/widen/dry
    this.forest.update(this.lodges,this.hydro); // growth capped by barren
    this.dams.update(this.hydro);            // span decay vs flow
    this.colony.update(this.dams,this.hydro);    // FSM + mortality
    if (this.colony.prunedThisTick){ this.updateLodges(); this.colony.prunedThisTick=false; }
    this.forest.blockUnderLodges(this.lodges,this.hydro);
  }
}

Rivers

The simulation starts with building a target river tree (trunk + noisy branches), reveals it over time (slider), then keep it alive with estuaries, widening, and right-side desiccation.

Beavers “feel” water via noiseCol[c] (stress driver).

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Forests & Barren Tiles

Willows (for building dams) and Aspen (food for the beavers) grow on land toward a cap that shrinks with barren; growth is blocked under lodges and zeroed on water.The simulation starts with building a target river tree (trunk + noisy branches), reveals it over time (slider), then keep it alive with estuaries, widening, and right-side desiccation.

Resulting effects: near water → fertile patches; dry right side → patchy, low-cap growth.

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Dams & Bank-to-Bank Spans

Dam Spans exist only across contiguous water segments bounded by land; integrity increases with work and decays with flow.

This prevents the beavers from spam building, and makes dams visually & mechanically legible.

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Agents & Interaction: Beavers, Vectors, HUD

Beavers are need-driven agents with vector steering.

Input from the right-side menu allows the user to shape conditions.

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Input & HUD

  • Keys: G generate new river; SPACE pause.
  • Mouse: Left = plant Willow, Shift+Left = plant Aspen; toggle Spawn Mode then Right-click to add a random beaver.
  • Sliders (stacked under descriptions; buttons below sliders—no overlap):
    1. River Creation Speed → reveal rate of Hydro.target
    2. Food Spawn Rate (Aspen) → forest growth term
    3. Building Material Spawn Rate (Willow) → forest growth term
    4. Dam Building Speed → per-action span integrity

This closes the system loop: environment drives needs; agents act; structures reshape the environment; HUD lets you adjust parameters and watch new equilibria emerge.

Logic be Dammed:
Representing Forces and Nature in Code

Storytelling midterm first draft

Marcus Thomas

Dec 21, 2024

In 2124, Paris hosts the Olympic Games, an event that mirrors the evolving tension between human ability and technological advancement. The city is a beacon of innovation, blending its rich cultural heritage with cutting-edge design. Mia, a 25-year-old track and field athlete, prepares for the competition of her life. Mia has hemophilia, and while she trains with the same intensity and drive as her peers, she depends on the VitaGuard, a medical patch that monitors her blood flow and automatically delivers clotting factors when necessary. This small device, affixed to her arm, is both a lifeline and a source of scrutiny. While the VitaGuard enables Mia to compete safely, it also sparks controversy over whether technology like this has a place in elite sports.

Mia’s reliance on the a sets her apart, not only from her competitors but from society’s expectations of what it means to compete. Technology is omnipresent in daily life, but in the realm of sports, it remains contested territory. The public is divided as some see Mia as a symbol of perseverance and of technology leveling the playing field for athletes who would otherwise be sidelined. Others, however, question whether her success is truly her own. Is she competing, or is it the device competing for her? This debate intensifies when Lena’s coach formally challenges Mia’s place in the competition, arguing that the VitaGuard offers her an unfair advantage.

Lena, Mia’s childhood friend and fellow competitor, is caught in the middle. As a young runner, Lena would often outpace Mia, not out of superior skill but simply because Mia’s condition held her back. With the VitaGuard, Mia is finally running at the level she has always aspired to, but this achievement comes with new challenges. Lena privately supports Mia’s right to compete but remains publicly silent, aware of the controversy her coach has sparked. This silence weighs heavily on Mia, amplifying her sense of isolation.

The track where Mia hopes to compete

As the pressure mounts, Mia grapples with the growing conflict between her reliance on the VitaGuard and her own sense of self. The technology that keeps her safe on the track also fuels her deepest doubts—does the device diminish her achievements, making her victories seem less earned? In quieter moments, Mia questions whether her hard work and determination will ever be recognized without the shadow of the VitaGuard looming over her.

The tension reaches a peak when Mia is called before the Olympic committee to defend her use of the patch. In a carefully measured argument, she explains that the VitaGuard does not give her an edge—it merely allows her to compete on equal terms with athletes whose bodies don’t require such interventions. The device does not make her faster or stronger; it simply ensures her survival. Yet, beyond this public defense, Mia faces a more personal reckoning. She must decide for herself whether the device defines her success or if it is her dedication, skill, and resilience that carry her forward.

Mia overlooks Paris, anxious about whether she'll get her shot at The Gold

The committee ultimately rules in Mia’s favor, setting a precedent for athletes who rely on medical technology to compete. But for Mia, the victory is more than a legal or ethical triumph, it's a moment of profound self-realization. As she steps onto the track for the final race, Mia runs not just to win but to reclaim her sense of agency. The VitaGuard is there, quietly doing its job, but it no longer represents the doubts that once haunted her. Mia finishes the race knowing that the patch, though vital to her health, is not what defines her. Her strength, both physical and emotional, transcends the technology that supports her.

In the end, Mia’s journey challenges the notion of what it means to compete. Her story is not just about navigating public perception or technological controversy; it is about the internal struggle to embrace one’s abilities, with or without assistance. Through Mia, the world of 2124 must confront its evolving relationship with technology and question where the line between fairness and enhancement truly lies.

Mia runs towards a future as an inspiration to the world

Code Breakdown

Classes

  • Hydro – tile grids for water, target, age, barren; column arrays for velCol, noiseCol
    • Builds trunk + branches with Perlin noise and stochastic jitter.
    • Spawns new estuaries on a timer; widens old undammed channels; applies right-side desiccation and water-adjacent recovery.
  • Forest – 2D fields for willow and aspen (0–1). Growth moves toward a cap reduced by barren; blocked under lodges; harvest() does a ring search for richest patch.
  • DamSpans – spans are {row, cL, cR, integrity} across a gap bounded by land. Integrity decays with time and high flow; collapsed spans are removed.
  • Colony, Beaver – array of agents; mortality filter; metrics; per-beaver FSM with vector steering.
  • Lodge – simple sprite; count tied to population

Making the world

Why this order: environment first, then resources, then structures that shape flow, then agents reacting to the current state.

Creates subsystems and enforces the following update order (water → resources → structures → agents).

class World {
  constructor(hud){
    this.hud=hud;
    this.hydro=new Hydro(hud);
    this.forest=new Forest(hud,this.hydro);
    this.dams=new DamSpans(hud,this.hydro);
    this.colony=new Colony(hud,this.hydro,this.dams,this.forest);
    this.lodges=[]; this.updateLodges(true);
  }
  update(){
    this.hydro.update();                     // rivers grow/branch/widen/dry
    this.forest.update(this.lodges,this.hydro); // growth capped by barren
    this.dams.update(this.hydro);            // span decay vs flow
    this.colony.update(this.dams,this.hydro);    // FSM + mortality
    if (this.colony.prunedThisTick){ this.updateLodges(); this.colony.prunedThisTick=false; }
    this.forest.blockUnderLodges(this.lodges,this.hydro);
  }
}

Rivers

The simulation starts with building a target river tree (trunk + noisy branches), reveals it over time (slider), then keep it alive with estuaries, widening, and right-side desiccation.

Beavers “feel” water via noiseCol[c] (stress driver).

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Forests & Barren Tiles

Willows (for building dams) and Aspen (food for the beavers) grow on land toward a cap that shrinks with barren; growth is blocked under lodges and zeroed on water.The simulation starts with building a target river tree (trunk + noisy branches), reveals it over time (slider), then keep it alive with estuaries, widening, and right-side desiccation.

Resulting effects: near water → fertile patches; dry right side → patchy, low-cap growth.

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Dams & Bank-to-Bank Spans

Dam Spans exist only across contiguous water segments bounded by land; integrity increases with work and decays with flow.

This prevents the beavers from spam building, and makes dams visually & mechanically legible.

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Agents & Interaction: Beavers, Vectors, HUD

Beavers are need-driven agents with vector steering.

Input from the right-side menu allows the user to shape conditions.

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Input & HUD

  • Keys: G generate new river; SPACE pause.
  • Mouse: Left = plant Willow, Shift+Left = plant Aspen; toggle Spawn Mode then Right-click to add a random beaver.
  • Sliders (stacked under descriptions; buttons below sliders—no overlap):
    1. River Creation Speed → reveal rate of Hydro.target
    2. Food Spawn Rate (Aspen) → forest growth term
    3. Building Material Spawn Rate (Willow) → forest growth term
    4. Dam Building Speed → per-action span integrity

This closes the system loop: environment drives needs; agents act; structures reshape the environment; HUD lets you adjust parameters and watch new equilibria emerge.

Logic be Dammed:
Representing Forces and Nature in Code

Storytelling midterm first draft

Marcus Thomas

Dec 21, 2024

In 2124, Paris hosts the Olympic Games, an event that mirrors the evolving tension between human ability and technological advancement. The city is a beacon of innovation, blending its rich cultural heritage with cutting-edge design. Mia, a 25-year-old track and field athlete, prepares for the competition of her life. Mia has hemophilia, and while she trains with the same intensity and drive as her peers, she depends on the VitaGuard, a medical patch that monitors her blood flow and automatically delivers clotting factors when necessary. This small device, affixed to her arm, is both a lifeline and a source of scrutiny. While the VitaGuard enables Mia to compete safely, it also sparks controversy over whether technology like this has a place in elite sports.

Mia’s reliance on the a sets her apart, not only from her competitors but from society’s expectations of what it means to compete. Technology is omnipresent in daily life, but in the realm of sports, it remains contested territory. The public is divided as some see Mia as a symbol of perseverance and of technology leveling the playing field for athletes who would otherwise be sidelined. Others, however, question whether her success is truly her own. Is she competing, or is it the device competing for her? This debate intensifies when Lena’s coach formally challenges Mia’s place in the competition, arguing that the VitaGuard offers her an unfair advantage.

Lena, Mia’s childhood friend and fellow competitor, is caught in the middle. As a young runner, Lena would often outpace Mia, not out of superior skill but simply because Mia’s condition held her back. With the VitaGuard, Mia is finally running at the level she has always aspired to, but this achievement comes with new challenges. Lena privately supports Mia’s right to compete but remains publicly silent, aware of the controversy her coach has sparked. This silence weighs heavily on Mia, amplifying her sense of isolation.

The track where Mia hopes to compete

As the pressure mounts, Mia grapples with the growing conflict between her reliance on the VitaGuard and her own sense of self. The technology that keeps her safe on the track also fuels her deepest doubts—does the device diminish her achievements, making her victories seem less earned? In quieter moments, Mia questions whether her hard work and determination will ever be recognized without the shadow of the VitaGuard looming over her.

The tension reaches a peak when Mia is called before the Olympic committee to defend her use of the patch. In a carefully measured argument, she explains that the VitaGuard does not give her an edge—it merely allows her to compete on equal terms with athletes whose bodies don’t require such interventions. The device does not make her faster or stronger; it simply ensures her survival. Yet, beyond this public defense, Mia faces a more personal reckoning. She must decide for herself whether the device defines her success or if it is her dedication, skill, and resilience that carry her forward.

Mia overlooks Paris, anxious about whether she'll get her shot at The Gold

The committee ultimately rules in Mia’s favor, setting a precedent for athletes who rely on medical technology to compete. But for Mia, the victory is more than a legal or ethical triumph, it's a moment of profound self-realization. As she steps onto the track for the final race, Mia runs not just to win but to reclaim her sense of agency. The VitaGuard is there, quietly doing its job, but it no longer represents the doubts that once haunted her. Mia finishes the race knowing that the patch, though vital to her health, is not what defines her. Her strength, both physical and emotional, transcends the technology that supports her.

In the end, Mia’s journey challenges the notion of what it means to compete. Her story is not just about navigating public perception or technological controversy; it is about the internal struggle to embrace one’s abilities, with or without assistance. Through Mia, the world of 2124 must confront its evolving relationship with technology and question where the line between fairness and enhancement truly lies.

Mia runs towards a future as an inspiration to the world

Code Breakdown

Classes

  • Hydro – tile grids for water, target, age, barren; column arrays for velCol, noiseCol
    • Builds trunk + branches with Perlin noise and stochastic jitter.
    • Spawns new estuaries on a timer; widens old undammed channels; applies right-side desiccation and water-adjacent recovery.
  • Forest – 2D fields for willow and aspen (0–1). Growth moves toward a cap reduced by barren; blocked under lodges; harvest() does a ring search for richest patch.
  • DamSpans – spans are {row, cL, cR, integrity} across a gap bounded by land. Integrity decays with time and high flow; collapsed spans are removed.
  • Colony, Beaver – array of agents; mortality filter; metrics; per-beaver FSM with vector steering.
  • Lodge – simple sprite; count tied to population

Making the world

Why this order: environment first, then resources, then structures that shape flow, then agents reacting to the current state.

Creates subsystems and enforces the following update order (water → resources → structures → agents).

class World {
  constructor(hud){
    this.hud=hud;
    this.hydro=new Hydro(hud);
    this.forest=new Forest(hud,this.hydro);
    this.dams=new DamSpans(hud,this.hydro);
    this.colony=new Colony(hud,this.hydro,this.dams,this.forest);
    this.lodges=[]; this.updateLodges(true);
  }
  update(){
    this.hydro.update();                     // rivers grow/branch/widen/dry
    this.forest.update(this.lodges,this.hydro); // growth capped by barren
    this.dams.update(this.hydro);            // span decay vs flow
    this.colony.update(this.dams,this.hydro);    // FSM + mortality
    if (this.colony.prunedThisTick){ this.updateLodges(); this.colony.prunedThisTick=false; }
    this.forest.blockUnderLodges(this.lodges,this.hydro);
  }
}

Rivers

The simulation starts with building a target river tree (trunk + noisy branches), reveals it over time (slider), then keep it alive with estuaries, widening, and right-side desiccation.

Beavers “feel” water via noiseCol[c] (stress driver).

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Forests & Barren Tiles

Willows (for building dams) and Aspen (food for the beavers) grow on land toward a cap that shrinks with barren; growth is blocked under lodges and zeroed on water.The simulation starts with building a target river tree (trunk + noisy branches), reveals it over time (slider), then keep it alive with estuaries, widening, and right-side desiccation.

Resulting effects: near water → fertile patches; dry right side → patchy, low-cap growth.

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Dams & Bank-to-Bank Spans

Dam Spans exist only across contiguous water segments bounded by land; integrity increases with work and decays with flow.

This prevents the beavers from spam building, and makes dams visually & mechanically legible.

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Agents & Interaction: Beavers, Vectors, HUD

Beavers are need-driven agents with vector steering.

Input from the right-side menu allows the user to shape conditions.

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Input & HUD

  • Keys: G generate new river; SPACE pause.
  • Mouse: Left = plant Willow, Shift+Left = plant Aspen; toggle Spawn Mode then Right-click to add a random beaver.
  • Sliders (stacked under descriptions; buttons below sliders—no overlap):
    1. River Creation Speed → reveal rate of Hydro.target
    2. Food Spawn Rate (Aspen) → forest growth term
    3. Building Material Spawn Rate (Willow) → forest growth term
    4. Dam Building Speed → per-action span integrity

This closes the system loop: environment drives needs; agents act; structures reshape the environment; HUD lets you adjust parameters and watch new equilibria emerge.

Logic be Dammed:
Representing Forces and Nature in Code

Storytelling midterm first draft

Marcus Thomas

Dec 21, 2024

In 2124, Paris hosts the Olympic Games, an event that mirrors the evolving tension between human ability and technological advancement. The city is a beacon of innovation, blending its rich cultural heritage with cutting-edge design. Mia, a 25-year-old track and field athlete, prepares for the competition of her life. Mia has hemophilia, and while she trains with the same intensity and drive as her peers, she depends on the VitaGuard, a medical patch that monitors her blood flow and automatically delivers clotting factors when necessary. This small device, affixed to her arm, is both a lifeline and a source of scrutiny. While the VitaGuard enables Mia to compete safely, it also sparks controversy over whether technology like this has a place in elite sports.

Mia’s reliance on the a sets her apart, not only from her competitors but from society’s expectations of what it means to compete. Technology is omnipresent in daily life, but in the realm of sports, it remains contested territory. The public is divided as some see Mia as a symbol of perseverance and of technology leveling the playing field for athletes who would otherwise be sidelined. Others, however, question whether her success is truly her own. Is she competing, or is it the device competing for her? This debate intensifies when Lena’s coach formally challenges Mia’s place in the competition, arguing that the VitaGuard offers her an unfair advantage.

Lena, Mia’s childhood friend and fellow competitor, is caught in the middle. As a young runner, Lena would often outpace Mia, not out of superior skill but simply because Mia’s condition held her back. With the VitaGuard, Mia is finally running at the level she has always aspired to, but this achievement comes with new challenges. Lena privately supports Mia’s right to compete but remains publicly silent, aware of the controversy her coach has sparked. This silence weighs heavily on Mia, amplifying her sense of isolation.

The track where Mia hopes to compete

As the pressure mounts, Mia grapples with the growing conflict between her reliance on the VitaGuard and her own sense of self. The technology that keeps her safe on the track also fuels her deepest doubts—does the device diminish her achievements, making her victories seem less earned? In quieter moments, Mia questions whether her hard work and determination will ever be recognized without the shadow of the VitaGuard looming over her.

The tension reaches a peak when Mia is called before the Olympic committee to defend her use of the patch. In a carefully measured argument, she explains that the VitaGuard does not give her an edge—it merely allows her to compete on equal terms with athletes whose bodies don’t require such interventions. The device does not make her faster or stronger; it simply ensures her survival. Yet, beyond this public defense, Mia faces a more personal reckoning. She must decide for herself whether the device defines her success or if it is her dedication, skill, and resilience that carry her forward.

Mia overlooks Paris, anxious about whether she'll get her shot at The Gold

The committee ultimately rules in Mia’s favor, setting a precedent for athletes who rely on medical technology to compete. But for Mia, the victory is more than a legal or ethical triumph, it's a moment of profound self-realization. As she steps onto the track for the final race, Mia runs not just to win but to reclaim her sense of agency. The VitaGuard is there, quietly doing its job, but it no longer represents the doubts that once haunted her. Mia finishes the race knowing that the patch, though vital to her health, is not what defines her. Her strength, both physical and emotional, transcends the technology that supports her.

In the end, Mia’s journey challenges the notion of what it means to compete. Her story is not just about navigating public perception or technological controversy; it is about the internal struggle to embrace one’s abilities, with or without assistance. Through Mia, the world of 2124 must confront its evolving relationship with technology and question where the line between fairness and enhancement truly lies.

Mia runs towards a future as an inspiration to the world

Code Breakdown

Classes

  • Hydro – tile grids for water, target, age, barren; column arrays for velCol, noiseCol
    • Builds trunk + branches with Perlin noise and stochastic jitter.
    • Spawns new estuaries on a timer; widens old undammed channels; applies right-side desiccation and water-adjacent recovery.
  • Forest – 2D fields for willow and aspen (0–1). Growth moves toward a cap reduced by barren; blocked under lodges; harvest() does a ring search for richest patch.
  • DamSpans – spans are {row, cL, cR, integrity} across a gap bounded by land. Integrity decays with time and high flow; collapsed spans are removed.
  • Colony, Beaver – array of agents; mortality filter; metrics; per-beaver FSM with vector steering.
  • Lodge – simple sprite; count tied to population

Making the world

Why this order: environment first, then resources, then structures that shape flow, then agents reacting to the current state.

Creates subsystems and enforces the following update order (water → resources → structures → agents).

class World {
  constructor(hud){
    this.hud=hud;
    this.hydro=new Hydro(hud);
    this.forest=new Forest(hud,this.hydro);
    this.dams=new DamSpans(hud,this.hydro);
    this.colony=new Colony(hud,this.hydro,this.dams,this.forest);
    this.lodges=[]; this.updateLodges(true);
  }
  update(){
    this.hydro.update();                     // rivers grow/branch/widen/dry
    this.forest.update(this.lodges,this.hydro); // growth capped by barren
    this.dams.update(this.hydro);            // span decay vs flow
    this.colony.update(this.dams,this.hydro);    // FSM + mortality
    if (this.colony.prunedThisTick){ this.updateLodges(); this.colony.prunedThisTick=false; }
    this.forest.blockUnderLodges(this.lodges,this.hydro);
  }
}

Rivers

The simulation starts with building a target river tree (trunk + noisy branches), reveals it over time (slider), then keep it alive with estuaries, widening, and right-side desiccation.

Beavers “feel” water via noiseCol[c] (stress driver).

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Forests & Barren Tiles

Willows (for building dams) and Aspen (food for the beavers) grow on land toward a cap that shrinks with barren; growth is blocked under lodges and zeroed on water.The simulation starts with building a target river tree (trunk + noisy branches), reveals it over time (slider), then keep it alive with estuaries, widening, and right-side desiccation.

Resulting effects: near water → fertile patches; dry right side → patchy, low-cap growth.

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Dams & Bank-to-Bank Spans

Dam Spans exist only across contiguous water segments bounded by land; integrity increases with work and decays with flow.

This prevents the beavers from spam building, and makes dams visually & mechanically legible.

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Agents & Interaction: Beavers, Vectors, HUD

Beavers are need-driven agents with vector steering.

Input from the right-side menu allows the user to shape conditions.

regen(){
  this.water=grid(false); this.target=grid(false); this.barren=grid(0); this.growth=0;
  const trunk = walkBranch(2, rows*0.5, cols*0.85, 0, true); paintPath(trunk,5);
  for (let i=0;i<10;i++){ const pC=rand(6,cols*0.7), pR=clamp(noise(i*.3)*rows,2,rows-3);
    paintPath(walkBranch(pC,pR,rand(18,48), coin()?-1:+1,false),3);
  }
}
update(){
  // reveal target → water
  this.growth=min(1,(this.growth||0)+(0.002+hud.get("riverSpeed")*0.02));
  for (let c=0;c<floor(cols*this.growth);c++) for (let r=0;r<rows;r++) if (target[c][r]) water[c][r]=true;

  // desiccate far right → barren land
  for (let c=floor(cols*.75); c<cols; c++) if (random()<0.0008)
    for (let r=0;r<rows;r++) if (water[c][r]){ water[c][r]=target[c][r]=false; barren[c][r]=min(1,barren[c][r]+.4); }

  // estuaries & widening (if undammed & old)
  if (++branchTimer>240){ branchTimer=0; /* spawn small branch from wet pivot; paintPath(...,2) */ }
  // …age water; leak to neighbors when age>180 && !damSpans.hasDamNear(c,r,4)

  recalcColumns(); // sets velCol[], noiseCol[] from wet fraction per column
}

Input & HUD

  • Keys: G generate new river; SPACE pause.
  • Mouse: Left = plant Willow, Shift+Left = plant Aspen; toggle Spawn Mode then Right-click to add a random beaver.
  • Sliders (stacked under descriptions; buttons below sliders—no overlap):
    1. River Creation Speed → reveal rate of Hydro.target
    2. Food Spawn Rate (Aspen) → forest growth term
    3. Building Material Spawn Rate (Willow) → forest growth term
    4. Dam Building Speed → per-action span integrity

This closes the system loop: environment drives needs; agents act; structures reshape the environment; HUD lets you adjust parameters and watch new equilibria emerge.