Week 14 – Final Project

Concept

My final project is an interactive rhythm based storytelling game with somewhat of a horror theme. The player presses one of four physical buttons to match falling tiles on the screen, and every correct hit helps restore the signal. As the signal gets stronger, pieces of a hidden story are revealed one fragment at a time, until the final message. I wanted the game to feel like the player was decoding a broken transmission, so the gameplay mixes rhythm, suspense, and storytelling together instead of feeling like a normal rhythm game.

Images

Schematic

User Testing video

Description of interaction design

The interaction is based on rhythm timing. Falling tiles move down four lanes, and the player presses one of four buttons that match those lanes and tiles. The player must press the correct button when the tile reaches the hit line near the bottom of the screen. If the timing and button match correctly, the tile counts as a successful hit, the signal bar increases, and the beep sound effect plays. Once the player reaches enough successful hits, the game moves into the “reveal” state, where part of the hidden story is shown on a projector background screen with static sounds and flickering text. After reading the fragment, the player presses space to continue to the next round. This repeats until the final message is revealed.

Description of p5.js code + code snippets + embedded sketch

The p5 code controls almost everything the player sees and experiences visually. At the top of the code, I created variables for the game states, story progress, tiles, spawning system, sounds, images, and serial communication. I also use sentenceProgress to track how many correct hits the player has made and hits needed to decide how many successful hits are required before unlocking the next story fragment. The currentStory variable stores whichever random story is selected for that game session.

One part I spent a lot of time on was the tile spawning system. I used a spawnTimer and spawnInterval to control when new tiles appear. Every frame during gameplay, spawnTimer increases by 1 like a stopwatch. Once it becomes larger than spawnInterval, which I set to 50, the game creates a new tile in a random lane using tiles.push(new Tile(randomLane, -100, 4)). Then the timer resets back to 0 and starts counting again. This makes the tiles appear at steady intervals instead of all at once. I liked this method because it gave me better control over rhythm and difficulty.

The tile checking system works by comparing the button sent from Arduino to the tile’s lane. Arduino sends a number from 1 to 4 depending on which physical button was pressed. In p5, I store that in latestButton. Then inside the game loop, every tile runs tiles[i].checkHit(latestButton). This checks if the tile is close enough to the hit line and whether the correct matching button was pressed. If both are true, the game counts it as a hit, adds 1 to sentenceProgress, resets latestButton back to -1, and plays the tile sound effect. If the tile goes off screen or gets hit, it gets removed from the tiles array using splice(). This keeps the game running smoothly and prevents old tiles from staying on screen.

//check win condition
  if (sentenceProgress >= hitsNeeded && state === "playing") {
    //if player reaches required hits
    state = "reveal";
  }

  //spawn tiles
  if (state === "playing") {
    spawnTimer++; //counts frames and adds 1 like a stop watch 
    if (spawnTimer > spawnInterval) {
      //to check if 50 frames has passed yet
      let randomLane = floor(random(4)); //chooses a random lane (i used floor to round the number down to the nearest whole number since random gives decimal values)
      tiles.push(new Tile(randomLane, -100, 4)); //creates a new faling tile (used push to save it in the tile array so i can do the move and display)
      spawnTimer = 0; //reset timer 
    }

    //update and draw tiles
    for (let i = tiles.length - 1; i >= 0; i--) {
      //start from the last tile and go backwards through every tile in the array (backwards bc I remove tiles)
      tiles[i].move(); //move tile downward
      tiles[i].display(); //draws tile on screen

      //hit check
      if (tiles[i].checkHit(latestButton)) {
        //checks if player pressed correct button at right time
        sentenceProgress += 1; //increaes score
        latestButton = -1; //reset button input
        tileSound.play();
      }
      if (tiles[i].isOffScreen() || tiles[i].hit) {
        //if tile is gone or hit
        tiles.splice(i, 1); //remove tile from array
      }
    }
  }
//hit detection
  checkHit(buttonPressed) {
    let hitZone = height - this.h; //creates the hit line area near bottom of screen (where the player has to press the button)
    if (buttonPressed === this.lane + 1 && //checks correct button, since the lanes start at 0 i added one so it matches
      this.y + this.h > hitZone && //checks if bottom of tile passed into hit zone
      this.y < hitZone + this.h //check if top of tile has not passed too far
    ) {
      this.hit = true; //marks it hit
      return true;
    }
    return false; //wrong button or timing so no
  }
}

I also built a story system using a custom story class (the story and tiles use oop). Each story has an id, title, fragments, final message, and an index to track progress. Instead of writing separate logic for every story, I used an array of story objects so the game can randomly choose one each time it starts. The function getCurrentFragment() shows the current part of the story, next() moves to the next fragment, and isComplete() checks whether the final message should appear. This made the storytelling system much cleaner and easier to scale because I could just add new stories without rewriting game logic.

class Story {
  constructor(id, title, fragments, finalMessage) {
    this.id = id; //so i can identify which story
    this.title = title; //story title
    this.fragments = fragments; //array of the story lines (one by one)
    this.finalMessage = finalMessage; //the last messagge
    this.index = 0; //keeps track of which fragment is shown
  }

