December 31, 2025 | 🧑‍💻 The birthday prank that resulted from sniping my friend's personal website domain and porting his game from 🐍 Python to 🦀 Rust

Topics: Coding

Screencast_20251115_144613 (1).gif
The Mega Man 2 Puzzle Attack - 🦀 Carcinized Title Screen

To close out 2025, I want to share a big focus of my year, the effort and accomplishment, and how it honors my best friend Mark Pulver.

This blog post shares the background where I secretly pulled together Mark's closest friends to collaborate and deliver a surprise birthday present to him: his own website domain that I sniped from him when it expired but with new content, and a modernized port of a game he made 20 years ago - that is now playable on his website directly in the web browser!

This effort also benefited me: it was an opportunity to better learn the Rust programming language, and resulted in me giving my first ever software-developer talk and presentation.

The talk was about what I learned in the process of by porting Mark's game from the Python programming language to the Rust programming language. I presented to an in-person and virtual audience of about 40 people of the Seattle Rust User Group ("SRUG") this past November at Bellevue, WA's City Hall where SRUG currently holds monthly meet-ups.

Although this blog post focuses on the story behind that talk, you can:

The presentation was a major artifact of the porting process and something that I am proud of, but this effort was really about honoring my friend Mark, his work, and bringing joy to him with a birthday surprise.

This post shares the story about the inspiration, the work, the team, and the delivery of the birthday present. It also shares a little bit of the technical background that I didn't include in my presentation.


Inception: Sniping his Personal Web Domain

Mark is my best friend. We played games together as kids, and made them in QBasic together.

I like to give surprises and play pranks for birthdays. In 2023, I noticed that he let his personal vanity domain (markpulver.com) expire. I secretly bought it. 🤭

I didn't know what I wanted to do with it for a long time. Although I considered making his personal domain something embarrassing (the Wayback Machine shows that the earliest known registered owner of the domain to be a very different person than my friend - NSFW), but during the course of developing my port of his game, I decided to do something that might be helpful instead.

Mark has done a lot of creative work, so I thought to make a portfolio website of those works. His portfolio includes a book he has written, a flash game, and also his Tetris / Mega Man 2 game that he made with 🐍 Python in 2005: Mega Man 2: Puzzle Attack, ("MM2PA"). It is this last artifact that I ended up re-creating in, or "porting" to, the Rust programming language in order to make it playable in the web browser directly on his website - but that's getting ahead of the story.

Chasing the Python; Deciding on Rust

Mark originally created MM2PA in 2005 in order to learn how to make a game in the Python programming language. Python 2.3 was the current version at the time and he used the Pygame library.

Because Mark and I always collaborated closely when we made games together as kids in Qbasic, we shared our work with each other. Over the years Mark had emailed me the various games he had made and in most cases, their source code and media assets as a zip file. This included the Python source code and media assets for MM2PA nicely bundled in a zip file.

At first, I tried to simply make the Python version of his game playable in the web browser. I tried to simply use a tool to make Python run in the web browser, but found that I couldn't even get his now 20-year old code to run on my local machine without modification. The tool, Pyscript, had no chance.

Then after talking with a fellow member of SRUG, Carl Cadie, I realized that I should do what other Rust software developers ("Rustaceans") do, and port it to Rust! This would be useful not only because of the various benefits of Rust, but also a good learning opportunity for me! I would be learning from Mark's own learning project! Standing on the shoulders of giants!

Early Challenges

At first, the old Python code wouldn't run on my Linux machine. That wasn't a surprise. It was written for Windows, true, but it was also code written for a Python runtime that was more than a whole major version behind the one on my laptop! Not only that, but some of the libraries used in MM2PA didn't even exist for modern Python!

To get MM2PA running on my Linux machine with a modern runtime, I ended up swapping out Numeric for Numpy, and spot-updating some of the code where the functions changed signature or behavior. For example, I had to change the function that calculates the elapsed game time so that it uses an integer instead of a floating point number.

Now it would run. Even though it was playable, I didn't have a way to compare my patched version against the original. How did I know that what I had running on my machine was the exact same as what Mark had originally created in 2005?! I didn't solve this problem directly, but the game is simple enough and Mark's Python code was written clearly enough to resolve most questions. I also decided that since I was making a 'new' version of the game, it was within reasonable artistic license to add enhancements or slightly change behavior if it made for a better experience.

Deciding on Macroquad

Now that I had a reasonable reference, I could code the game. But which game engine did I want to use?

I had experience building a couple other games with the Bevy engine in Rust, but I wanted to try a different Rust game engine to see if there were something more ergonomic. Also, given the size/scope of this project, Bevy felt unnecessarily powerful.

Instead, I looked at other game engines in the Rust ecosystem. I found Macroquad, and it seemed to be the right level of abstraction for my project. I also liked that it made it easy to compile to Web Assembly ("WASM") and therefore playable in modern web browsers without any additional dependencies. After developing an initial proof of concept, I was confident Macroquad was the right choice.

Starting the Porting Process

To start my port, I needed a chunking strategy to help me "eat the whole elephant".

Mark used a fairly typical game loop in constructing his game, and had game states the player transitions through in the course of a session. Initialization -> Intro -> Title Screen -> Stage Select, etc. I decided that doing one game state at a time would be a good approach and allow me to develop and test in a sequence that matches the experience of a player. Although I would later find out this approach had some draw-backs, it ended up also being the right approach for maximizing my learning.

