Week 11 – Group Exercises

Group Members: Joy, Yiyang

(Arduino codes are commented in the bottom of p5 links)

1. Make something that uses only one sensor on Arduino and makes the ellipse in p5 move on the horizontal axis, in the middle of the screen, and nothing on arduino is controlled by p5

p5 & Arduino Code: https://editor.p5js.org/joyzheng/sketches/63Yg60k8D
Video Demonstrative: IMG_9638

2. Make something that controls the LED brightness from p5

p5 & Arduino Code: https://editor.p5js.org/yiyang/sketches/dtftbIzaK

3. take the gravity wind example and make it so every time the ball bounces one led lights up and then turns off, and you can control the wind from one analog sensor

p5 & Arduino Code: https://editor.p5js.org/joyzheng/sketches/v77Sd41K4
Video Demonstrative: IMG_9640

Week 11 – Reading Response

Design Meets Disability treats constraint more than a deficit. When a flow fails under limited vision or one‑hand use, the failure is a measurement of hidden demand, e.g., precision, memory, timing. Fixing those loads tends to make the product faster and safer for everyone.

The shift from accommodation to inclusive design is a key shift in the design workflow. An add‑on ramp or a screen reader retrofit treats accessibility as a patch. Building large hit targets, consistent structure, multimodal signals, and undo by default treats accessibility as a core requirement. The second approach reduces support costs and broadens use. Captions prove the point, becuase they serve deaf users first, but help viewers in noisy spaces, language learners, and anyone scanning a video on mute. Curb cuts started for wheelchairs, then made cities usable for strollers, carts, and bikes. The spillover is not an accident, but it is the direct result of “designing for constraints” that generalize. As Charles Eames believed, “design depends largely on constraints.” And I agree.

Inputs, perception, and cognition form a clear framework. Products assume hands with fine motor control, perfect vision and hearing, and uninterrupted attention. Alternatives (e.g., switch controls, eye‑tracking, high contrast, scalable text, haptics, chunked steps) lower friction and error rates across contexts. Voice control demonstrates its utility along this path—essential for limited mobility, valuable hands‑free while cooking or driving. Predictive text began as assistive technology, now it is an everyday efficiency feature, especially in coding today, a humorous but significant save of less efficient efforts. That’s why Cursor dominates.

I do have questions. Are there cases where inclusive design adds complexity that hurts clarity? For instance, voice, haptic, and visual signals can compete. The answer may be progressive disclosure. Maybe default to one strong signal, then let users layer or swap modes. But it raises another concern. How do we balance among options, and must we spend resources to develop all of them? How do teams budget for inclusive testing without turning it into a checkbox? We must tie success to task completion under constraint, not to the presence of features. If two flows pass under one‑hand use, low contrast, and divided attention, or even less for a more specific use case they are ready.

The actionable stance: Write constraints into requirements. Set minimum hit area sizes, enforce semantic structure, and require undo and confirmation for destructive actions. Prefer multimodal capability, but choose a clear default per context. Measure success as completion with minimal precision under time pressure.

Week 10 — Reading Response

Bret Victor argues that hands do two things, feel and manipulate, and that most screen-first products ignore both. On the counter I judge texture, resistance, and weight, I adjust heat by feel, I correct errors through immediate tactile feedback. On the screen I scroll and tap with one finger, I convert rich physical cues into flat sequences of steps, accuracy falls and attention shifts from food to interface.

Fitness tracking shows a similar pattern. A watch counts reps and time, yet it cannot teach grip pressure, bar path, stance, or breath. Effective coaching speaks through the body, the right cue is a change in force or timing, not another chart. A better tool would offer variable resistance and haptic prompts, small vibrations for tempo, pressure feedback for grip, and state you can feel without looking.

Even productivity tools can illustrate the loss in “transaction”. Physical sticky notes on a whiteboard build spatial memory, clusters are recalled by location and reach, the body encodes the arrangement. Dragging cards on a screen removes proprioception, scanning columns replaces simple recall by place. Tangible controllers and deformable surfaces could restore some of that embodied structure, information would be carried in texture and force, not only pixels.

To improve this, I propose we treat touch as information but not just input. Design for affordances that speak through force, texture, and spatial arrangement. If a tool mediates physical tasks or spatial understanding, add haptic and tangible feedback before adding new visual layers.

Week 10 — Electronic Drum

Concept

