Project Portfolio

Here's a curated list of some of the more interesting and fun projects that I've worked on over the years.

  1. Single-node Kubernetes Cluster
  2. Sage Game Engine
  3. twitch-eventsub-framework
  4. MBus Arrival Times
  5. Chatterino


Single-node Kubernetes Cluster

After a summer internship working directly with Kubernetes, I became interested in trying to host some of my own services within a Kubernetes cluster. After exploring managed options like EKS, GKE, DOKS, and more, I decided that the cost of a multi-node, highly-available cluster was not justifiable with my simple ambition of "just run it in Kubernetes". After looking around at possible solutions, I decided to set up a single-node K3s cluster on an $18/month DigitalOcean droplet.

kubectl cluster output
Inspecting the cluster with kubectl

Also mirroring some techniques I picked up over the prior summer, I decided to try and provision the underlying infrastructure using Terraform under an infrastructure-as-code model. This Terraform module includes the DigitalOcean droplet, the DNS records for the cluster, the public/private network configuration, and firewall rules.

To secure/isolate my cluster, I opted to set up Wireguard on the Kubernetes node and configured the control plane to bind to the Wireguard interface. I was also able to set up my home server as a peer via Wireguard, which I then configured as a sort of "metrics replicator". I'm running VictoriaMetrics in the k8 cluster while my home server exports metrics to its own Prometheus/Grafana monitoring stack.

Grafana dashboard with K3s metrics
K3s metrics exported to home server Grafana/Prometheus stack

I'm currently running only one or two services in my Kubernetes cluster, so the value add of running an entire Kubernetes node is perhaps questionable at the moment. Nonetheless, I think the whole ordeal of transforming a bare-metal (OK, it's a DO droplet, but whatever) machine into a functioning cluster complete with metrics, Traefik routing, etc. was very valuable and a fun challenge. It's also very nice to deploy rolling, validated updates to the few services running in the cluster with a single command compared to my prior method of SSHing into my home server and running a bunch of docker compose commands.

Sage Game Engine (GitHub)

During the winter semester of my junior year at the University of Michigan, I enrolled in EECS 498-007 Game Engine Architecture. This course focused on building a multipurpose 2D game engine with Lua scripting and a component-based architecture.

Screenshot of laser battle game
Laser Battle, a two-player online game

This game engine was the single largest project I've worked on for University (and close to some of my other projects) and I learned a lot about designing a performance-critical, developer-facing piece of software.

Throughout the development of my "Sage Game Engine" (or sge for short), I integrated several third-party dependencies and made use of tools like:

  • SDL2
  • GLM
  • Box2D
  • Lua + LuaBridge
  • Boost.Asio
  • CMake

Multiplayer Capabilities

At the end of the course, our final assignment was to design and implement a completely new feature of our choosing into our existing game engine. Because I mostly play multiplayer games, and because I thought it would pose an interesting technical challenge (it certainly did!), I chose to add multiplayer capabilities to my engine.

To make multiplayer "just work" for the game developer, I added the idea of a component existing in a certain "realm". A component can run on the server, on the client, on the owner client, or be "server replicated", in which case it exists across all clients and the server. Below, I show the message flow for replicating a Transform component representing the position of an actor in the scene.

Server-replicated component replication flow diagram
Server-replicated component replication flow

If you're interested in learning more about the multiplayer capabilities of sge and how they came to be, I recommend you watch the following two videos I recorded for my class:


twitch-eventsub-framework (GitHub)

I maintain an open-source framework for connecting your Go application to Twitch's EventSub API. The main goal is to enable simple dispatching of EventSub Webhook requests to your application code, letting the framework deal with the HMAC verification, unmarshalling, routing, etc.

// Create my handler with no secret key verification
handler := eventsub.NewHandler(nil)

// Process channel.update EventSub notifications
handler.HandleChannelUpdate = func(h bindings.NotificationHeaders, sub bindings.Subscription, event bindings.EventChannelUpdate) {
    fmt.Println("Got a channel.update notification!")
    fmt.Printf("Channel = %s, Title = %s\n", event.BroadcasterUserName, event.Title)
}

// Listen for HTTP requests from Twitch EventSub servers
http.ListenAndServe("127.0.0.1:8080", handler)

Recently, in a v2 redesign of the framework API, I've moved to a code generation method for dealing with the ever-growing number of EventSub events and bindings. Reproducible code generation based on simpler Go struct definitions allow for a more maintainable and stable framework.


MBus Arrival Times (Website)

Tired of standing around waiting for other University of Michigan bus tracking apps to load, I decided to create my own arrival times viewer in the form of an Apple Watch app. MBus Arrival Times, available here, uses your GPS to determine which bus stop you are standing at and displays data about the next arriving busses.

Apple Watch Image
MBus Arrival Times in action

I've also published the source code for interacting with the University of Michigan's BusTime API at https://github.com/dnsge/mbus-ltp-api.


Chatterino (GitHub)

Note: There are many talented people that also work on Chatterino! I am just one contributor.

I've been contributing to the 3rd party Twitch chat client Chatterino since early 2020. Over the years, I've worked on multiple parts of the application. For example, one feature I'm particularly proud of is message filtering using a custom programming language (unfortunately, I designed the filtering language before taking a theory of programming languages course).

Another feature that has greatly improved the Chatterino chatting experience is layered emotes. Certain custom emotes in Twitch chat can be layered on top of each other, leading to great combinations (pictured below). I worked on making layered emotes a first-class entity within our message rendering pipeline and greatly improved the accessibility around viewing them.

The layered emote tooltip of "FeelsBadMan RainTime"