  //story navigaton
  getCurrentFragment() {
    //returns the current line of the story based on index
    return this.fragments[this.index]; //takes the current index and give it that specific story line
  }

  next() {
    //moves to the next line in the story
    if (this.index < this.fragments.length - 1) {
      //only move if we are not at the last fragment yet
      this.index++; //increases the index to move to next fragment
      return true; //keep moving forward
    }
    this.index = this.fragments.length; // force completion state
    return false; //if at end do nothing
  }
  isComplete() {
    //check if story is done
    return this.index >= this.fragments.length; //return true if we are at or past the last fragment
  }

  reset() {
    //resets story back to beginning
    this.index = 0;
  }
}

//array that stores all the stories
const stories = [
  new Story(
    1,
    "Emergency Channel 7",
    [
      "If anyone is still receiving this broadcast,\n do not trust the silence outside.\n We thought the signal loss was a storm at first.",

      "Every attempt to trace the interference..\n led back to the same abandoned house.\n No one who entered answered again.",

      "Tonight..\n the signal came through clearly for the first time. \n It wasn't static. It was breathing...\n and it knew all of our names.",
    ],
    "FINAL MESSAGE: Do not attempt to locate the source.\nIt already knows where you are.\nLock the front door."
  ),

Description of Arduino code + code snippets + Github full code

https://github.com/farahshaer/Intro-to-IM/blob/f22e6be49632925d6dba9f548362066ddd89bce8/sketch_may1a.ino 

Arduino handles the physical interaction side of the project. I connected four push buttons as inputs and one LED as an output. Each button represents one lane in the rhythm game. I used input_pullup so the buttons read high normally and low when pressed, which made the wiring simpler because I did not need extra resistors:

void setup() {
  Serial.begin(9600);

  // inputs
  pinMode(redButtonPin, INPUT_PULLUP);//used inputpullup so buttons read high when not pressed and for no resistors
  pinMode(yellowButtonPin, INPUT_PULLUP);
  pinMode(blueButtonPin, INPUT_PULLUP);
  pinMode(greenButtonPin, INPUT_PULLUP);

  // output
  pinMode(signalLedPin, OUTPUT);//LED that reacts to game state
  pinMode(LED_BUILTIN, OUTPUT);//for debugging

In the loop, Arduino constantly checks if any button is pressed. If the red button is pressed, it sends 1 through Serial.println(), yellow sends 2, blue sends 3, and green sends 4. These values are what p5 reads and uses to check player input:

//SEND TO P5 (BUTTON INPUTS 1-4)
  if (digitalRead(redButtonPin) == LOW) {//if button pressed
    buttonPressed = 1;//assign value number
    Serial.println(buttonPressed);//prints value and moves to the next line, send to p5
    delay(100);//delay to prevent repeated button tirggers from one press

  if (digitalRead(yellowButtonPin) == LOW) {
    buttonPressed = 2;
    Serial.println(buttonPressed);
    delay(100);
  }

  if (digitalRead(blueButtonPin) == LOW) {
    buttonPressed = 3;
    Serial.println(buttonPressed);
    delay(100);
  }

  if (digitalRead(greenButtonPin) == LOW) {
    buttonPressed = 4;
    Serial.println(buttonPressed);
    delay(100);
  }
}

Arduino also receives information from p5.js about the current game state. In p5, I created a variable called ledState where start= 0, playing= 1, reveal= 2, and end= 3. This gets sent to Arduino using port.write(). Arduino reads that number using serial.parseInt() and changes the LED behavior depending on the state.

During the game tiles, the LED flickers quickly to feel active and stressful. During the reveal screen, it flickers more slowly to create a static/projector feeling. At the end screen, the LED stays fully on, and during start or instructions, it stays off:

void loop() {
//READ FROM P5
  while (Serial.available()) {//check if p5 is sending data
    digitalWrite(LED_BUILTIN, HIGH);//led on while recieving data
    gameLevel = Serial.parseInt(); //read game state number from p5 (used parseint to skp anything that isnt digits)
    Serial.read(); // clears '\n' after parseint
  }
  digitalWrite(LED_BUILTIN, LOW);

//LED behavior based on game state
if (gameLevel == 1) { //the playing state, faster flicker
  digitalWrite(signalLedPin, HIGH);
  delay(50);
  digitalWrite(signalLedPin, LOW);
  delay(50);
}
else if (gameLevel == 2) {//reveal state, slow flicker for a calmer feel
  digitalWrite(signalLedPin, HIGH);
  delay(200);
  digitalWrite(signalLedPin, LOW);
  delay(200);
}
else if (gameLevel == 3) {//end state, light stays fully on
  digitalWrite(signalLedPin, HIGH);
}
else { //for the start and instruction, led off
  digitalWrite(signalLedPin, LOW);
}

Description of communication between Arduino and p5.js

Arduino sends button presses to p5 so the player can interact with the falling tiles:

//SEND TO P5 (BUTTON INPUTS 1-4)
  if (digitalRead(redButtonPin) == LOW) {//if button pressed
    buttonPressed = 1;//assign value number
    Serial.println(buttonPressed);//prints value and moves to the next line, send to p5
    delay(100);//delay to prevent repeated button tirggers from one press

And p5 reads it and converts it to a number:

//READ FROM ARDUINO HERE
   let data = port.readUntil("\n"); //read message until newline
   if (data && data.length > 0) {
     latestButton = int(trim(data)); //converts input into number 1-4
   }

And then p5 sends game state data back to Arduino so the LED can visually respond to the game:

//SEND TO ARDUNIO HERE (sends game state back)
    let ledState = 0;
    if (state === "start") ledState = 0;
    else if (state === "playing") ledState = 1;
    else if (state === "reveal") ledState = 2;
    else if (state === "end") ledState = 3;
    port.write(ledState + "\n"); //sends the state so ardunio can control LED
  }

Where Arduino reads it and changes the LED state based on the game state:

//READ FROM P5
  while (Serial.available()) {//check if p5 is sending data
    digitalWrite(LED_BUILTIN, HIGH);//led on while recieving data
    gameLevel = Serial.parseInt(); //read game state number from p5 (used parseint to skp anything that isnt digits)
    Serial.read(); // clears '\n' after parseint
  }
  digitalWrite(LED_BUILTIN, LOW);

//LED behavior based on game state
if (gameLevel == 1) { //the playing state, faster flicker
  digitalWrite(signalLedPin, HIGH);
  delay(50);
  digitalWrite(signalLedPin, LOW);
  delay(50);
}

So overall, Arduino sends button input to p5 so the player can interact with the game, and p5 sends game state information back so Arduino can physically respond through the LED.

Aspects of the project that I am particularly proud of

One thing I am particularly proud of is how the concept feels cohesive instead of looking like separate parts forced together. The horror story, the rhythm gameplay, the static visuals the sound design, and the led feedback all support the same theme of restoring a broken transmission. I did not want it to feel like just a button game, so I focused a lot on atmosphere. I am also proud of the story system because it made the game replayable by randomly choosing different types of stories instead of showing the same one every time.

Also, the integration between physical buttons and the tiles, I am really proud of the mapping.

Challenges faced

A big challenge was debugging the story progression and the final reveal logic. At one point, the game would skip the final message and go straight to the ending screen, which broke the whole experience. I had to keep testing how currentStory.next() and currentStory.isComplete() interacted and realized the order of those checks mattered a lot in the kepressed logic:

else if (state === "reveal" && key === " ") {
  //if already showing final message, go to end screen
  if (currentStory.isComplete()) {
    state = "end";
    return;
  }
  //otherwise move to next fragment
  currentStory.next();//move to next line/fragment of story 
  sentenceProgress = 0;//reset player progress for next round 
  tiles = [];//remove all the falling tiles 
  spawnTimer = 0;//reset tile spawn timing 
  hitsNeeded += 2;//increase diffiuclty each round
  state = "playing";//go back to gamestate
}
  if (state === "end" && key === " ") {
    resetGame();
  }
  //serial connect
  if (key === "v") {
    setupSerial();
  }
}

I also had a challenge with the tiles spawning too fast, so I used spawntimer and the spawninterval system, which worked very well.

Future Improvement

If I had more time, I would improve the game by making the difficulty scale smoother and adding visual feedback for missed notes, not just successful ones. Right now I just wanted to focus mainly on correct hits, but stronger fail states would make the tension higher. I would also like to make the LED system more by using multiple LEDs so each story state feels even more immersive. Another future improvement would be adding more story branches where player performance changes, which ending they get, instead of always leading to one final message. I think that would make the game feel even more interactive and personal.

Resources and AI usage

I searched up on google how to shift something and it said use translate(), so i looked at the p5 reference page for more information so I can do it for the tiles and glitch effect: https://p5js.org/reference/p5/translate/

I needed a refresher on return because I wanted to use it to return the current fragment back into the array or to return true/false so the game knows if the story can keep moving forward. so I watched this youtube video:
https://www.youtube.com/watch?v=qRnUBiTJ66Y

Search on google how I can remove a tile from array after it gets off of screen and I found splice, where I then look at the p5 reference page for more information on how to use it: https://p5js.org/reference/p5/splice/

My music would overlap so I looked through the p5 soundfile page to see if there was a fix for that, which I found playmode to help me.
https://p5js.org/reference/p5.sound/p5.SoundFile/

I also wanted to know how to create a line (the one one at the bottom), so I used beginshape() and end (shape) for the to create a continuous wave line. I also used it to understand vertex shapes function in p5 because I did need a refresher:
https://p5js.org/reference/p5/beginShape/

I also used drawingconext reference page for my effects by looking at their examples:
https://p5js.org/reference/p5/drawingContext/

For the tiles:
https://p5js.org/reference/p5/floor/#:~:text=Reference%20floor()-,floor(),the%20value%20of%20a%20number.

AI usage:

I had trouble with the tiles being skipped, so I asked ChatGPT for debugging, and it was because it was looped forward. So I learned that I need to loop it backwards and start from the last tile and go backwards through every tile in the array because I remove tiles, and so it will not mess up with the remaining index. And scanning a list from bottom to top is better so deleting items basically does not confuse the order. for (let i = tiles.length – 1; i >= 0; i–)

My audio and images would not load, so I asked ChatGPT for debugging, and it was because I had them organized in a folder and forgot to call it…

I also wanted a stronger jitter and glitch effect for my falling tiles to make the game feel more unstable and distorted. I was already using sin() for the pulse effect, but I wanted the tiles to feel less smooth and more corrupted. I asked ChatGPT for ideas on how to make the movement feel more random and glitchy, which helped me understand that I could use random values for variation. I then used this.corruption = random(0, 1); and multiplied it with the pulse and jitter movement, so each tile had a slightly different glitch effect that matched the horror atmosphere I wanted

Week 13 – User Testing

So I let my siblings test it out and they were able to figure out the basic idea pretty quickly, that they needed to press the colored arcade buttons when the falling tiles reached the hit line on screen. The colors helped a lot because they made the connection between the physical buttons and the tiles more obvious. But they were confused at first about when exactly they were supposed to press, since there were no instructions during gameplay, so they needed a few seconds of trial and error to understand the timing.

I think the mapping between the controls and the experience worked well because each button matched a lane and color on screen, which made the interaction feel natural. Once players understood that each button controlled a specific lane, they were able to continue without much help. The physical arcade buttons also made the experience feel more immersive compared to using a keyboard.

I think the strongest part of the experience was the atmosphere. The background visuals, projector reveal screen, sound design, and glitch effects made the game feel tense and it matched the theme and concept well. They especially liked the reveal screen because it felt like a reward after completing each round and made them curious about the story.

The main area that could be improved is clarity at the beginning. One of them were unsure whether to press buttons immediately or wait for the tiles to reach the bottom hit line. I found myself explaining the timing and the goal of “rebuilding the signal” so they could progress. To make this clearer, I could improve the instruction screen by adding a short visual example or animation showing exactly when to press the buttons (like a quick tutorial).

(Also, I noticed I wrote 4 rounds but its kind of 5 because you have to play again to go to the final message…I am thinking about just reducing it maybe its too long of a game??)

Final Project Concept

Finalized Concept

For my final project, it will basically be my preliminary concept, where I will create a physically interactive rhythm based system called Recovered Signal, where the user helps reconstruct a corrupted digital story through timed physical interaction. The concept is inspired by rhythm games such as Piano Tiles, but instead of focusing only on scoring, the user will actively uncover fragments of a hidden/broken narrative.

The experience is designed as a mystery signal recovery system. On screen, the user sees falling colored rhythm tiles with music playing, while physically pressing with their hand the right buttons/pads in sync with them. For the visuals, it will initially appear distorted, with glitch effects and broken text to show a broken signal along with the tiles. As the player successfully hits notes on time, the system will respond immediately by reducing the distortion, sharpening the text, and revealing fragments of audio or text of a story. It will gradually form a short narrative, like a corrupted voicemail or like a partial conversation/story. But if the user misses notes, the distortion stays or I might make it so that it temporarily increases.

Arduino

So the Arduino will act as the physical input system for the project.

The inputs will be either an arcade style push buttons or pressure pads, and each pad represents a tile in the rhythm game. When the pad is pressed, it sends a high signal to the Arduino. Within the Arduino, it will continuously read the state of each button, detecting which button was pressed. The Arduino will not handle any game logic or timing evaluation, just detect the input and send that data to p5.

For output and communication, it will send a serial message to p5 in the format of a button id (which will show which pad was pressed), and a timestamp using millis to indicate when the press occurred. I will probably use the numbers 1,2,3,4 in correlation to each pad/button. For example 1 if the red button was pressed or 1, 10230, if it was pressed at a specific time.

UPDATE: the Arduino will send the button information, and then p5 checks if it was the right timing, and p5 sends back whether it was correct or wrong (0 or 1), and correct will turn on the green LED light, and wrong will turn on the red LED light. I am also thinking about making the LEDs flicker if they’re still on the weak signal stage, or have a steady glow when their half way there, and the brightest when it’s strong.

(If time allows, I will also set up an LED that lights up when a button is pressed for feedback/confirmation.)

P5

P5 will function as the main visual and audio system of the project.

It will generate a rhythm game with 4 vertical lanes that displays falling tiles synchronized to a beat. It will detect input from Arduino (which button was pressed) and it will match Arduino input with falling tile positions, evaluate timing accuracy (perfect/miss/late/early), and update the system state based on performance. Everything will be in real time as the button is pressed.

For the audio, it will be handled entirely in p5, so it’s clear. Each correct input will trigger musical elements, and the layered audio starts muffled or distorted, becomes clearer as player progresses, and eventually reveals a full short narrative (voicemail or conversation)

What it will communicate with the Arduino is that it will receive button press data through serial input and use that data to trigger game events and check accuracy, and send back to Arduino if the timing was right and the right button was pressed, in which it will light up a red or green LED light.

Current Progress

I have currently made all of the backgrounds and set up the skeleton code in p5, with the game states and made a signal level bar (as the player taps, a signal bar fills up on the screen. When the signal reaches a certain level, it triggers a story message to appear, like a transmission being decoded).

Here is the link to the sketch and some of the backgrounds:

https://editor.p5js.org/farahshaer/sketches/LJyoiS0O_


I will next make the tiles, stories (using oop), and sounds, glitch effects, and make my Arduino code and circuit…I still have a long way to go.

Stipend Breakdown

I plan to use the $50 stipend to build the pressure pads or buy arcade buttons (but I am not too sure if it will come in time).

Cardboard/foam board for mounting structure
Copper tape and sheets
Colored paper and materials for labeling the pads visually to match the p5 lanes/tiles.
Basic craft supplies (tape, glue, cutting materials)

Week 11 – Serial Communication

Exercise 1:

P5 code:

https://editor.p5js.org/farahshaer/sketches/K1ETNJevI 

Arduino code:

https://github.com/farahshaer/Intro-to-IM/blob/15f03b7108b0eead04ecc8fbade23e0703c774e4/sketch_apr16a.ino 

Reflection/process:

So for the first part, it was a one way communication between arduino and p5 with the idea of taking an input from a sensor on arduino and using that data to control the circle on p5. I used a potentiometer as my sensor because it gives a smooth range of values which makes it easier to control the movement on the screen. The arduino reads the values and sends it to p5 using serial.prin1n(). Then in p5 I used readUntil(“\n”) to receive the data and once I got that value I cleaned it using trim() and converted it into a number using int(). Then I map it from the sensor range to the width of the canvas so it can control the x position of the ellipse. As I turn the potentiometer, the circle moves left and right on the screen. 

 

Exercise 2:

P5 Code:

https://editor.p5js.org/MariamAlameri/sketches/oWfNkocIc 

Arduino Code:

https://github.com/mariam9766/Intro-to-IM/blob/736de2e50c777dff22b3545885aebfa6cce33cfd/BidirectionalCommunicationExercise2_mariam.ino 

Reflection/process:

The second exercise involved bidirectional communication between p5 and Arduino, where we were asked to control the Arduino from p5. I wanted to create a p5 sketch that allows the user to control the brightness of an LED on the Arduino board. I chose to use a slider in the sketch, as it provides an intuitive and suitable way to adjust brightness. I also referred to the exercises completed in class and adjusted them to meet the purpose of this assignment. In the Arduino code, I used two if statements to ensure that the LED responds when data is received from p5, and to constrain the brightness value within the range of 0–255 for proper PWM control. In the p5 sketch, I implemented the slider using createSlider, adjusted its position and appearance, and used port.write to send the brightness value to the Arduino, allowing accurate control of the LED.

 

Exercise 3:

Concept:

After completing the first two exercises and creating communication between the p5 sketch and the Arduino code and board back and forth, in this exercise, we had to combine both. When the ball in the p5 sketch bounces on the ground, the LED on the board flashes on and off, and when we use the potentiometer, which is the analog sensor on our Arduino board, we control the wind in the sketch and move the ball left and right.

P5 Code:

https://editor.p5js.org/farahshaer/sketches/hAwlRZjXM 

Arduino Code:

https://github.com/mariam9766/Intro-to-IM/blob/9f561f01e2719a784d6c54e8d43e4bbc998a6608/BidirectionalCommunicationExcercise3_mariam.ino 

Demonstration:

Circuit:

Schematic:

Code we’re proud of:

One part of the code that we are proud of is the bounce detection and how it connects to the Arduino:

//the bounce detection
  if (position.y > height - mass / 2) {
    //check if the ball hits the ground
    velocity.y *= -0.9; // A little dampening when hitting the bottom (reverse the direction when it hits)
    position.y = height - mass / 2; //keep it above the floor
    bounce = 1; //to mark that the bounce happened
  }
  //send to arduino
  let sendToArduino = bounce + "\n"; //send the bounce value 1 or 0 and the "\n" tells ardunio the message is done
  port.write(sendToArduino);
  // reset bounceafter it sends
  bounce = 0;
}

We are proud of this part because it turns the ball bouncing into a signal that affects something physical (the LED). It also only sends the signal once per bounce, which makes the interaction feel more intentional instead of constant.

Reflection/future work:

So in this version of the gravity and wind example, I added serial communication so the sketch can interact with an Arduino on p5. Instead of controlling the wind using the keyboard like in the original example, the wind now comes from an analog sensor (like a potentiometer) connected to the Arduino. The Arduino sends that sensor value to p5, and I map it to a wind force so it pushes the ball left or right. I also added a bounce signal that goes the other way. Every time the ball hits the bottom of the canvas, I set a variable to 1 and send it to the Arduino. This tells the Arduino to briefly turn on an LED, then it gets reset back to 0, so the signal only happens once per bounce. Most of the original physics code stayed the same, but the main changes were adding serial setup, reading sensor data to control wind, and sending a bounce message back to control the LED.

For the Arduino side, I worked on the Arduino code to align with the p5 sketch we have and create serial communication from the Arduino board to the p5 sketch and vice versa. I set it up so the Arduino sends the analog sensor value from A0 to control the wind on the ball in the sketch, and receives a bounce signal from p5 when the ball hits the ground. When this signal is received, the Arduino briefly turns on an LED to indicate the bounce, and then resets the value so the LED only activates once every time it touches the ground. I also made sure the serial communication was properly structured so both inputs and outputs work smoothly together at the same time, allowing interaction between the physical sensor and the digital sketch.

This exercise helped us understand how bidirectional communication actually works, instead of just sending data one way. It was interesting to see how the Arduino and p5 sketch can influence each other at the same time. One challenge we ran into was getting the potentiometer to properly control the wind. Even though the LED response worked, the sensor input was inconsistent, which made it harder to debug whether the issue was in the Arduino code or the p5 code. This made us realize how important timing and serial communication structure are, especially when both sides are sending and receiving data continuously.

If we had more time, we would focus on possibly smoothing the wind movement so it feels less jumpy. We would also experiment with adding more physical outputs, like multiple LEDs or different types of sensors, to make the interaction more dynamic, but we just wanted to stick with the assignment instructions for now to get a grasp of the concept.

Preliminary Concept for Final project

For my final project, I plan to create a physically interactive game where the player helps recover a corrupted digital signal of a story using their feet. The idea is inspired by games like Piano Tiles and Just Dance, but instead of simply playing for points, the user is actively uncovering a hidden message through their performance. By stepping on floor pads in time with visual cues, which I am thinking will be something similar to piano tiles and the Just Dance mat, the player will gradually restore a distorted audio/visual, which makes the experience into kind of like a mystery game:

 

I will use Arduino to capture physical input and P5 to handle the visual and audio output. On the floor, there will be 4 pads made from materials like cardboard or foam with conductive layers inside (or if there is a better sensor for this idea, I will use it). Each pad will act as a button connected to the Arduino, and when someone steps on a pad, the circuit is completed, and the Arduino sends that input data to p5 through the serial communication.

On the screen, p5 will display a rhythm like visuals with vertical lanes and falling tiles, like the piano tile game. The user must step on the pad at the correct time to match the falling tiles (which I am thinking will be color based, so it matches the floor tiles, and it is more obvious). For the visuals, it will initially appear distorted, with glitch effects, static, and broken text or images to represent a broken signal along with the tiles. As the player successfully hits notes on time, the system will respond immediately by reducing the distortion, sharpening visuals, and revealing fragments of audio or text of a story. I want it to gradually form a short narrative, such as a corrupted voicemail or like a partial conversation. But if the user misses notes, the distortion stays or I might back it to where it temporarily increases.

The game basically listens through the Arduino sensors, thinks by processing the timing and accuracy of the input in p5, and responds through changes in the visuals and sound. The player will then be paying attention and adjusting their movements based on the feedback they receive, especially when they start revealing more of the story.

I prompt Gemini AI to create a picture of the game, so you can get a vision of what I am trying to achieve:

 

Reading Reflection – Week 11

Design Meets Disability

This was an interesting read, especially the idea of discretion in disability design. I honestly realized I never really questioned it before, I just kind of assumed that making things invisible or less noticeable was automatically better, but the reading made me realize it is actually much more about culture and how people feel about themselves. The example of the Eames leg splint was interesting to me because I did not expect something medical to be described as a beautiful design. The idea that a medical object could actually lead to iconic furniture made me rethink the direction of influence in design. It does not just go from mainstream to disability, but the other way around, too.

The idea of discretion vs fashion also really changed how I think about assistive devices. I have definitely grown up seeing and hearing things like hearing aids or prosthetics as something you need to hide, so the idea that invisibility might actually reinforce shame really stuck with me. The comparison with the glasses made a lot of sense because I have never thought of glasses as medical, I sometimes see them as normal or even stylish. Which makes me wonder why other devices have not gone through the same shift yet.

I also found the discussion about simplicity really relatable, especially the iPod example. I have definitely experienced how too many features in a product can actually make it harder to use. The example of simple radios for people with dementia made me think about how inclusion is not just physical, but also about how easily something can be understood without stress. Overall, this reading has me thinking about how much design depends on who is involved in the process, especially considering it needs input from mainstream designers and artists because disability design does not have to be separate or special. It can actually shape what good design looks like for everyone.

Week 10 – Musical Instrument

Here are pics and videos:

 

Video link if not working:

https://drive.google.com/file/d/1pQPYnyUyf5OOBwbfCVHiDrsOvqDn_P3d/view?usp=sharing

Here is my GitHub link:
https://github.com/farahshaer/Intro-to-IM/blob/4ff1ee52b33d4edf72a1f905fc3d014cd8dfadb6/sketch_apr14a.ino 

Overall concept

So for this project, I built an interactive music system that plays two different songs (Jennifer’s Body by Ken Carson and Die with a Smile by Bruno Mars), and you can control the pitch of the melodies. I included a buzzer for the sound output, a button to switch between the songs, a potentiometer to change the pitch, and an LED that visually blinks along with the music. The main idea was to create something interactive where you can actually affect the sound while it is playing.

Code Highlight

One part of my code that I am particularly proud of is the if statements that switch between the two melodies and make the LED blink:

//mode 0 (melody 1)
  if (mode == 0) {

    int size1 = 15;                                      //number of notes in melody 1
    int noteDuration = 1000 / noteDurations1[thisNote];  //converts note type into time in milliseconds
    int finalPitch = melody1[thisNote] + pitch;          //combines the meoldy note and the knob turning (can adjust the note using the potentiometer)
    tone(buzzer, finalPitch, noteDuration);              //plays sound on buzzer
    digitalWrite(led, HIGH);                             //turns led on while the note is playing
    delay(noteDuration);                                 //waits for note to finish
    digitalWrite(led, LOW);                              //turns the led off between the notes and for blinking effect
    delay(noteDuration * 0.3);                           //short pause between the notes to make the melody clearer
    noTone(buzzer);                                      //stops sound before next note
    thisNote++;                                          //moves to next note in the melody
    if (thisNote >= size1) thisNote = 0;                 //if at the end of the melody go back to the start (loop song)
  }


  if (mode == 1) {
    int size2 = 23;                                      //number of notes in melody 2
    int noteDuration = 1000 / noteDurations2[thisNote];  //converts note into time (mill sec)
    int finalPitch = melody2[thisNote] + pitch;          //applys the pitch shift from the potentmeter
    tone(buzzer, finalPitch, noteDuration);              //plays sound
    digitalWrite(led, HIGH);                             //turns led on during the sound
    delay(noteDuration);                                 //wait for note
    digitalWrite(led, LOW);                              //led off
    delay(noteDuration * 0.3);                           //pause between notes
    noTone(buzzer);                                      //stops sound

    thisNote++;                           //go to the next note when done
    if (thisNote >= size2) thisNote = 0;  //loop back to start when song ends
  }
}