This slide from my presentation shows my (simplified) Rust code and the game loop that mostly matches the Python loop:
Pasted image 20251231113853.png

I started my porting process by setting up the game states and the game loop, and then wrote the code for each game state starting with Initialization all the way through Credits and Quit.

Adding Features; Building a Team

Once I wrote the code for the first couple game states, and started on the Stage Select screen, I decided that this project was viable but also exciting! I started having ideas for features and enhancements that were possible as a result of developing in Rust and Macroquad: I could add a secret stage! Playable in a web browser! On mobile! etc. etc.

It was March and Mark's birthday was in July. In addition to finishing the game, I also had to set up Mark's website, configure the domain, add content, etc. If I wanted to have time to add new features and a secret stage to the game, I'd need some help. Especially since I don't have the skills to create music or art.

💡 Then I had the idea to involve Mark's mutual friends as collaborators who could all contribute to this for Mark's birthday!

So I started by discreetly contacting our mutual friends and his wife to gauge interest in contributing. I'd end up bringing on our friend Chase Bolen to help code some of the game states, a friend named Mark Brooks, to create music for a secret stage, and commission a pixel artist, John Kaimatten Bond (a game developer himself), to create original art for the secret stage.

I also included Mark's wife, Jessica, who would help review website content I created for his domain, facilitate introductions to some of Mark's other friends to help, play-test, and coordinate his schedule so we all could do a surprise birthday video call. She was instrumental in bringing the whole team together.

Late in the process, I also asked many other mutual friends to play-test so I could include their names in the default "Best Times" scoreboard:
Pasted image 20251231115700.png

Challenges

Before I could surprise Mark with a version of his game on his birthday, Mark surprised me with an updated version! Very shortly after I built the team for the project, Mark released version 1.1 of the original and sent it out to many of the same people who were on my team! His new version updated MM2PA to run on modern machines.

This caused some reflection on whether I should shelve the porting project and just focus on building out the website. I decided to continue forward since I wanted the game to be playable directly on his website and to create a new secret stage for him to play through. Fortunately, none of my collaborators who signed on were discouraged.

Crunch

The video game industry is known for "crunch time". Basically, compulsory overtime the development teams go through leading up to the launch of a game. Similarly, since Mark's birthday was coming up quickly, this project experienced some 11th hour crunch. In fact, I merged in fresh code from a contributor within a couple hours of the scheduled video call where we would unveil the website and he would play his game!

To meet the "launch window", I had to deprioritize some minor features for what I had hoped would be a full 1.0 launch. For example, touch screen support, compiled Windows and macOs binaries, and a global high score list, etc. would not make the cut. As of this writing, those features are still not implemented but are expected for a 1.0 release.

The major features did make it in time: it was playable in the browser with keyboard, there was a brand new secret stage with new graphics and music and boss logic, and a new credits sequence, and local persisted high score in the browser cache.

Naming the ported game

As the team was working on implementing the final game states, like 'Credits', I was trying to decide on the name of the ported game. For Rust developers, it is common to name a port of an existing program with a variation or reference to the fact it is written in Rust. There are even companies whose names are Rust-related, like Oxide and Ferrocene.

So following precedent, I brainstormed a few names and messaged a few collaborators with ideas to see if any resonated. I settled on the same name as Mark's game, but appended with "Carcinized". Carcinization is the tendency of various species to evolve into crabs.. The unofficial mascot of the Rust programming language is Ferris the Crab. So we "Carcinized" the Python code into Rust code. It's a bit of a joke of which one collaborator said "It sounds like we are giving Mark's game cancer.", but it also fits given the nature of the additions we made to the game.

Birthday Launch

Since Mark's wife was an insider to the project, she was able to discreetly block some of his time for us to meet on a video chat so that I could ask him to join under the guise of showing him something I made in Excel (a port of my Google Sheets AI plug-in). I had discreetly coordinated with the project collaborators to join a separate video call that he would join so we could surprise him.

The first video call was just for he and I. Once Mark joined the initial one-on-one call, I had him try out my Google Sheets tool where I had planted an Easter Egg as a "bug" that sent him to his website domain, www.markpulver.com. Once he followed that and saw his website, I "accidentally" dropped the call, and invited him to join a "new" meeting where unbeknownst to Mark, everyone else was already on and waiting.

At this point, Mark knew this was a birthday surprise, and we all watched him explore his website. Then he played the new version of his own game: Mega Man 2 Puzzle Attack - 🦀 Carcinized - including the new secret level.

Result

MM2PA-🦀 is awesome! — essentially a love letter to a love letter of Mega Man 2
- Mark Pulver

Mark was very motivated to play the game so he could get the top "Best Time", and after the call he sent me a screenshot of his achievement.

It was very satisfying for me to see Mark so engaged with a new version of his own game, on a portfolio website of his own domain that I hope will be helpful to him, together with a team of our mutual friends, and to create a novel experience that I think he will remember for a long time.

Although he is a professional programmer and I'm just a hobbyist at the moment, I really appreciated "collaborating" with past-Mark to co-create something together again - just like we used to in Qbasic when we were young kids. This was the highlight of my entire year!