Digital Public Bathroom


Physical computing project from grad school

Project Description

I created an experimental video game about the absurdity of modern bathroom technology, which has been over-engineered to solve nonexistent problems, resulting in lousy UX.

The objective of the game is to activate the on-screen toilet, sink and towel dispenser using a  tabletop game controller. Like using a public bathroom, accomplishing all three is easier said than done.


As a UX designer, I’m accustomed to making interfaces and experiences as effortless as possible. However. this project pushed me to think like a game designer. I had to obfuscate interactions and resist the urge to provide instructions, constantly negotiating the level of difficulty I want the player to experience.


Project inspiration
A bathroom in NYU’s new Brooklyn campus is the best example of the worst bathroom technology I’ve ever encountered.

Stall Doors

Doors have no visible handles or latches. Only conceivable affordance is to push. Even worse, default state is closed, with no signifier to indicate if stall is occupied. Must crouch down to look for legs.  



Nothing happened when I held my hand under the soap dispenser. I went to next dispenser. Still nothing. Pressing on it didn’t work. Is it out of soap? No way to know since there’s no tiny window. 


Sensor for paper towel dispenser is constantly broken.


Someone (not I!) made a poster collecting bathroom complaints halfway through the making of this project.

Task at hand

I’ve always held strong opinions on the design of modern public bathrooms, trying to reconcile why even the newest and cleanest yield miserable experiences. For my physical computing mid-term final project, I knew I wanted to create a video game of sorts, and was inspired by the campus bathroom.

How the game works
         Tabletop controller triggers on-screen animations

Controller’s layout makes it likely for the player to inadvertently trigger actions (just like a real public bathroom).

When reaching over to crank the potentiometer, you might trigger the facuet’s motion sensor, causing the sink to run for no apparent reason.

Yellow Button—Push for soap 

Silver Knob (Potentiometer)—Crank for a paper towel

Blue Ultrasonic Motion Sensor—If motion is detected within 2 inches of sensor, the faucet will run

Red (Water) Sensor—Submerging the sensor at least halfway into the cup of water triggers a toilet flushing sound 

Give it a try
         In lieu of the controller, hover your mouse around the bathroom interface (at right) to preview some of the interactions.

Try getting the toilet to flush. Wash your hands in the sink. Pull a towel from the dispenser.

See it in action

         Press play to see the water sensor flush the toilet. Sound on! 🔉

Tech specs

I assigned 4 different sensors to the 4 on-screen animations (which I spun up in p5.js), matching each animation to the sensor whose trigger most closely mimics the real-life interaction. I programmed each sensor individually, setting value thresholds as event triggers, before connecting all sensors to the microcontroller and combining the Arduino code in one sketch.

Next came the hard part — getting the microcontroller to talk to my laptop, so the sensor readings could affect the p5 UI. Since web browsers can’t access a computer’s serial ports, I downloaded the p5.serialcontol app and the p5.serialport library, which communicates with a serialserver, a WebSocket server written in node.js that provides access to the serial devices attached to my computer. Now, I had the ability to generate analog output values from my sensors and send those values (from my microcontroller) to p5 via asynchronous serial communication.

In my p5 bathroom sketch, I added a serialEvent() function to read the incoming serial data as a string until it encounters a carriage return and new line (‘rn’), at which point it checks to see if the length of the resulting string is greater than 0 bytes. If so, it uses the the split() function to split the string into an array of substrings on the commas. This is super helpful because it parses the incoming data so I know which readings are tied to which sensor. Now I could assign variables to the readings and use conditional statements to animate the p5 sketch based on the reading’s value. See the code for more detail.