This is the core of my project because instead of playing an entire song at once, it processes one note at a time, which allows for real-time interaction through the button and the potentiometer. The code selects the current note, modifies pitch with the sensor input, and then outputs the sound plus the LED, while moving to the next state.

Reflection/future work

I cannot lie, I had trouble with the code, but the wiring was straightforward once I understood how each component connected to the Arduino. The buzzer is connected to digital pin 8, and outputs sound using the tone() function. The LED is connected to digital pin 9 with a resistor, and it provides visual feedback by blinking in sync with each note. The button is connected using INPUT_PULLUP, meaning it reads HIGH when not pressed and LOW when pressed, which required me to wire one side to ground so the logic would work correctly. The potentiometer is connected to analog pin A0, with one side connected to 5V, the other to ground, and the middle pin sending a variable signal that controls pitch in the code.

For the code, I used a variable called thisNote, which stores the current position in the melody array. Instead of using a for loop to play the entire song at once, the code plays one note per loop cycle, which allows for constant checking for input changes while the music is playing. At first, I used for loops, and it just was not working. The Arduino got stuck inside the loop, the button presses were ignored until the song finished, and the potentiometer did not update in real time, so switching to thisNote, it made the program run one note at a time inside the loop. So the Arduino can check the button constantly, and the song can change and pitch in real time.