For our interactive media sound project, my partner, Joy Zheng, and I decided to create a simple yet expressive instrument with a few sensors and a buzzer on Arduino Uno. We wanted to build something that was intuitive to play and produced a unique, percussive sound. The result is this force-sensitive drum. Tapping different pads creates different notes, and a toggle switch shifts the entire instrument into a higher-pitched mode.

Our initial idea was inspired by the force sensors used in class to control sound. We thought, what if we could use multiple sensors to combine frequencies and create rhythms? We brainstormed a few possibilities. Could we assign different chords to each sensor, where pressing harder makes a certain chord more prominent? Or could the sensors act as modifiers for a continuous track?

We settled on a more direct approach for a playable instrument. We decided to have three Force Sensitive Resistors (FSRs) that would each trigger a distinct note, like pads on a drum machine. To meet the project requirements and add another layer of interactivity, we incorporated a digital two-way switch. Flipping this switch would transpose the notes of all three pads to a higher octave, giving the player two different sound palettes to work with.

Arduino Build

The build was straightforward, centered around an Arduino Uno and a breadboard.

Components Used:

  • 1x Arduino Uno

  • 1x Breadboard

  • 3x Force Sensitive Resistors (FSRs), our analog sensors

  • 1x Two-way toggle switch, our digital sensor

  • 1x Piezo Buzzer

  • Resistors (for the FSRs and switch)

  • Jumper wires and Alligator clips

Each of the three FSRs was connected to a separate analog input pin on the Arduino. This allows the Arduino to read a range of values based on how much pressure is applied. The toggle switch was connected to a digital pin to give us a simple ON/OFF (or in our case, Mode 1/Mode 2) reading. Finally, the piezo buzzer was connected to a digital pin capable of PWM (Pulse Width Modulation) to produce the tones.

The Arduino code continuously checks the state of our mode switch and reads the pressure on each of the three force sensors. If a sensor is pressed hard enough to cross a defined hitThreshold, it calls a function to play a corresponding sound.

To simulate it more as a drum effect, we made this for loop to create this pitch decay effect:

// drum pitch decay effect
  for (int f = baseFreq + 40; f > baseFreq; f -= 5) {
    tone(buzzer, f);
    delay(10);
  }

Challenges and Improvement

There was evolution of our instrument. We started with a basic concept (v0.1) and then refined it by adjusting the frequency gaps between the sensors for a more distinct and musical sound (v1.0a). Finally, we tweaked the delay to give it a more responsive and percussive, drum-like feel (v1.0b).

Our biggest physical challenge was the alligator clips. It was indeed a handy tool to create a prototype, but their exposed metal heads made it very easy to accidentally create a short circuit if they touched. We learned to be meticulous about checking that the rubber insulators were covering the clips properly before powering on the Arduino.

On the software side, getting the sound right was an iterative process. First, we spend time exploring the pitch gaps. Initially, the pitches were too close together and didn’t sound very musical. By trial and error, we adjusted the base frequencies to create a more noticeable and pleasant musical gap between the pads. Second, rhythm and feel in hand needed to match a those of a “drum machine”. We played with the delay() value in the main loop. A shorter delay made the instrument feel much more responsive and rhythmic.

If we were to continue this project, we could add more sensors for a full octave, or perhaps use the analog pressure value to control the volume (amplitude) of the note in addition to triggering it. It would also be interesting to experiment with different waveforms or sound profiles beyond the simple tones.

Week 9 – Two-Degree Safety

My Concept

I decided to build a “two-degree safety guardrail.” The logic is based on two separate actions:

  1. Idle State: A red LED is ON (digital HIGH).
  2. “Armed” State: A button is pressed. This turns the red LED OFF (digital LOW).
  3. “Active” State: While the button is held, a FSR (force-sensing resistor) is pressed, which controls the brightness of a green LED (my analog output).

Challenge

My challenge was getting the red LED to be ON by default and turn OFF only when the button was pressed. I tried to build a hardware-only pull-up or bypass circuit for this but struggled to get it working reliably on the breadboard.

So, I shifted that logic into Arduino code adapted from a template in the IDE.

// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2;  // the number of the pushbutton pin
const int ledPin = 13;    // the number of the LED pin

// variables will change:
int buttonState = 0;  // variable for reading the pushbutton status

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
}

void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
  if (buttonState == LOW) {
    // turn LED on:
    digitalWrite(ledPin, LOW);
  } else {
    // turn LED off:
    digitalWrite(ledPin, HIGH);
  }
}

The demo was shot with the Arduino implementation.

Schematic

