DEV Community

Cover image for How I Fixed My Own Mistake: The TCJSgame Speed.js Story
Kehinde Owolabi
Kehinde Owolabi

Posted on

How I Fixed My Own Mistake: The TCJSgame Speed.js Story

How I Fixed My Own Mistake: The TCJSgame Speed.js Story

Code Refactoring

Even as a creator, I make mistakes. Here's how I fixed a critical bug in my own game engine's performance optimization.

The Background

I created TCJSgame as a lightweight, beginner-friendly JavaScript game engine. It gained traction quickly, but users reported performance issues. The core problem was the game loop:

// Original TCJSgame v3
this.interval = setInterval(() => this.updat(), 20);
Enter fullscreen mode Exit fullscreen mode

This meant games were capped at 50 FPS and ran inefficiently. So I created speed.js as a performance enhancement.

The First Attempt (And Failure)

My initial speed.js looked deceptively simple:

Display.prototype.interval = ani;

function ani(){
    // ... game loop logic
    return requestAnimationFrame(ani);
}
Enter fullscreen mode Exit fullscreen mode

The Problem: It didn't work. The animation loop never started because I was just assigning a function to a property without ever calling it.

The Critical Bug

In my second attempt, I made an even worse mistake:

function ani(){
    display.stop() // 🚨 THIS BROKE EVERYTHING!
    // ... rest of game loop
    return requestAnimationFrame(ani);
}
Enter fullscreen mode Exit fullscreen mode

I accidentally called display.stop() inside the game loop, which meant the engine would:

  1. Start the animation frame
  2. Immediately stop itself
  3. Request another frame (which would also stop itself)
  4. Repeat infinitely without ever rendering properly

The "Aha!" Moment

The issue wasn't the concept—it was the execution. I needed to:

  1. Properly override the start method to initialize the loop
  2. Remove the destructive display.stop() call
  3. Ensure the loop actually runs continuously

The Final, Working Solution

Here's the corrected speed.js that's now published and working:

Display.prototype.interval = ani;

function ani(){
    Mouse.x = mouse.x;
    Mouse.y = mouse.y;

    display.clear(); // ✅ Correct: clear canvas each frame

    display.frameNo += 1;
    display.context.save();
    display.context.translate(-display.camera.x, -display.camera.y);

    try {
        update(); // Global game update function
    } catch (e) {
        // Silent fail for user code errors
    }

    comm.forEach(component => {
        if(component.scene == display.scene){
            component.x.move();
            try {
                component.x.update(display.context);
            } catch {
                // Handle component errors
            }
        }
    });

    display.context.restore();
    return requestAnimationFrame(ani); // ✅ Continue the loop
}
Enter fullscreen mode Exit fullscreen mode

What This Fix Actually Achieves

Before (setInterval):

  • 50 FPS cap regardless of display capability
  • CPU waste when tab is inactive
  • Janky animations due to timing mismatches
  • Poor mobile performance

After (requestAnimationFrame):

  • 60+ FPS matching display refresh rate
  • Automatic pausing when tab is inactive
  • Buttery smooth animations
  • Better battery life on mobile
  • Professional-grade performance

The Technical Lessons Learned

  1. Don't just assign functions—call them when initialization matters
  2. Test every line—one misplaced function call can break everything
  3. Understand the game loop lifecycle from start to continuous execution
  4. Keep error handling but make it non-destructive

How to Use the Fixed speed.js

Simply include it after the main TCJSgame script:

<script src="https://tcjsgame.vercel.app/mat/tcjsgame-v3.js"></script>
<script src="speed.js"></script>
Enter fullscreen mode Exit fullscreen mode

Your existing TCJSgame code will automatically run at 60 FPS without any changes!

The Moral of the Story

Even as the creator of a project, I'm not immune to bugs. The key is being willing to:

  • Acknowledge mistakes publicly
  • Iterate quickly on fixes
  • Document the process so others can learn
  • Ship the solution rather than hide the problem

The fixed speed.js is now live and helping TCJSgame developers create smoother, more professional games. Sometimes the best improvements come from fixing your own oversights.


TCJSgame is an open-source JavaScript game engine I created to make 2D game development accessible to beginners. You can find it at https://tcjsgame.vercel.app/

Tags: #JavaScript #GameDev #OpenSource #WebDevelopment #Performance

Top comments (0)