What have I been up to?

James Fenn |

It's been a while since I last wrote anything here!

A lot of my time recently has been spent working on things that aren't all presented on this site. I figured I'd write a post summarizing it all, for the curious.

Unicorn Utterances, Version 2.0

Unicorn Utterances is a blog site/community I'm involved with that hosts all kinds of educational computer science and technology content.

Last week, I merged a 992-commit Pull Request into the Unicorn Utterances website that we've been working on for the past 6+ months! This included a complete overhaul of every part of the site, making it easier and more accessible to browse and read the articles we host.

To clarify, "we" includes:

I can't overstate how much of an improvement this was from the previous version of the site, and I'm really glad we've finished it.

There is a lot more to be done - and we'll likely have a full changelog posted on the site sometime soon with the most interesting changes!

Music and things

Near the end of last year, I picked up Bitwig Studio to start experimenting with fun synth noises and music production in general.

I am finding out that there are limits to what I can get to sound good with little audio knowledge to rely on. Knowing the general idea of compressors and limiters certainly helps, but there's a lot more that I'll need to figure out to know what I'm actually doing.

Overall, Bitwig is pretty fun! On the surface, I haven't seen too much setting it apart from its competitors, but its Linux support has been great and it's definitely worth checking out how its modulation system and "The Grid" works. It manages to be both intuitive and highly dynamic with what it'll let you configure out of the box. No, I'm not sponsored by them or anything.

I've put most of the stuff I've made so far on Bandcamp if you'd like to check it out!

MIDI Visualizations

I've also been taking advantage of the exported MIDI data from Bitwig to write a bit of a visualizer framework in Vue with ThreeJS and the WebCodecs API!

Here's my most recent example of this in action:

At the moment, this is a combination of three separate repositories: vue-three-js, vue-pixel, and midificator. I am considering combining those into a central monorepo, though, as I'm not really using them with anything else.

I'm planning to write a separate post about how this all works in the future, but for now, the highlights:

  • useCapture() handles delayed rendering with the WebCodecs API into a video that can be easily synced with the music. I'm impressed with how (relatively) straightforward this was to set up! This basically worked first try, and wasn't even that much to write!

  • In contrast, useRenderer() is probably the messiest part of the project, and handles all of the ThreeJS configuration being passed into Vue components.

  • Finally, Notes.vue demonstrates what this all looks like to use. This component creates a new box for each MIDI note it receives, and translates them on each frame so that they slowly move across the screen as they're played.

Game Development

I've also occasionally been messing with some game/graphics projects that I started a while back. I picked Rust and WGPU for these, as both are interesting languages that I've wanted to explore in more depth.

I think the biggest challenge in both of these has been consistency on my part. I cannot understate the importance on finding something to deliver in personal projects, no matter how small or incomplete of a state they are in. Otherwise, it's too easy to fall into a cycle of feature creep and end up with something I'll never finish.

These projects in particular have been much longer term than I'd expected - both because I worked on them quite infrequently, and because, well, there was a lot to do.


The idea behind "NIL" was to create a state machine-powered voxel world that could challenge the player with circuit-like puzzles - i.e. basically Redstone with a more explicit purpose. In general, games with resource management systems tend to set up an interesting premise that forces the player to innovate and design their own solution to accomplish a goal.

The problem is that I never quite made it to a point where I could consider implementing the above. I did manage to create a highly parallelized procedurally-generated world that could render in WGPU, hence the below screenshot:

A bunch of spikes rendered from very small light-gray cubes

However, I didn't anticipate the amount of difficulty in implementing the chunk-based graphics. This involved a plethora of floating point rounding errors, race conditions, performance issues, and eventually even a custom octree implementation.

Overall, while WGPU was a significantly better experience from other graphics libraries in some ways, there are still a lot of complex problems in building your own graphics pipeline from scratch. I wouldn't really recommend it for most projects.

I might continue this at some point in the future, but it isn't in the best state for further development at the moment. I was attracted to the technical challenge at first, but it was definitely unnecessary to attempt to build this all myself.

My next challenge will likely be implementing Rapier to replace my current physics behavior. And avoid writing my own programming language for the game logic. No matter how tempting it is... Very tempting...


Learning from my previous endeavor, I have more recently started building an overengineered Snake game using the Bevy engine.

Bevy is still powered by WGPU, but implements its own render graph system, as well as using the Entity Component System (ECS) pattern to implement game logic. I have an upcoming post about this as well - which will be written for Unicorn Utterances - to provide an introduction to ECS in more detail.

There are a few interesting features I've planned out for this project, but nothing hugely revolutionary - I'm intentionally keeping this fairly simple and limited to something I can actually achieve.

If you'd like to see the current progress, you can try out the latest build right from your web browser thanks to Bevy's WASM & OpenGL support! (be warned: it might have bugs)