I first stumbled upon this competition through a FreeCodeCamp podcast, while in a gym. I was immediately drawn to the whole idea of 13 kilobytes constraint for a whole game, due to how bloated the web is nowadays. Game dev is also something I really wanted to explore, as it seems to be the perfect balance of technical and creativity. Despite having only 3 days left (competition goes on for a month), I decided to create (and hopefully submit) something.

The theme this year is “Black Cat”. The whole concept of cats being silent guardians and keeping dark, otherworldly, forces at bay, was an inspiration from a beautifully animated short film “For He Who Creeps”, from Love, Death & Robots Season 4. Definitely one of my favorites, after “How Zeke Got Religious”, of course.

When choosing a game engine, I figured there’s no time left to be researching what is the best engine, pros & cons etc, I just got to pick one and roll with it, and push through whatever the limitations of that engine may be. This avoids the paradox of choice (a trap I always fall into, unfortunately). I decided to pick the first engine I see recommended in JS13K’s resources page, which happens to be LittleJS.

Challenges/Stories: Link to heading

Character Movement (normalization of (0, 0) vector wasn’t what I expected) Link to heading

Normalization of a vector is required to prevent a character from moving faster diagonally. After applying the normalization, the character automatically moves upward even though no keys were pressed. Digging into the engine’s source code, I found the line that caused the issue:

    normalize(length = 1) {
        const l = this.length();
        return l ? this.scale(length / l) : new Vector2(0, length);
    }

Notice the Vector2(0, length) instead of Vector2(0, 0) at the end. I assumed the function would return a 0 vector when being fed a 0 vector. However, it is not a bug in the engine, the author has his technical reasons for this behaviour, as described in this Github issue.

This was resolved by adding checks before running normalize.

Collision Detection (movement code) Link to heading

At one point, I couldn’t get a basic collision detection to work even though I followed the documentation. Strange right? Collision detection is fundamental to any game engine, why am I having trouble with it?

Turns out, there are many different methods you can use to move a game character, and each method you choose to implement, comes with it’s own nuances, pros & cons, as perfectly described in this YouTube video. Apparently, my method of directly manipulating the position of objects, isn’t the best for physics and collision detection

// won't work for collision
this.pos.y += movementVector.normalize().y * speed;
this.pos.x += movementVector.normalize().x * speed;

// works
this.velocity.y = movementVector.normalize().y * speed;
this.velocity.x = movementVector.normalize().x * speed;

Spawning (duct tape solution for vector rotation) Link to heading

While looking for ideas on how to spawn enemies, I came across this C++ tutorial that describes a great spawning technique at 27:20. Basically, given a fixed vector and radius pointing out from the player, rotate that vector randomly so that it points to a random point in the circle around the player, where the enemy spawns.

I couldn’t get the vector rotation to work in the engine, as there isn’t much example in the documentation (probably skill issue). I used the vector rotation code found in Stack Overflow instead and implemented it, duct tape style.

Pixel Art Link to heading

This is me unleashing my inner artist, creating pixel art for the first time (referencing an art I found in OpenGameArt):

creating my pixel art

Even with the time constraint, I just had to make my own asset. I believe taking art directly from other sources, you are missing the whole point of game dev and the joy it brings (unless you are focusing on other aspects, of course). It can be ugliest thing humanity has ever seen, but it has to be yours.

Getting Textures Into The Game Link to heading

Shout out to this written guide that helped me implement textures into my game.

LitteJS is a wonderful game engine but it really could use more resources such as video tutorials (there is only one video tutorial from the author) and bite-sized examples of various features (instead of digging through full game examples for the section needed). With the limited resources, AI have trouble helping out with errors too.

Hero Image Artwork Link to heading

With a few hours left, I checked the submission page and realized I had to submit a hero image for the game. And this is my result that I ain’t proud of, done by slapping together 3 different assets quickly:

paw of fate cover photo

It would be great if I had the time to at least draw a cat.

Build System Link to heading

This is where majority of the stress kicked in. I couldn’t get the game size under 13kb and the build system provided by LittleJS is throwing an error. Using the .min.js version of the engine, combined with the zip compression with the -9 flag still results in over 20kb in file size.

When I realized the starter code example provided to run the build system does not work too, I panicked and was certain I wouldn’t make the submission. I tried Windows 10 and even SSH-ing into an Arch desktop just to verify I had the same issue (I was on a Ubuntu system). I have opened an issue too, so hopefully it gets fixed.

Anyways, I eventually got it down to 8kb by combining the half broken script, along with lot’s of manual work and file manipulation (I will spare you the gory details).

Conclusion Link to heading

Overall, the game was a far cry from what I had in mind, I didn’t get to implement most of my ideas. But I am just really happy to have submitted something for JS13K 2025!

Game URL: https://js13kgames.com/2025/games/paw-of-fate