Rendering 16x16 pixel graphics at 60 FPS via JavaScript on a hacked IKEA FREKVENS LED light.

I embarked on this project just about a week before Toronto went into shutdown due to the COVID-19 pandemic. I had already purchased the FREKVENS cube, with plans of doing something with it, while not being quite sure what. The entire project ended up being realized with just materials that were lying around. I mustered the courage to get cracking (and also kinda waited to share the fun, and also rely on his expertise) one weekend when my good friend Nick Matantsev came over. We pried open the box together, while somewhat exercising social distancing (Again, this was a week before things around there got really serious).

And it organically evolved into this Rube-Goldberg-like contraption, taking a long path to just rendering an animation on an LED screen:

  1. The author writes a time-based animation scene in JavaScript on a minimalistic rendering runtime using a web interface
  2. Upon submitting, the JavaScript is broadcast to rendering clients via WebSockets
  3. Inside the FREKVENS cube is a WiFi-connected Linux computer (Onion Omega 2+) that runs a Node.js daemon that picks up the JavaScript scene and starts sending rendered frames to a Node.js extension written in C++ (aka the driver)
  4. The driver uses GPIO to send pixel data to the LED controller
  5. All the clients send time synchronization requests to the server to be aware of the time delta to the one and only physical rendering client (the cube)
  6. Regardless of which screen (or the physical cube) you're looking at, all the rendering is in unison 

All the code is open-source and the GitHub repository links are in the project details.

The original cube before disassembly:

This is the LED controller (white) and the graphics controller (green) inside:

This is after replacing the graphics controller with an Arduino Uno prototype, timing code and electronics courtesy of Nick. Info on pinout + data transfer provided by Brent Marshall was also pivotal:

I continued the project on my own after that initial night of hacking.

Switching to an Onion Omega 2+, rendering some test patterns:

Some case modding to pass in a USB-C cable to power the Omega:

All the guts stuffed into the cube, with some really gnarly soldering job:

Cube closed, ugliness hidden:

Custom hole with the USB cable sticking out. QC passed, warranty void:

Rendering some Sierpiński triangles as a test animation, with a piece of red paper taped to the face as a filter to avoid getting blinded by the extremely bright LEDs:

I also repurposed the buttons on the back:

There are also status overlays rendered on top of the scenes:

Because writing JavaScript on an SSH connection to the Omega and then to restart the Node.js script was very cumbersome, I created this toolset to make pattern creation faster and more enjoyable:

A happy tweak was to connect the USB power back to the cube's own power supply by using an old Apple iPad charger I found lying around:

I made a Game of Life tribute a day after learning that John H. Conway had passed away :(

To be continued...