I also had a problem with the button logic, because at first I wrote if (buttonState == LOW) and it caused it to continuously trigger while the button was held down, which made the song behave unpredictably. So I used chatgpt to debug and I learned to use lastButtonState with buttonState so the code only detects a transition from high to low (single press instead of holding), and because I used input_pullup, I also had to adjust my thinking since high is not pressed and low was pressed so it was confusing at first because it is the opposite of what I expected.

Overall, I learned that structure matters just as much as logic, especially when dealing with real-time input and output, because small details like button states and loop structure completely change how responsive the system feels. For future improvements, I would add more songs or more modes, and more LEDs or patterns to visualize the rhythm more creatively, and probably replace delay with millis for smoother control.

Here is my schematic:


References:

(I mainly used the lecture slides), but I also used these websites for a better understanding.
https://github.com/hibit-dev/buzzer/blob/e1442497e7c56cee0d5efe73304bdb922b3ab907/src/songs/ken_carson_jennifers_body/ken_carson_jennifers_body.ino

https://github.com/hibit-dev/buzzer/blob/e1442497e7c56cee0d5efe73304bdb922b3ab907/src/songs/die_with_a_smile/die_with_a_smile.ino

https://docs.arduino.cc/built-in-examples/digital/toneMelody/

https://docs.arduino.cc/built-in-examples/digital/InputPullupSerial/