However, I later figured out the pull-up logic, and was able to implement a hardware-only solution. This schematic was a result of the updated circuit.

Week 9 – Reading Response

Interactive art should be designed as a conversation (or workshop seminar) instead of a speech. The clearest takeaway from the two pieces is that affordances and arrangements matter more than artist statements. If the system communicates its possibilities through handles, hints, and constraints, the audience can complete the work through action. When artists over-script, they collapse the range of possible meanings and behaviors into one narrow path.

Physical computing’s “greatest hits” list is useful because it exposes where interaction often stalls. Video mirrors and mechanical pixels are beautiful, but they rarely push beyond “move, see response.” Gloves, floor pads, and utilty controllers introduce a structured gesture vocabulary that people already know, which shortens the learning curve. Across categories: where gesture has meaning, interaction retains depth; where mappings are shallow, novelty fades quickly.

These pieces prompt two design questions. First, what minimal cues will help a participant discover the interaction without text? Second, what state changes will keep the system from settling into a single loop? In practice, that means compositional choices, such as discrete modes, cumulative effects, and recoverable errors.

For attention sensing, presence is not engagement. Designers should think of for signals that correlate with intent, then treat them probabilistically. Use the audience’s behavior as feedback to adjust affordances, not narratives. If the work does not evolve under interaction, you likely built a display, not a performance.

Week 8 – Reading Response

If good design induces positive emotion, why do bad designs exist?

For a long time, I thought good designs not “nice-to-haves”, because it would take much mental efforts for me to even open an app I don’t like. Norman’s piece reinforced my belief, and I started noticing how intentional UX design can guide positive feelings. If good design makes users happier (and presumably more loyal), why would anyone create something clunky or unpleasant?

One big reason is cost. Last year, I bought a cheap disposable raincoat for a trip. It was thin, the buttons fell off easily, and it didn’t even cover my shoulders properly. The design was terrible, but it cost $5 compared to a $50 waterproof jacket that would’ve lasted years. For the brand, the goal was to sell a low-cost, single-use product, not to create something that felt good to wear. Good design here would’ve raised production costs, which didn’t align with their business model.

Another reason is misaligned priorities. I’ve used software for courses that’s so confusing—not p5.js, but it would be fair to mention Arduino IDE and most Adobe offerings. The team behind it probably focused solely on function, “Does it track data, can it be integrated with all hardware?” They forgot to ask, “Will this feel easy to use?” Maybe they were rushed to launch, or thought “usability” was less important than checking off feature lists.

There are also cases of designing for the wrong user. I’ve read about stories where the visually impaired struggles with many “well-designed” apps, with all the bright colors that blur together, tiny text, no screen-reader support. The designers may have imagined a “typical” user and didn’t consider how their choices would exclude others. Poor design is a lack of empathy for diverse needs.

Is software engineering compatible with good design?

Software engineering becomes non-negotiable in high-risk, high-pressure contexts, most probably the world Hamilton worked in. When a product’s failure could mean disaster (e.g., a space mission, a medical device, or a banking app), engineering ensures no crashes, no glitches, no errors that cost lives or money. Overall, reliability. I think about Apollo 11. If Hamilton’s code hadn’t detected and fixed the P01 flaw mid-flight, the moon landing must’ve failed. In that case, engineering wasn’t just “important” but existential.

But engineering and good design don’t conflict, but rather complement each other. Engineering builds the “trust” (i.e., will a product work when I need it?), and good design builds the “connection” (i.e., will it be easy, intuitive, and after all nice to use?). Take the Wio banking app as an example. Its engineering ensures my transactions are secure and fast, and its clear, low-jargon design makes it easy to check my balance or transfer money. If the app crashed every time I used it, its pretty interface wouldn’t matter. If it worked perfectly but was impossible to navigate, I’d switch to another bank.

Midterm – Pitchy Bird

following my initial progress on a backend-backed idea, I faced challenges managing the complexities of API usage and LM output, and thus switched to another idea briefly mentioned at the start of my last documentation.

Core Concept

For my midterm project, I wanted to explore how a fundamental change in user input could completely transform a familiar experience. Flappy Bird, known for its simple tap-based mechanics, was what I took to re-imagine with voice control. Instead of tapping a button, the player controls the bird’s height by changing the pitch of their voice. Singing a high note makes the bird fly high, and a low note brings it down.

The goal was to create something both intuitive and novel. Using voice as a controller is a personal and expressive form of interaction. I hoped this would turn the game from a test of reflexes into a more playful—and potentially, honestly, sillier challenge.

