DEV Community

Cover image for Kiro Set me Back 2 months

Kiro Set me Back 2 months

Building Haunt For Gold: From "Vibe Mode" to Multiplayer Production

By the Haunt For Gold Development Team

If you've visited my Kiroween game submission, the cover image will not be what you saw initially. That version was my plan for the first Kiro hackathon, but I could not finish before the deadline. Now I could; welcome to Haunt For Gold.

Building this actually took months which was a little surprising but still rewarding. In the first iteration, I always wanted to build a game and a 2D pixel-art style game. I immediately thought back to my childhood and the Gameloft game "Diamond Rush".

I played this religiously and played through multiple times, but we're in 2025. It also has to be multiplayer, and my personal preference for gaming is controllers so that's important too.

Starting in "Vibe Mode"

Now time to start. I opened Kiro and kept it in vibe mode. I just described the game, no images, nothing too deep, no mention of the inspiration either. I just asked how to build it and the best frameworks and languages for this game.

Based on its recommendations and some familiarity on my part, I went with Pixi.js. It's lightweight and very 2D focused (perfect for me). Then I spun up a new node project, added Pixi.js, and then just told it to make the game.

This is what it did:  

Side bar: This as the starting point of anything is honestly sort of crazy. A few years ago building this took about a week (if not more) but given that this was not the finished product, my job is safe.

Back to the game; not there yet. Basic keys on the screen, very ugly design (My final design is not the most beautiful thing, I know, sue me), and that was barely a game too. Just moving around.

After some clarification and creating a spec for it to build the game, we ended up with this:

Better. A game. These bones are still present in the finished game at the end. The whole premise of my game was that you move your character around to collect coins and avoid enemies. Simple really, but still didn't look the part.

Onto the Media: Part One

I needed it to look right.

Characters:

Environment:

Enemies and Coins:

I think you see the vision. I now used Kiro to spec out the rest of the things I wanted (controller support, a sound engine, testing framework, user auth).

I never got to this though. I got really busy with work, missed the hackathon deadline, and moved on for a bit.

The 4-Day Sprint (The Real Work)

Then the Kiroween hackathon came along and I got to it (for real this time). I had about 4 days to turn those "bones" into a production-ready multiplayer game. Here is the chronicle of how that actually went down.

Day 1: Foundation & The Witch

The first major hurdle was the Witch Enemy. She's the special antagonist that hunts players for a -30 point penalty. I needed her to be smart, but not too smart.

class WitchEnemy {
  constructor(mapWidth, mapHeight) {
    this.mapWidth = mapWidth;
    this.mapHeight = mapHeight;
    this.isActive = false;
    this.speed = 0.12; // Balanced for dodgeability
  }

  update(players) {
    // Chase nearest player logic
    // Collision detection
    // Cackle sound on catch
  }
}
Enter fullscreen mode Exit fullscreen mode

Key Decision: The witch speed was carefully tuned through multiple iterations. We started at 0.08 (too slow) and landed on 0.12. It had to be challenging but not impossible to dodge.

We also added a Practice Mode with an AI. The challenge here? The AI kept blowing itself up. We had to filter "bomb" type coins from its targeting logic so it could actually compete.

Day 2: Multiplayer Magic & The Controller Obsession

As I said earlier, I love controllers. Local multiplayer was a must-have. We implemented the Gamepad API to detect Xbox/PlayStation controllers.

setupGamepadControls() {
  const AXIS_THRESHOLD = 0.5;
  const pollGamepads = () => {
    const gamepads = navigator.getGamepads();
    gamepads.forEach((gamepad, index) => {
      // Map each gamepad to a player
      // Check D-pad (buttons 12-15)
      // Check analog sticks (axes 0-1)
      // Check R2 for speed boost
    });
  };
}
Enter fullscreen mode Exit fullscreen mode

The Canvas Visibility Crisis
We hit a wall on Day 2. The game canvas simply wasn't displaying in multiplayer modes. It was playing sounds, the game loop was running, but the screen was black. The fix required some aggressive CSS visibility settings and forcing a browser reflow.

// Ensure canvas is visible
canvas.style.display = "block";
canvas.style.visibility = "visible";
canvas.style.opacity = "1";
canvas.offsetHeight; // Force reflow
Enter fullscreen mode Exit fullscreen mode

Day 3: Polish & Production

We needed to make sure people didn't try to play this on their phones (since we rely on keyboards/controllers). We added a Mobile Block Page that detects the device type in the HTML head and blocks rendering if it's not a desktop.

We also fixed a weird bug where the Witch moved at different speeds in different game modes.
The Fix: Move the update logic to the main render loop (60fps) so she moves consistently regardless of the mode.

// In render loop (60fps)
if (!window.gamePaused && this.witch) {
  this.witch.update(players);
  gameState.witch = this.witch.getState();
}
Enter fullscreen mode Exit fullscreen mode

Day 4: Analytics & Insights

I built a standalone analytics service (running on a separate port) to track game metrics. We integrated tracking into all game modes to see wins, losses, and high scores.

Crucial Lesson: Database preservation. Our early deployments kept wiping the SQLite database. We had to add a backup step in our GitHub Actions workflow to preserve user data and high scores across deployments.

Tech Stack Summary

Backend: Node.js, Express, Socket.IO

Frontend: HTML5 Canvas, Vanilla JavaScript (ES6+)

Database: SQLite with Sequelize ORM

Deployment: GitHub Actions, PM2, Nginx

Conclusion

It took a while to get here, from the initial "vibe mode" prompt to a fully deployed multiplayer game. But we made it.

This game was built with passion, late-night debugging sessions, and a commitment to creating a fun, spooky multiplayer experience. Special thanks to the open-source community for the tools and libraries that made this possible.

Play Haunt For Gold: https://haunt.rotimi.name.ng
Analytics Dashboard: https://dash.rotimi.name.ng

Built with 👻 by Me

Top comments (0)