Reading Reflection – Week 10

A Brief Rant on the Future of Interaction Design + follow-up

Reading this article made me rethink how I usually imagine the future of technology. I realized that I tend to accept touchscreens and the sleek interfaces without really questioning whether they actually improve human interactions. I really liked the author’s idea of pictures under glass, because it reframes devices like phones and tablets as limiting rather than advanced. I had never really considered how much tactile feedback shapes my everyday actions, like holding a cup or turning a page, and how it completely disappears when interacting with digital screens. This made me more aware of how much current technology prioritizes visual simplicity over physical engagement.

I wonder whether designers will continue to rely on interfaces that ignore the full capabilities of the human body. If our hands and bodies are so complex and expressive, why is most technology reduced to tapping and swiping? His point about finger blindness really is scary to think about, especially if we lose the ability to feel and understand our objects. This makes me wonder whether convenience and market trends are prioritized over innovation, or if designing for full-body interactions is simply too difficult to do for every single person. It is interesting to see how we adapt to our devices rather than devices adapting to us. Overall, the reading challenged my assumption that technological progress is always linear and improving.

I think the follow-up was quite interesting. I understand that his goal was to highlight a problem and push others to explore it. I am not sure why people expect an immediate answer rather than seeing critique as the starting point for innovation. I was also surprised that removing the body from interaction, like through voice or brain interfaces, might actually reduce human experience. I had not thought about how much physical interaction shapes understanding. To be honest, this made me reflect on how passive I have become in using technology and whether easier always means better.

