Skip to content

Dev Log: 2026-09-25

A playtest review put it bluntly: the concept is an 8, the UI makes it a 4. It was right more often than I liked. This build is the answer: a rebuilt unit status screen, dialogue that finally respects its own text-speed setting, a colour pass with a test behind it, and a couple of silent failures that no test had ever caught.


A review that scored the UI, not the game

The review came in at 1.5 out of 5, but almost none of it was about the game itself. Stability 5/5, difficulty "well tuned", "kinda addicting". Then a long, detailed list of UI complaints: grey headings that looked like body text, achievements whose earned and locked states looked the same, a stage clear screen with no hierarchy, tooltips running across the whole screen, a debug-looking log window on every stage clear.

Reading it again with earlier reviews next to it, the same themes kept coming back from other testers too, so I treated it as a pattern rather than one person's taste. I wrote the points down as a ranked plan (cheap fixes that read as bugs first, bigger redesigns later) and worked through it.

The cheap tier was mostly small and satisfying. Earned achievements now get a gold frame instead of relying on icon brightness, which failed because the easiest tier's icons are white by design. Section headings share one style instead of each screen picking its own grey. Long tooltips wrap. The action log button, a genuine bug-report tool that looked like leftover developer output, is now hidden unless you turn it on in Gameplay Options.

A setting that did nothing, since day one

One point asked for dialogue that appears word by word, "like the older Pokemon games, with adjustable speed". While looking for where to add that, I found the Options menu already had a Text Speed setting. Slow, Normal, Fast, saved to the config file, restored on launch. And read by nothing at all. It had been there since the very first UI commit, and dialogue had always appeared instantly.

So the reveal went in for real, with one rule that matters more than the animation itself: the first click on a line that is still appearing completes it, and only the next click advances.

func _request_advance() -> void:
    if _revealing:
        _finish_reveal()
        return
    emit_signal("_advance_pressed")

Every advance input (click, tap, Space, the Next button) goes through that one function, so none of them can skip past a half-read line. There is a short retro blip per letter, throttled so Fast never turns into a buzz, and skipped on spaces. A new Instant option shows every line at once with no sound, for anyone who preferred the old behaviour.

The unit status screen, from scratch

The status screen was the loudest complaint, and a fair one. Everything hugged the left edge, the limit break's upgrades sat in a different section from the limit break, the button to use it was a gold bar at the top of the panel, and there was no HP or XP on a screen called "status".

It is now three boxes, one job each: who she is (portrait, vehicle, movement type), how she is doing (level, XP and HP bars, colour-coded stats, a small diagram of her attack range), and what her limit break does (gauge, description, upgrades, and the Use button at the bottom when it is ready). The arrows next to the name, or Q and E, switch between units without closing it.

Then I sent it for a playtest, and the most useful feedback of the whole pass came back: the upgrade rows said things like Block charges: 4 -> 6, and it was unclear which number was the current one and what a single upgrade actually does. Every test was green and every screenshot looked fine. The layout was right, but the information was still not clear to a player.

The fix is a small component I now want everywhere: a value ladder. One box per value the upgrade can reach, the owned ones tinted in the unit's colour, the current one strongest, the locked ones grey.

Curtain Capacity
  Block charges   [ 2 ] [ 4 ] [ 6 ]

It works for every kind of upgrade ([3][4][5], [x1][x2][x3], [100%][150%][200%]), the step between two boxes says what one upgrade buys, and a maxed upgrade looks the same, just fully lit. The level-up screen now uses the same ladder with the value you are about to unlock outlined, so choosing an upgrade looks exactly like the result. Along the way "skills" became "upgrades" everywhere, because every pick only ever upgrades that unit's limit break, and "skill" had been read as a new standalone ability.

Colours that only looked readable

The reviewer asked for a real colour scheme. When I measured the existing one, two surprises came out. First, the UI and the dialogue used different colours for the same characters, and the UI set matched none of the outfits. Second, Maria's name, navy on a dark panel, came in at a contrast ratio of 1.6:1. The usual minimum for text is 4.5.

The characters now share one outfit-based set in both places, and a test checks every named text colour and every speaker colour against the panel background:

func test_theme_text_colors_are_readable_on_panels() -> void:
    for name in TEXT_COLORS:
        var ratio := contrast(TEXT_COLORS[name], UITheme.COL_PANEL_BG)
        assert_gte(ratio, MIN_CONTRAST, "%s is %.2f:1 on COL_PANEL_BG" % [name, ratio])

It also caught four side characters and the error red sitting just under the line, all lifted just enough to pass.

A font I shipped and pulled the same day

For headings I tried a pixel font with full Japanese coverage, on the theory that it would echo the pixel logo. In cropped screenshots of single titles it looked great. On a full screen it did not: its capital I is a thin bar, so "OPTIONS" read as "OPT|ONS"; it only comes in one light weight, so the title looked weaker than the bold text right under it; and it did not match the logo's chunky letters after all. It was reverted the same day, and the reasons are written down in the style notes so I do not talk myself into it again. The lesson is the useful part: judge a visual change on the full screen, next to everything it has to live with.

Two failures that had been silent for months

Two problems turned up that no test had been built to catch.

The translation table can define the same key twice without any error: the importer silently keeps the last row. I found out when a new label I added replaced an existing one in a different screen. There is now a test that rejects duplicate keys, and on its first run it found an older duplicate that had been quietly shadowed for a long time.

The second was worse. Local bug-report files (screenshots and a stage log) were being packed into every build, about 2.7 MB of dead weight, because that folder was ignored by version control but not by the engine's export. The fix is one marker file, and the project check now refuses to pass if any ignored folder is missing that marker, so it cannot happen again without a loud failure.


Bug fixes

  • The Text Speed setting had no effect. It existed since the first UI build, but dialogue always appeared instantly. Lines now reveal at the chosen speed, with a new Instant option.
  • Text Speed choices were shown in English in every language.
  • Tooltips on locked world map stages were always in English.
  • A German world map tip was cut off, and at smaller window sizes the longest English tip was clipped too. The tip box now sizes itself to the longest tip and steps the font down if needed.
  • Earned and locked achievements looked almost the same for the easiest tier, whose icons are white by design.
  • Maria's name (and a few side characters) were hard to read against the dark panels.
  • Builds contained about 2.7 MB of stray development files.

Miscellaneous

  • New tests for the text reveal and blip, the achievement frames, the contrast rule, duplicate translation keys, the unit status cards (including a check that every unit fits without scrolling in English, German and Japanese), unit switching, the value ladder and the level-up screen.
  • GDScript test suite: 1,419 passing (up from 1,363).
  • Python test suite: 647 tests, all passing (18 skipped: opt-in slow suites).
  • Build 0.1.9.106 goes out to Steam, Google Play, and itch.io.

The most valuable moment in this whole pass was not a test or a tool. It was a playtester looking at a screen that every check said was finished and asking which of two numbers was the current one. Tests tell me the screen works. Only people playing it can tell me whether it explains itself, so the next UI pass will get playtested before it is finished, not after.