How It Works (and What I’m Proud Of)

The project uses the p5.js for all the visuals and game logic, combined with the ml5.js library to handle pitch detection. When the game starts, the browser’s microphone listens for my voice. The ml5.js pitchDetection model (surprisingly it’s lightweight) analyzes the audio stream in real-time and spits out a frequency value in Hertz. My code then takes that frequency and maps it to a vertical position on the game canvas. A higher frequency means a lower Y-coordinate, sending the bird soaring upwards.

click here to access the game as the embed is not functional.

I’m particularly proud of two key decisions I made that really improved the game feel.

First was the dynamic calibration for both noise and pitch. Before the game starts, it asks you to be quiet for a moment to measure the ambient background noise, which is measured set a volume threshold, so the game doesn’t react to the hum of a fan or distant chatter. Then, it has you sing your lowest and highest comfortable notes. This personalizes the control scheme for every player, adapting to their unique vocal range, which could be an important design choice for a voice-controlled game. I conseptualized this “calibration” idea and used AI to explore ways to implementation, finally coding up the components in the game.

setTimeout(() => {
  // Set noise threshold (average level + a buffer)
  noiseThreshold = mic.getLevel() * 1.5 + 0.01;
  console.log("Noise threshold set to: " + noiseThreshold);
  
  gameState = 'calibratePitch';
  isCalibratingLow = true;
  // Capture lowest pitch after a short delay
  setTimeout(() => {
    minPitch = smoothedFreq > 50 ? smoothedFreq : 100;
    console.log("Min pitch set to: " + minPitch);
    isCalibratingLow = false;
    isCalibratingHigh = true;
    // Capture highest pitch after another delay
    setTimeout(() => {
      maxPitch = smoothedFreq > minPitch ? smoothedFreq : minPitch + 400;
      console.log("Max pitch set to: " + maxPitch);
      isCalibratingHigh = false;
      // Ensure model is loaded before starting game loop with getPitch
      if (pitch) {
          gameState = 'playing';
      } else {
          console.log("Pitch model not ready, waiting...");
          // Add a fallback or wait mechanism if needed
      }
    }, 3000);
  }, 3000);
}, 2000); // 2 seconds for noise calibration

Another technical decision I’m happy with was implementing a smoothing algorithm for the pitch input. Early on, the bird was incredibly jittery because the pitch detection is so sensitive. To fix this, I stored the last five frequency readings in an array and used their average to position the bird. This filtered out the noise and made the bird’s movement feel much more fluid and intentional. Additionally, instead of making the bird fall like a rock when you stop singing, I gave it a gentle downward drift. This “breath break” mechanism hopefully makes the game feel like air.

Challenges and Future

My biggest technical obstacle was a recurring bug where the game would crash on replay. It took a lot of console-logging and head-scratching, but it ultimately turned out that stopping and restarting the microphone doesn’t work the way I’d thought. The audio stream becomes invalid after microphone stops, and I couldn’t reuse it. The solution was to completely discard the old microphone object and create a brand new one every time a new game starts.

In addition, there are definitely areas I’d love to improve. The calibration process, while functional, is still based on setTimeout, which can be sort of rigid. A more interactive approach, where the player clicks to confirm their high and low notes, would be an alternative user experience I could test and compare with. Additionally, the game currently only responds to pitch. It might be fascinating to incorporate volume as another control dimension—perhaps making the bird dash forward or shrink to fit through tight gaps if you sing louder. 

A more ambitious improvement would be to design the game in a way that encourages the player to sing unconsciously. Right now, the player is very aware that you’re just “controlling” the bird only. But what if the game’s pipe gaps prompt them to perform a simple melody? The pipes could be timed to appear at moments that correspond to the melody’s high and low notes. This might subtly prompt the player to hum along with the music, and in doing so, they would be controlling the bird without even thinking.

Week 5 – Midterm Progress

After three days of painstaking brainstorming for my midterm, I came up with two directions: one was a game-like networking tool to help people start conversations, and the other was a version of Flappy Bird controlled by the pitch of your voice.

I was undoubtedly fascinated by both, but as I thought more about the project, it was clear that I wanted to experiment with generative AI. Therefore, I combined the personal, identity-driven aspect of the networking tool with a novel technical element.

The Concept

“Synthcestry” is a short, narrative experience that explores the idea of heritage. The user starts by inputting a few key details about themselves: a region of origin, their gender, and their age. Then, they take a photo of themselves with their webcam.