Week 9 – Analog and Digital Sensors

Here are pictures and videos:

^ if that does not work here is the google drive link to the video:

https://drive.google.com/file/d/1cqjdY0IDc7IcCNzmsgcox7MWBKphB9yT/view?usp=sharing

Here is the GitHub link: https://github.com/farahshaer/Intro-to-IM/blob/56d1cd018f4c8af02c5288f277d48bbc5288f498/sketch_apr4a_20260404184101.ino 

Overall concept

So, for this project, I wanted to make a system where red and green LEDs react to the light in the environment. I used a photoresistor to detect the amount of light in the environment. When it’s dark, the red LED turns on, and when it’s bright, the green LED lights up. There is also a button that lets you make the LEDs blink if you want.

Code Highlight

One part of the code that I am particularly proud of is where the LEDs respond to the light and button input, basically the logic that decides which LED to turn on. I used digitalWrite for the red LED to turn it fully on or off, and analogWrite for the green LED for brightness control using PWM. It also makes the LEDs blink if the button is pressed. Here is the code snippet:

//Dark Environment
  if (sensorValue < 790) {        //if the light level is below the midpoint value = dark
    digitalWrite(greenLED, LOW);  //turns the green led off in the dark
    if (buttonState == HIGH) {    //and if the button is pressed make the red led blink
      digitalWrite(redLED, HIGH);
      delay(50);
      digitalWrite(redLED, LOW);
      delay(50);
    } else {
      digitalWrite(redLED, HIGH);  //if the button is not pressed keep the red led on
    }
  }
  //Bright Environment
  else {                                  //if the light level is above the midpoint value = light
    digitalWrite(redLED, LOW);            //turn off the red led in the light
    if (buttonState == HIGH) {            //if the button is pressed make the green led blink
      analogWrite(greenLED, brightness);  //to set the brightness based on the mapped sensor values
      delay(50);
      analogWrite(greenLED, 0);
      delay(50);
    } else {                              //if the button is not pressed keep the green led on
      analogWrite(greenLED, brightness);  //to set the brightness based on the mapped sensor values
    }
  }
}

