Post-Mortem: Recreating Donkey Kong in JavaScript
A couple of years ago, I had an idea: recreate an old sprite-based game using one of the many JavaScript game libraries available. In this article I'll be sharing some of the experiences and pitfalls while building this classic game for the web in Kaboom.js/Kaplay.js

A couple of years ago, I had an idea: recreate an old sprite-based game using one of the many JavaScript game libraries available. In this article I'll be sharing some of the experiences and pitfalls while building this classic game for the web in Kaboom.js/Kaplay.js
After browsing online sprite libraries, I landed on the ubiquitous classic Donkey Kong, specifically the Atari 2600 version. My initial thought was actually to remake the famed flop, "E.T." for Atari – who would do that, right? – but I ultimately settled on a more enjoyable style of play.
I worked on this project in my spare time over several months. While I initially considered making this article a tutorial, the game's scope is likely a bit too much for a single guide. Instead, this will be a post-mortem where I share lessons learned and, hopefully, some useful tips for your next JavaScript game build.
You can play the game here: https://supertorio-games.github.io/kaboom-donkey-kong/
Picking an Engine
For the game library, I chose Kaboom.js. I'd been experimenting with it for a couple of years and found its simple, component-style architecture compelling. It also seemed like a very approachable engine for building small web games. There are many 2D web game engines out there, with Phaser.js being the most well-known. I've spent time building some prototypes in Phaser, but at the time, Kaboom felt like a good fit.

Unfortunately, in June 2024, Replit, the company that sponsored and maintained the engine, ceased maintenance of the project. The community, however, decided to pick it up, creating Kaplay.js from a fork of the original Kaboom project. I've since migrated this game's codebase to the Kaplay engine. It was very straightforward, requiring only a couple of minor API and type name changes.
Coding
I genuinely enjoy the component-style architecture of building games with Kaplay. It feels quite similar to how one might build games in a bigger engine, such as Unity.
Here's our Donkey Kong entity, which consists of a couple of built-in components—Position
and Sprite
—along with a custom Stomp
component:
import k from "../game";
import stomp from "../components/stomp";
import type { Vec2 } from "kaplay";
export const donkeyKong = (starPos: Vec2) => [
k.sprite("donkeyKong", {
animSpeed: 0.4,
anim: "idle",
}),
k.pos(starPos),
stomp(),
];
In addition to built-in components, you can write your own custom components to add specific functionalities and behaviors. As an example, here's a custom component attached to Mario which scores jumps over barrels:
export default function jumpScorer(
onScoreBarrel: () => void
): JumpScorerComponent {
return {
id: "jumpScorer",
// Specify Required components
require: ["characterController"],
// This component activates each frame via the update hook
update(this: PosComp & CharacterControllerComp & JumpScorerComponent) {
if (this.characterState?.value === "jump") {
const allBarrels = k.get("barrel");
for (let barrel of allBarrels) {
if (!barrel.scored) {
if (
// Check if the barrel position is beneath the player position
this.pos.y - barrel.pos.y < 6 &&
this.pos.x - barrel.pos.x < 1
) {
barrel.scored = true;
onScoreBarrel();
}
}
}
}
},
};
}
Art & Sounds
For artwork, I had a couple of options: create the sprites from scratch or try to find an online sprite sheet. I ended up doing both! There are some really great resources for finding sprite sheets from old cartridge and PC games online; I found the sprites for this game on The Spriters Resource

I started by opening this image in Photoshop to cut out the individual sprites. However, due to the image size and compression, the sprites weren't as clean as I wanted. As a fix, I popped open Aseprite and, using this sheet as a guide, recreated each sprite. Now, I'm no pixel art master, but these sprites are pretty simple, and I was able to recreate them along with their animations. I've included the source files in the project repository as well.

While I did use sprites for the numbers, I opted for bitmap fonts for the other text, which I'll discuss in a bit.
Similarly for the audio, there are online resources where you can download ripped sound files from old games. Since I have no experience or talent for creating my own sound effects, I chose to use sound files from The Mushroom Kingdom.
Pitfalls (no pun intended) for Retro Pixel Games
Building this retro remake led me to a few surprising gotchas.
Physics & Colliders
One of the most difficult aspects of creating this game was dealing with colliders. Originally, I had planned to use physics and colliders for the barrels rolling down the map. When I first wrote this game in the Kaboom engine, its physics support was very basic. It lacked the different effector types currently seen in Kaplay.js.
Having Mario climb through platforms via ladders and barrels fall through platforms would have required some custom physics development. Instead, I approached these issues through math (as I suspect the original game developers did). Using the known positions of each platform and ladder on the map, I calculated the vectors on which each entity should move, climb, and fall.

The other collider issue I struggled with was having nested colliders on an entity. Mario has his own area collision detection for checking overlaps with barrels, so when he doesn't quite make the jump, he loses a life. I wanted to add a second area collider that activated when Mario jumps, to see if a barrel passes underneath him. I wasn't able to get a secondary nested collider to work, so instead, again, I just used some math to check if any barrels were underneath him while he was in the jump state.
Fonts
For the score, I built a custom component that takes the score and uses each digit to render the correct number sprite to the screen.

While I used the number sprites for the score, I needed a way to add text for instructions and other on-screen elements. Dealing with pixel fonts can be very frustrating. In upgrading from Kaboom 2000-3000, they removed the built-in fonts. Finding a suitable replacement font that's readable on a 232x232 pixel screen isn't easy. You pretty much have to use bitmap fonts as standard fonts look terrible when rendered that small and scaled up. In this case, I used unscii. Kaplay can take this bitmap font image and automatically map it to your input strings.

// Fonts
k.loadBitmapFont("unscii", "fonts/unscii_8x8.png", 8, 8)
Finishing the Game
As we all know, finishing a game is often the most difficult part of game development. And to be honest, I had grand plans of completing the "rivets" map and rounding out the rest of the game's features. However, seeing as this was just meant to be a learning experience and demo – not to mention also a copyrighted game and property – I decided I was happy with how it turned out and what I had learned while building it.
But you know, now that Kaboom.js has become Kaplay.js and has added new features and functionality, I'm tempted to dive back in and give the second map a go. Perhaps after I wrap up some other projects!
Full Source Code is available on github: https://github.com/Supertorio-Games/kaboom-donkey-kong