↓ Skip to main content
  1. Gremlin Engine/

Gremlin Dev Log: January 2026 - Handhelds & Housekeeping

VeraShackle
Author
VeraShackle
Tales of computers, gadgets & gizmos.
Gremlin Dev Log - This article is part of a series.
Part 1: This Article

So, what have I actually been doing?
#

OK, the design principles posts are all very well, but talk is cheap. This is the first of what I hope will be a monthly dev log - what actually changed in Gremlin each month, what made me change it, and (inevitably) which decisions I’m already regretting.

January was a quiet month by commit count - the festive season does that to a hobby - but there were two clear themes: getting Gremlin onto whatever devices catch my attention (in this case a Christmas present), and tidying the codebase so I can actually find things in it!

The R36 Max
#

Previously in Dependency Decisions I said an important part of going through the pain of developing my own toolkit is to allow me to make things for whatever devices ‘happen to interest me’. Well, one did. The R36 Max is one of those inexpensive ARM Linux handhelds - a little games console running a stripped-down Linux - but of course I don’t feel like I really own it until I get my own Gremlin game running on it!

The R36 Max handheld console showing its default ‘Open Source Console’ boot screen
Christmas Day: the R36 Max, fresh out of the box and still blissfully Gremlin-free

The catch with these devices is that you don’t build on them, you cross-compile for them, against a sysroot image copied off the device. So Gremlin’s CMake needed teaching a couple of new tricks:

  • Use the device’s SDL2, not mine. A new CMake flag forces Gremlin to pick up SDL2 from the cross-compiled sysroot rather than building its own.
    • The device’s SDL2 already knows how to talk to its own screen and buttons. Someone else has done the hard platform work - this is exactly the SDL2 ubiquity I was so pleased about. Nice.
  • Route OpenAL through SDL2. The same flag forces OpenAL Soft to use SDL2 as its audio backend, so only one thing on the device needs to understand the audio hardware.

Over in GremlinApps, linking the Wayland client library became an explicit option too. The R36 Max runs Linux, but without Wayland, and it turns out I had quietly assumed that “Linux” meant “Wayland”. It doesn’t.

And then git got involved. My .gitignore excluded binaries globally, which is normally exactly what you want… except a cross-compile environment needs a few specific libraries from the sysroot committed. Cue one carefully targeted exception file.

So, did it work? Oh yes! Lots of my games ran on it - MiniBlaster, Cannonade, VictorVector and Buccaneer all made it onto that little screen. I’ll admit VictorVector’s title screen wasn’t quite expecting such a square display, and ‘Help Victor VCarve his way to victory’ loses the end of a few words, but that’s a problem for another day. It’s mine now :)

Who’s that entity?
#

ECS architectures are wonderful right up until you want ’the score label’ or ’the OK button’ and remember that an entity is just a number. Referring to them later is awkward unless you hold on to increasing numbers of numbers!

The culprit this time was Skirmish, my two-player sci-fi wargame, which needs a lot of UI - and UI is exactly where you keep wanting to find ’that button’ again. So January brought an EntityQueryService. Entities can carry an optional EntityName component, and a cached service resolves names back to entities. You can get at it from both Scene and ECSManager, and UIBuilder now names the entities it creates, so UI code can find its own buttons and labels again without clinging on to raw entity IDs.

The UI layout code got a bit of love at the same time - some redundant code removed, a clearer statement of what a layout actually needs, Visible components added by default, and the grid layout support I’d somehow managed to leave out entirely.

The great rename begins…
#

The last week of January started a tidy-up I’ve been putting off for far too long. Gremlin had two ECS namespaces - an older ECS and a newer GremlinECS - the fossilised remains of a migration I never quite finished. On the 27th, GremlinECS finally went, and everything lives under one ECS again.

Then I pulled out the ECS-agnostic bits - the interfaces that let any object hook into the app’s update and draw loop - gave them a new ‘AppObject’ naming convention, and moved them out of the ECS namespace altogether. Why? Because the ECS is one user of the app loop, not the owner of it, and the code should say so.

This is the kind of change that touches 70-odd files and alters no behaviour whatsoever, which is precisely why it’s so easy to keep putting off. And it isn’t finished yet, either - there’s plenty more still to move.

While I was in there, I also took fullscreen out of the preprocessor in the apps (it was breaking web embedding). It’s now decided at runtime from Settings.txt, which is where it should have been all along.

What’s next?
#

Finishing that restructure, which is currently half done and half confusing :)

Gremlin Dev Log - This article is part of a series.
Part 1: This Article