Reflection/Future work

For the wiring, it was pretty straightforward. The photocell is connected to the analog pin A0 and reads the light level, and is connected to a 10k resistor. The red LED is connected to digital pin 8 because it only needs on/off control. The green LED is connected to PWM pin 9, allowing its brightness to be controlled through code using analogwrite. The button is connected to digital pin 2, and its state is read using digitalRead. In the code, the sensor values are first constrained to a usable range and then mapped to a PWM range of 0-255 using the map function. This allows the green LED’s brightness to adjust to the amount of light detected by the photocell. The code then checks whether it is dark or bright, turns the correct LED on, and makes it blink if the button is pressed.

This assignment was very helpful. I used the lecture slides for reference. It helped me learn how to combine the sensors leds and buttons. Using the PWM for the green LED allowed me to explore the brightness control instead of just turning the LED on and off. Also, looking at the photocell readings in the serial monitor helped me understand the sensor range and change it in the constrain and map functions.

For future improvements, I could add more LEDs and maybe make the blinking speed or brightness based on how dark or bright it is, or I could incorporate more sensors to make the system even more interactive.

Here is my hand-drawn schematic:

Reading Reflection – Week 9

Physical Computing’s Greatest Hits (and misses)

This was an interesting read, especially looking through all of the different projects. What stood out to me was the author’s point that many physical computing projects repeat the same themes every year. At first, this surprised me because I usually think that in creative fields, you are supposed to come up with something new and original. But reading this made me realize that originality does not always mean starting from scratch. It could be taking a familiar idea and just approaching it in a different way, which can still lead to something unique. I think this perspective makes me feel a bit better about the physical computing projects, because I was always afraid that my idea would have already been created or would be too similar to someone else’s concept. I also thought that these projects were too complex, but they actually come from simple concepts, some of which we even covered in class.

