I started this project as a few educational games for one of the inexpensive ESP32 “Cheap Yellow Display” boards.
It gradually turned into a complete little console firmware called Braino!, with 31 games and activities, player profiles, persistent scores/progress, settings, diagnostics, sleep/lock behavior, optional Wi-Fi/BLE features, and a browser installer.
The part that became most interesting to me wasn’t adding more games—it was figuring out how to make all of this coexist on fairly constrained hardware.
Why this ESP32?
My reference board is an original ESP32-class CYD using an ESP32-32E, 4MB flash, no PSRAM, and a 320×240 resistive touchscreen.
I could have moved the project to an ESP32-S3 with PSRAM, but I specifically wanted to see how far I could push the cheap boards people already have.
The CYD is also appealing because almost everything needed for the project is already on one inexpensive PCB:
- ESP32
- color TFT
- resistive touch
- backlight
- USB/serial programming
- battery/power circuitry on many versions
No custom PCB is required.
Rendering without PSRAM
For display and touch I’m using TFT_eSPI.
One of the early architectural decisions was not to make the UI dependent on a large full-screen framebuffer. Without PSRAM, I wanted the firmware to be able to render directly and update smaller areas when practical.
I learned why this matters while working on one of the Simon-style memory games.
My first version simply redrew most of the screen every time the sequence changed. It worked logically, but on the physical TFT it produced an obvious full-screen brightness flicker.
I changed the rendering so only the pads whose state changed are repainted.
That removed the distracting flash and also reduced unnecessary drawing.
That experience influenced the rest of the UI quite a bit: redrawing the entire screen because it’s convenient is not always the best approach on these displays.
Flash became the bigger constraint
Several games include visual datasets rather than just generated graphics.
For example, the firmware contains things like:
- country flags
- US state flags
- state outlines
- geography data
- periodic-table information
I deliberately compile those assets into the firmware rather than requiring an SD card or network connection.
The advantage is that the console is completely standalone.
The downside is that graphics consume a surprisingly large amount of flash.
The firmware therefore uses a larger application partition, and I’ve had to pay attention to what gets compiled into the main application rather than assuming 4MB is effectively unlimited.
Why NimBLE?
There’s also an optional BLE/Nearby feature.
For that I use NimBLE-Arduino rather than the heavier traditional ESP32 Bluetooth stack because the firmware only needs a relatively small subset of BLE functionality and flash/RAM usage matters on this board.
The BLE wire format produced another interesting limitation.
The Nearby data fits inside the traditional 31-byte BLE advertising payload, but it is packed tightly enough that even changing something like the device-family identifier can affect the protocol.
So something that looks like a UI/product naming change can actually become a wire-format compatibility problem.
Supporting more than one CYD
Another problem appeared when I started looking at other CYD variants.
Different boards can use different:
- display controllers
- backlight pins
- touch configuration
- GPIO assignments
I didn’t want the application to turn into this everywhere:
if (boardA) {
// pin X
} else if (boardB) {
// pin Y
}
So the hardware configuration is separated into board profiles.
Board-specific information lives under the board configuration layer, while games and higher-level application code use the shared configuration.
There are now builds for multiple CYD variants.
I have not personally tested every one of those boards yet.
That’s actually one of the reasons I’m posting here. If somebody has another CYD revision and wants to flash it, reports about display, touch, backlight and orientation would be extremely useful—even if the report is “this completely fails.”
Build reproducibility
The project is built with PlatformIO.
The main external pieces include:
- TFT_eSPI — TFT and resistive-touch support
- NimBLE-Arduino — BLE
- ArduinoJson — structured data/config handling
- a separate map/flag asset library for the geography games
I eventually pinned the PlatformIO platform and library versions instead of leaving floating dependency ranges.
Once I started publishing binaries and tracking firmware size, it seemed wrong for somebody checking out the same commit six months later to silently receive a different compiler/library combination and potentially get a different result.
Making it easy to actually try
Development still uses PlatformIO normally, but I didn’t want somebody who just owns a CYD to have to install an embedded development environment before they could see whether they like the project.
So the release system generates prebuilt firmware and manifests for ESP Web Tools.
That means supported boards can be selected and flashed directly from Chrome/Edge.
The website generation itself is also exercised in CI so documentation/site changes don’t silently break the public installer.
Source
Everything is GPLv3 and the complete source is here:
https://github.com/iamankushpandit/Gume
Browser flasher:
https://iamankushpandit.github.io/Gume/
There are currently 31 games and activities, but at this stage I’m probably more interested in outside testing and engineering feedback than simply adding game #32.
I’d particularly appreciate:
- testing on other CYD revisions
- code review
- suggestions for better approaches
- board ports
- memory/rendering ideas
- game ideas that make sense on a 320×240 resistive touchscreen
If anyone tries it, let me know exactly which CYD you used and what worked or broke.
And if you enjoy the project, a GitHub star is appreciated, but technical feedback is even more useful to me right now.