A multi-visualizer for a place that was once home.

I was born in Portland, OR in 1988, at Bess Kaiser Hospital, during a nurse’s strike. My older brother had been a traumatic and difficult birth, and so it was decided that a planned Caesarian section would be the best way to ensure a smooth delivery for me. As an added benefit, this meant that the birth could be scheduled around the strike. And so, that July, on a hot day weeks before my projected due date, my folks got a spot in the parking lot on Interstate Avenue, and went home in the mid-afternoon with a baby, feet and hands rubbed and warmed to make the lingering blue coloration fade. The hospital closed within the next couple of years, and was razed to the ground, replaced by a scrub embankment between the actual interstate highway and the street named for it.

This site is now the national headquarters for Adidas, who design shoes for human feet and shirts for human chests and backs, to be fabricated elsewhere by human hands and shoulders. It’s about two hours drive from there to Mount Hood, and about two hours from there to the low-class beach towns of Tillamook County I’ve been going to since shortly after that finally opening my eyes, a few weeks after returning from the hospital. From there to the Media Lab at CMU, travel time depends on your means of travel.


Here at CMU, there is a live projection of a wave-like shape on the wall. The waves are as a big as the waves are in Manzanita, OR, just outside the mouth of Tillamook Bay. The height of the waves on the wall is the height of the tide in Garibaldi, OR, just inside that bay. The scale of the waterline is 1:1; if you imagine the floor of this room to be “sea level”, these waves are as high above that as the water is in Oregon, right now. “Sea Level” is of course a relative term– the level of the actual sea is anywhere from +8.0′ to -2.0′ above Sea Level. There’s a certain similarity between this and the notion of a birth time, or a birth location: if not here, where? If not now, whenever.

There is a tiny screen in front of the big wave that shows you what what is happening at Manzanita right now. It’s what’s above, here. The waves you’re seeing in the video are the same waves you’re seeing in the other video, translated through a National Weather Service API and fifteen years of living on the East Coast. The relative scale between these things is about right, don’t you think? Some things are hard to let go, even when they’ve been reduced by time to a tiny picture-in-picture in your memory. I’m reconstructing this using random sinusoidal functions. I’m reconstructing this using a prejudicial feeling that ascetic minimalism, only tighter, only more monochrome, is the only way ethically correct, and accurate, way to model a place like this. I’m reconstructing this memory using another memory. Of something I was never here for. Poorly.

There is also a basin of water, with a bright light pointing into it, reflecting the surface of the water onto the wall. There is a contact speaker attached to the bottom of the basin, playing a filter-swept noise generator that sounds like waves. When the sound gets loud enough, it makes a little pump drip water into the basin from above, and ripples show up on the wall. You’re going to have to trust me here. The pictures didn’t come out. The pictures didn’t come out. But the idea was for it to look something like this:It, of course, didn’t look like this. This is a theater piece I saw maybe ten years ago, with an old friend I don’t get to see much any more– a person whose name starts with D, and for that reason or maybe some other, I would occasionally accidentally call him “dad”. It was very snowy– we made it to the theater at the last section, far up on the Upper East Side, far from everything. I’ve been thinking about it ever since. My friend said it was one of those singular experiences you’ll never forget, that you only get a handful of, and that made me feel proud to have been able to get him the ticket. The key about this show is it’s about memory, but more crucially that there are no people in it.

But, unfortunately, there are people in every room. The concept of “room” implies people, and so you find them there. Speaking of which: the drips from the pump. During critique for this piece, a professor asked me if the timing of the waves and drips was related in any way to the timing and the structure of the video. It’s not. But he asked it in such an aggressive, dismissive way that I lied about it– now, I lied in a way that didn’t make the piece any more conceptually coherent, of course, making some additional claim about the API that really didn’t make any difference. But it felt good to lie to him.

Here’s the code for the max patch:


And while we’re at it, here’s the code for the P5.js wave modeler:

var weather;
const tideURL = 'https://www.tidesandcurrents.noaa.gov/api/datagetter?date=latest&station=9437540&product=one_minute_water_level&datum=MLLW&time_zone=lst&units=english&format=json';
const waveURL = 'https://api.weather.gov/gridpoints/PQR/46,124';
const canvasHeight = 800;
const canvasWidth = 1280;
const wallHeight = 10.0;
const wallBottom = 3;
const numWaves = 4;
const zeroPoint = canvasHeight - (canvasHeight/(wallHeight+wallBottom)*wallBottom);
var ampCtr = 10;
var newAmpCtr = 10;
var waterHeight;
var newWaterHeight;
var xSpacing;

var serial;
var portName = '/dev/tty.usbmodem14201'; 
var inData;                            
var outByte = 0;  

let waves = [];
let period = 500.0;
let fontsize = 20;
var time = "";
var name = "";