I also really liked the discussion about thescooby doo painting and the video mirror, where it was visually impressive but sometimes limited because people mostly just stand there and wave their hands. I thought this was interesting because it points out that something can look cool, but still does not create a very deep, meaningful interaction. Overall, I think this reading helped me think more about the relationship between creativity and physical interactions. It made me realize that the most interesting projects come from designing meaningful ways for people to interact with it. I think this reading also helped me get some inspiration from others for this week’s assignment.

 

Making Interactive Art: Set the Stage, Then Shut Up and Listen

This reading definitely made me think differently about what interactive art actually is. I loved how the author argued that artists should not interpret their own interactive work, it something I never thought about. I always assumed that explaining your concept was needed so the audience would understand what you mean, but it is the opposite. The artwork should allow people to form their own interpretations through their experience with the work. I found this idea interesting because it shifts the focus away from the artist and instead lets the audience become part of the creative process.

I also liked the way the author described interactive art as a conversation between the artwork and the participant. It reminds me of the constant point in my understanding IM class, where the artwork is not the finished piece, but it is only complete through the audience’s interaction. The end result of the artwork could be different for some people, even all of the small design choices, like whether something looks touchable or has indicators, can guide how people interact with the piece, and can influence the end result. So sometimes we should limit the guidance, if the goal is to make the experience full and meaningful for each person.