From there, through a series of text prompts, the user is guided through a visual transformation. Their own face slowly and smoothly transitions into a composite, AI-generated face that represents the “archetype” of their chosen heritage.

Designing the Interaction and Code

The user’s journey is the core of the interaction design, as I already came across game state design in class. I broke the game down into distinct states, which becomes the foundation of my code structure:

  1. Start: A simple, clean title screen to set the mood.
  2. Input: The user provides their details. I decided against complex UI elements and opted for simple, custom-drawn text boxes and buttons for a more cohesive aesthetic. The user can type their region and gender, and select an age from a few options.
  3. Capture: The webcam feed is activated, allowing the user to frame their face and capture a still image with a click.
  4. Journey: This is the main event. The user presses the spacebar to advance through 5 steps. The first step shows their own photo, and each subsequent press transitions the image further towards the final archetype, accompanied by a line of narrative text.
  5. End: The final archetype image is displayed, offering a moment of finality before the user can choose to start again.

My code is built around a gameState variable, which controls which drawing function is called in the main draw() loop. This keeps everything clean and organized. I have separate functions like drawInputScreen() and drawJourneyScreen(), and event handlers like mousePressed() and keyPressed() that behave differently depending on the current gameState. This state-machine approach is crucial for managing the flow of the experience.

The Most Frightening Part

The biggest uncertainty in this project was the visual transition itself. How could I create a smooth, believable transformation from any user’s face to a generic archetype?

To minimize the risk, I engineered a detailed prompt that instructs the AI to create a 4-frame “sprite sheet.” This sheet shows a single face transitioning from a neutral, mixed-ethnicity starting point to a final, distinct archetype representing a specific region, gender, and age.

To test this critical algorithm, I wrote the startGeneration() and cropFrames() functions in my sketch. startGeneration() builds the asset key and uses loadImage() to fetch the correct file. The callback function then triggers cropFrames(), which uses p5.Image.get() to slice the sprite sheet into an array of individual frame images. The program isn’t fully functional yet, but you can see the functions in the code base.

As for the use of image assets, I had two choices. One is to use a live AI API generation call; the other is to have a pre-built asset library. The latter would be easier and less prone to errors, I agree; but given the abundance of nationalities on campus, I would have no choice but to use a live API call. It is to be figured out next week.

 

Week 5 – Reading Response

After reading Golan Levin’s “Computer Vision for Artists and Designers,” I’m left with a deep appreciation for the creativity that arose from confronting technical limitations. The article pulls back the curtain on interactive art, revealing that its magic often lies in a clever and resourceful dialogue between the physical and digital worlds, not in lines of complex code. Apparently, the most effective way to help a computer “see” is often to change the environment, not just the algorithm.

Levin shows that simple, elegant techniques like frame differencing or brightness thresholding can be the building blocks for powerful experiences, in contrast to my preexisting thought for a powerful CV system. The LimboTime game, conceived and built in a single afternoon by novice programmers who found a large white sheet of Foamcore, pushed the change in my perspective. They didn’t need a sophisticated algorithm; they just needed a high-contrast background. It suggests that creativity in this field is as much about physical problem-solving as it is about writing code. It’s a reminder that we don’t live in a purely digital world, and that the most compelling art often emerges from the messy, inventive bridge between the two.

The article also forced me to reflect on the dual nature of this technology. On one hand, computer vision allows for the kind of playful, unencumbered interaction that Myron Krueger pioneered with Videoplace back in the 1970s. His work was a call to use our entire bodies to interact with machines, breaking free from the keyboard and mouse. In the past or now, it is always joyful that our physical presence can draw, play, and connect with a digital space in an intuitive way.

On the other hand, the article doesn’t shy away from the darker implications of a machine that watches. The very act of “tracking” is a form of surveillance. Artists like David Rokeby and Rafael Lozano-Hemmer confront this directly. Lozano-Hemmer’s Standards and Double Standards, in particular, creates an “absent crowd” of robotic belts that watch the viewer, leaving a potent impression that I would not have expected from visual technology in the early 2000s.

Ultimately, this reading has shifted my perspective. I see now that computer vision in art isn’t just a technical tool for creating interactive effects. It is a medium for exploring what it means to see, to be seen, and to be categorized. The most profound works discussed don’t just use the technology; they actively raise questions about the technology. They leverage its ability to create connection while simultaneously critiquing its capacity for control. I further believe that true innovation often comes from embracing constraints, and that the most important conversations about technology could best be articulated through art.