← All writing

/ 3 min read

Spare Knight: teaching the UI to explain itself

Players said the interface was hard to read. I rebuilt it as a token system inside Phaser and fixed the soft-locks on the way.

devlog / ui / phaser / readability / combat-design

Spare Knight shipped for Gamedev.js Jam 2026 with combat I was proud of and a UI I was not. The jam comments were kind and clear: the layout was hard to read, and a few players hit bugs that ended their runs. I replied “Game UI is not my forte, hopefully I’ll improve it in next builds,” and then went to find out whether that was true. This update is the answer, and it is the build that is live on itch.io now.

Start with the font

The original build used IM Fell English everywhere. It looked like a medieval manuscript, which was the point, and it read like one, which was the problem. Ability names, damage numbers, and tooltips all paid the atmosphere tax. Body text moved to Alegreya: still a warm serif that belongs in the world, but designed for reading. That one change did more for the game than any mechanic I tuned during the jam.

A token system inside a game engine

The deeper fix was structural. Text styling was scattered across scenes as ad-hoc Phaser calls, so every fix had to be applied in six places and drifted anyway. I rebuilt it the way I would build a web app: a textStyle() helper with named type roles, panel tokens for chrome, and a small atomic kit, shared atoms and a real Modal, that every scene consumes. The first bug the migration caught was in the system itself: type role objects that never resolved. Once that was fixed, restyling every non-combat scene was a sweep rather than a rewrite.

If you build design systems for the web, this is the same discipline in a different renderer. Tokens are tokens.

Make the mechanics visible

The combat rules were always deterministic. The interface just kept that a secret. The readability pass put the game state on the grid itself:

  • Enemies are highlighted directly, with their threat range shown, instead of asking you to decode cell tints.
  • Every status effect renders on its cell, and its tooltip is generated from the mechanics data, so the text cannot drift from the rules.
  • Ability buttons know why they are disabled. An out-of-range ability stays armable, and a reason tooltip tells you what is wrong instead of greying out.
  • MP costs sit on the buttons as price tags, damage numbers are signed, and hits land with real collision and an impact bounce.

The lesson repeats from ThunderBashers: readability is a mechanic. Deterministic combat only feels fair when the player can see the determinism.

The soft-locks

Two players reported turns that never ended. Both traced to the reaction system. A timing wheel could wedge in a state that never resolved, and separately, killing the turn announcer’s tween mid-flight left the turn queue waiting forever. Both were root-caused and fixed, along with a combat input crash from a stale text pool and an invisible-cursor bug that the new painted cursors replaced outright.

What carried

The whole overhaul landed as one branch, built in seven passes: typography, tooltips, ability bar, statuses, inventory counts, panel chrome, scene migration. Fixes first, then polish: fullscreen, a cursor sweep, and a Salvage and Forge layout rebuild with panels that finally line up. Player comments picked the target. The token system made hitting it cheap.

← Back to writing