Building "Castle Wars: Legacy"
Castle Wars: Legacy started as a side project in late 2024. The original idea was simple: take the classic castle wars card game that a lot of us played as kids on old Flash game sites and rebuild it for the modern web. No downloads, no installs, just open a browser and play.

The first version was rough. A basic game loop, two players taking turns playing cards, castles going up and coming down. It worked, but it felt lifeless. The cards were static, turns had no weight to them, and the whole thing looked like a prototype because it was one.
The stack
I went with Node.js and Express on the backend, with server-side rendered JSX templates and HTMX handling most of the interactivity. The real-time multiplayer runs over WebSockets. State lives in Valkey (a Redis fork) for persistence. It is not a typical setup for a game, but it works surprisingly well for a turn-based card game. Pages load fast, the server does the heavy lifting, and the client stays light.
No React, no Vue, no build step for the frontend. Just plain JSX templates rendered on the server and HTMX swapping in the updates. It sounds old-fashioned but it keeps things simple. When a player plays a card, the server calculates the new state, renders the HTML fragments, and pushes them to both players over the WebSocket. Both sides always see the same thing because there is only one source of truth.
Getting the game right
The card balance took a long time to get anywhere close to right. There are 57 cards in the game right now, split across offense, defense, magic, resource, and special types. Each one interacts with castle HP, wall height, and three resource pools (bricks, crystals, weapons). Early on, some cards were obviously broken. A well-timed Dragon could end games in three turns. Resource generation cards felt pointless when you could just rush offense. It took dozens of playtesting rounds and small tweaks to get the pacing where it should be.
The AI opponent went through several iterations too. The first version just picked random legal cards. Then it got some basic heuristics, like preferring offense when the opponent has low walls, or building walls when under pressure. It is not going to fool anyone into thinking they are playing a human, but it gives new players something to practice against and fills the gap when nobody else is online.
Campaign mode
Single player campaign was one of the bigger additions. Six levels, each with a different AI personality and modified deck. Some levels limit your resources, some give the AI a head start, one gives the AI a stacked deck of high-cost cards. The idea was to teach different strategies through the level design itself rather than through tutorials. There is a star rating system for each level based on how quickly you win, which gives people a reason to replay.
Going cross-platform
The game runs as a PWA, so you can install it on your phone or tablet and it works. It is also a Discord Activity now, so people can play directly inside Discord voice channels with friends. That was an interesting integration. Discord's Embedded App SDK handles the auth flow and lets you pull in the player's Discord identity, so their username shows up in-game automatically.
There is a Steam release in the works too. That one is an Electron wrapper that loads the web version but adds Steamworks SDK integration for achievements, cloud saves, and the Steam overlay. The game itself stays the same, just packaged differently.
Multiplayer and matchmaking
The matchmaking is intentionally simple. Click play, get put into an open room or create a new one. No queues, no ranked tiers, no wait times. For a small player base, anything more complicated would just mean longer waits. There is an ELO rating system running in the background that powers the leaderboards, but it does not gate who you can play against.
One thing I added recently is the ability to join games that are already in progress against AI. If someone is playing solo and you click play, you get a choice: jump in and replace the AI, or start a fresh room. Small feature, but it makes the game feel more alive when there are only a handful of players online.
Push notifications handle the asynchronous side. In long game mode, you can play a turn and close the browser. When your opponent plays, you get a notification to come back. It is not real-time at that point, more like correspondence chess but with castles.
Tournaments
The tournament system runs on a scheduled bracket format. Players sign up, get matched into a single-elimination bracket, and play through the rounds. Each match is a standard game with a time limit. The bracket updates live on a hex-grid map that shows which castles are still standing and which have fallen. It is probably the most over-engineered feature in the whole project, but it looks cool and gives the competitive players something to aim for.
What I learned
Building a multiplayer game on web tech taught me a lot about state management and the thousand ways things can go out of sync. WebSocket connections drop. Sessions expire. Players close their browser mid-turn and come back three days later expecting everything to still be there. Every edge case you can think of will happen, and a few you would never think of.
The HTMX approach turned out to be a good fit for this kind of game. Turns are discrete, state changes are well-defined, and the server already knows everything. There is no need for a thick client keeping its own copy of the game state. The trade-off is that you lose the ability to do complex client-side animations, but for a card game about building castles, simple transitions and CSS animations do the job.
If I were starting over, I would probably make the same tech choices. The simplicity of the stack means I spend most of my time on game features instead of fighting tooling. And for a solo project, that matters more than anything.
What is next
Steam launch is the immediate goal. After that, more campaign levels, more eye candy, and some kind of clan or guild system tied into the Discord integration. The leaderboard already tracks which Discord servers have the most active players, so building on that with server-vs-server competitions is the natural next step.
The game is free to play at https://cwl.proclive.io and as a Discord Activity. If you have any feedback or want to follow development, the in-game chat is usually the fastest way to reach me.