Digital Public Bathroom



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


Activate the on-screen toilet, sink and paper-towel dispenser using a homemade tabletop game controller. Like using a public bathroom, accomplishing all 3 is easier said than done.


C/C++, p5.js, p5.serialcontol app, p5.serialport library


As a UX designer, I’m accustomed to making interfaces and experiences as seamless, effortless and easy as possible. 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.

I’ve held strong opinions on the design of modern public bathrooms for years, trying to reconcile why even the newest and cleanest yield miserable experiences. In his standup bit about such pitfalls, Demetri Martin summarizes it perfectly, as he laments, “I don’t like automatic paper-towel dispensers because they don’t tell you when they’re not working. So I just end up looking like a shitty magician for a few minutes.” He goes on to ponder why they have to “use lasers and make it complicated.”

The ITP women’s bathroom is the best example of the worst application of bathroom technology I’ve ever encountered.

         A tabletop controller triggers the on-screen animations.

The controller’s layout makes it likely for the player to inadvertently trigger actions (just like a real public bathroom). When the reaching to crank the potentiometer, you might trigger the 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 Sensor (Ultrasonic Motion Detector)

If motion is detected within 2 inches of sensor, the faucet will run

Red (Water-Level) Sensor

Submerging the sensor at least halfway into the cup of water triggers a toilet flushing soun

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

         Play video to see the water sensor in action (🔉sound on!)

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.