function preload(){

function setup() {
  waterHeight = newWaterHeight;
  ampCtr = newAmpCtr;
  serial = new p5.SerialPort();
  //serial.on('data', serialEvent);
  //serial.on('error', serialError);
  setInterval(askNOAA, 60000);
  setInterval(serialDrip, 1000);
  for (let i=0; i<numWaves; i++) {waves[i] = new wave();}

function wave(){
  this.size = Math.floor(Math.random()*10+7);
  this.offset = +(Math.random()*6.3).toFixed(2);
  this.speed = +(Math.random()/100).toFixed(5)+0.001;
  this.shade = Math.floor(Math.random()*75)+180;
  this.yVals = [];
  this.theta= 0;
  this.ampVar = Math.random()*ampCtr-ampCtr/2;
  this.amp = ampCtr + this.ampVar;

function askNOAA(){
  loadJSON(tideURL, gotTide);
  loadJSON(waveURL, gotWave);

function gotTide(data){
  weather = data;
  if (weather){
    newWaterHeight = (weather.data[0].v);
    newWaterHeight = map(newWaterHeight, 0.0, wallHeight, 0, canvasHeight);
    newWaterHeight = newWaterHeight.toFixed(2);
    name = weather.metadata.name;
    time = weather.data[0].t;

function gotWave(data){
  weather = data;
  if (weather){
    waveHeight = (weather.properties.waveHeight.values[0].value);
    waveHeight = waveHeight * 3.28;
    if  (waveHeight !=0){
      newAmpCtr = Math.floor(waveHeight*(wallHeight+wallBottom));

function serialDrip(){
 // s = ['A','B','C','D'];
  //i = Math.floor(Math.random()*4)

function draw() {

  for (let wave of waves){

function increment(){
  if(waterHeight < newWaterHeight) waterHeight+=.01;
  else if (waterHeight > newWaterHeight) waterHeight -=.01;
  if (ampCtr<newAmpCtr) ampCtr++;
  else if (ampCtr<newAmpCtr) ampCtr--;
  for (let wave of waves){
    wave.amp = ampCtr + wave.ampVar;


function calcWave(wave){
  var w = canvasWidth+wave.size;
  dx = (3.14159*2 / period)*wave.size;
  wave.theta += wave.speed;
  let x = wave.theta;
   for (let i=0; i <= w/wave.size; i++){
     wave.yVals[i] = sin(x+wave.offset)*wave.amp + (zeroPoint-waterHeight);

function drawWave(wave){
  for (x=0; x<wave.yVals.length; x++){
    ellipse(x*wave.size, wave.yVals[x], wave.size, wave.size);
  //yValues = [];

function drawText(){
  text(name + " | " + time, canvasWidth, canvasHeight-10);
  let divisions = canvasHeight/(wallHeight+wallBottom);
  let n = -wallBottom;
  for (let i=canvasHeight;i>0;i-=divisions){
    text('> '+n, 0, i);

And as for the Arduino that controlled the pump, it was just a single transistor switching a 12v power supply, triggered over the serial port from Max. With some basic filtering to make less like the sky was peeing into the basin. Code:

const int buttonPin = 2;
const int pumpPin = 9;
const int ledPin = 13;
int newByte;
int lastByte;

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(pumpPin, OUTPUT);
  pinMode(ledPin, OUTPUT);


void loop() {
  if (Serial.available()){
    newByte = Serial.read();

    if (newByte == lastByte) newByte = 0;
    if (digitalRead(buttonPin) == HIGH || newByte == 1){
      digitalWrite(ledPin, HIGH);
      digitalWrite(pumpPin, HIGH);
    } else{
      digitalWrite(ledPin, LOW);
      digitalWrite(pumpPin, LOW);
    lastByte = newByte;

They say you can never go home, because it’s always different. Which is of course true: people change and times change and cities undergo massive gentrification driven by an insane belief that unyielding and constant growth is an unimpeachable positive that will continue to be sustainable for the same amount of time that human civilization has existed thus far. And besides, your parents get old and die, and your friends move, or lose their minds, or slowly disappear into themselves; and maybe you realize that nothing ever made any sense, and indeed that’s the one constant through all of this.

On the other hand, for all its environmentalist overtones, isn’t that a remarkably anthropocentric way to look at the world? Decay is a constant, and you’re part of it. Standing at the upper lip of a waterfall watching the freezing white water whip past, one notices that the water is always different, and the rock always smoothing and decaying, the gorge filled with fallen trees that decay and rejoin, your feet the same stupid feet standing and supporting your towering eyes, the feet that won’t stop walking despite mounting evidence that the contrary would be a better move– what makes these things is constantly in flux, never the same, always immaterial, and yet we try and call it by the same name as long as we possibly can.

Life is, properly, a curse: inescapable, defining, visited upon you when you weren’t paying attention, destined to define your ultimate end. Comforting in its familiarity, becoming ‘you’ through lack of any other serious offers.
The water comes and goes, and comes, and goes.