| Connections Lab

Asmbly Dash

Cover Image for Asmbly Dash


Our Connections Lab midterm project was an opportunity to combine and integrate ideas we’ve been covering over the past few weeks. I recently joined Austin’s local makerspace, Asmbly. During my onboarding and training the instructor mentioned the need for a way to quickly report issues with the stations. For my MVP I wanted to create a site that could contain information about each station (tips, safety, required training) and also allow users to submit those reports to the releveant staff.


I used Next.js for this project, this choice was motivated by two key features. The dynamic routes would allow me to programatically create pages based on a simple JSON file storing the tool data. In addition, when deployed on Vercel, the Next.js API routes makes deploying serverless functions a snap. I used this feature to create a function to create emails and route them to the appropriate staff using the nodemailer library.

For the frontend code, I used TypeScript, React and CSS modules to create reusable, scoped components. While this project certainly could have been tackled without these tools, I find that React greatly reduced the amount of code authored. In addition, TypeScript and CSS modules makes it difficult for future developers to break things. This is particularly important for this project considering Asmbly staff are all volunteers so anyone could chip in.

One piece that turned out really well was the QR code generation. I used a JavaScript library to map over the tools data and generate a QR Code for each one. I even got a chance to use the print media query to format the list when printed.

Next steps

I did a playback with Charlie, the instructor who first pitched this idea and he had some great ideas. The makerspace has a wiki that has some basic information about each tool. This could be used either as the actual link target or to source data into my app. Rather than throwing the information all on one page, another version might allow the user to select from three options: Info, Maintenance, Problem. The app could then simply route the user to the correct service depending on what they’re trying to do.

| Creative Coding


Cover Image for Smell-O-Vision


This project has been a collaborative effort between myself and M Dougherty. I was incredibly excited to participate in their vision: to create an interactive, sensory experience with visuals and scents.


After some planning and feasibility experiments we decided to aim for an interactive environment that utilized camera based position detection to find the number of individuals in a space, the center point between them, and some other metrics discussed here. These datapoints would power a visualization using the P5 library and trigger scent diffusers around the room.

My primary role was to develop the machine learning integration, linking it with a live webcam and tuning it for performance in low light. M tackled hacking the diffusers so that they could be triggered from a single arduino. We both collaborated on the artistic direction for the visuals.



My previous post discussed the basic setup of the Posenet machine learning model. As it turns out the most useful data points for our v1 were the number of individuals (poses), and their average X and Y coordinates in the room. The white circles in this photo represent individual poses; the purple circle is the center point for the group.

Top down view of individuals in a lobby. A purple blob is in the center of the photo and smaller white circles are on each individual.

Feeling pretty good about the model’s ability to handle stock footage, my next mission was to experiment to find possible visualizations that could use this data. Our initial attempts at visuals used the HSB colormode and had a pretty brutal color palette no matter the saturation. The results of my experimentation were maybe interesting but they weren’t much better I think.

In the end, we knew that we wanted four different color scenes in each corner and that they should be at least vaguely red, blue, green and yellow. After a few days of experimenting, our solution was pretty simple. Whenever the groups central point crossed into a new zone, we draw the blobs in standard RGB color mode using only the channel that corresponds with that zone.

User testing with my lovely wife Raven


After settling on a visual aesthetic, the performance of our visualization (as measured with frame rate) was starting to chug and lag. I found that the most impactful improvement was significantly shrinking the P5 canvas size, then scaling it up in the browser with CSS. This ended up creating some weird misalignments between the generated Posenet positions and the newly distorted canvas. However, after correlating the video, canvas, and Posenet input resolutions, it effectively solved all of our animation lag problems.

Installation Issues

At this point, we felt comfortable beginning to move our work into our installation space (a conference room at the NYU ITP campus). When using a proper webcam instead of the my Macbook’s, we ran into quite a bit of trouble finding a place for the camera due to a change in aspect ratio. We wanted the lights to be as dim as possible to enhance the visibility of the projection, but this lower light caused Posenet to struggle. In addition, we had a hard time finding a position for the camera that could see the room in its entirety. As a result, we couldn’t get any blobs to appear.

Installation Solutions

After another series of video and canvas size tweaks, we got some poses, but they would disappear eratically due to the lighting. After some experimentation, our current solution is two-fold: adjust our code to permit poorer quality poses and using post processing software to increase the exposure. It’s a super fine line between under and over detection (more blobs than people), but I’m pretty happy with the balance we’ve tuned it to at the moment.

Finally, for the camera positioning, we simply couldn’t manage to find a position that included the four quadrants of the room; I wished out loud for one of those iPhone fish eye lenses so we could tape it to the webcam. A few minutes later – in a moment of pure magic – M comes into the room brandishing a tragically unused gift from their mom: an iPhone fisheye lens. To the great delight of M’s mother, it worked like a charm.

Me setting up the FishEye lens in the corner of the room


This project was a tremendous opportunity for me to experiment with a variety of topics from machine learning, to animation, performance, and visualization. Historically, I have a difficult time delegating and trusting partners. This project, with it’s size, scope and deadline, would have been impossible task alone. However, with our shared creative vision and work ethic, M and I were able to create something really special. Getting to experience the gestalt of a truly collaborative, creative endeavor has been an incredibly rewarding lesson I’ll carry with me.

| Creative Coding

Three.js – Week Two

Cover Image for Three.js – Week Two


This week I wanted to learn more about camera movement and effects in three.js. I also wanted to experiment with bringing in outside data into the animation. M and I are working on a project to visualize group dynamics in a small room, so I started with laying data on top of a video feed using regular canvas elements. The ”levers” we were looking for in order to control the visualization were person count, average group X and Y coordinates, and a proximity or unity factor describing how close the audience was in relation to one another.

After I was able to successfully get these paramaters from a video feed, I started experimenting what an output would look like using three.js.


Sourcing the data from a video feed occurred in a series of measurements that build off of one another. Throughout the process, I drew directly onto a canvas with regular canvas drawing tools to ensure I was describing the data correctly.


The first representation of the group comes the Poesnet model, using tensorflow.js. This required a fair amount of tweaking due to the overhead view.

Overhead view of people walking in a public space with data drawn on top

Center points

The next representation came from calculating the central point of each bounding box. We can also get a solid count on the number of in the feed at this stage.

Overhead view of people walking in a public space with data drawn on top

Group average

Finding the group average would now allow us to approximate average group X and group Y coordinates. At this point it was apparent that data smoothing would be required to deal with individuals entering/exiting the scene as well as general uncertainty in the model negatively impacting the animation.

Overhead view of people walking in a public space with data drawn on top


For the final parameter, unity, a bounding box was drawn over the group‘s X and Y coordinates. Calculating the area of this bounding box allows us to approximate how close the individuals are to one another at any given moment.

We wanted to ensure that for the unity dimension, at a certain point of closeness (presumably 6 feet) there‘s no impact to prevent individuals standing closer than necessary.


To experiment with the different parameters, I used mouse position to approximate group X and unity (measured on the Y axis). Clicking the mouse has the same effect as adding an additional person.