Remove OpenFontRender, embedded Meslo assets, custom-font APIs, and their runtime allocation overhead. Keep the taller status layout and compact card grid, with used RAM, aligned faded WiFi bars, and tighter telemetry rows.
Cache font heights, release FreeType glyph state between apps, and catch renderer allocation failures before they cross Lua and abort the device. Individual low-memory draws degrade to allocation-free Font 1. Show disconnected WiFi as three faded zero-signal bars without expanding the icon footprint.
Embed a Latin-1 Meslo LG S default and use OpenFontRender for anti-aliased text with an explicit pixel size on each draw and measurement call. Apps may replace the one retained face with an SD-backed TTF and restore Meslo with nil. Refresh UI sizing, status telemetry, Settings typography, tests, documentation, and font license notices.
Use a two-row 44px status bar with a full-height back button, centered app name, WiFi beside the clock, and free/total RAM below. Expand grids to three portrait and four landscape columns with consistent card text and left-to-right partial rows.
Make sys.launch push the current path and argument, sys.replace switch without pushing, and sys.back restore the previous route. The status-bar chevron uses the same back action, failed child apps return to their caller, and history is capped at eight routes. Remove the redundant Settings back card.
sys.launch(path, arg) carries a string to the next app's init(arg), nil when there is
none. States share no memory, so one string is the whole handoff; anything structured
travels as a Lua literal the receiver loads. This is what a screen split across apps
needs to say "collect a password for this network".
sys.setAppName() retitles the status bar, defaulting to the directory name as before. A
setter rather than a declared constant, so one app can retitle per screen. The bar needs
no new invalidation path for it -- the name joins rotation and theme in the cache key --
and clips a name wide enough to reach the memory slot.
The bar repainted itself whole every second. It now compares each field against what
it last painted, adds seconds and a memory percentage, and keys the cache on
gui.getRotation() and ui.themeName so rotation and theme changes still repaint it.
Invalidation lives entirely in Lua; the firmware's push flag and gfx/statusbar.h are gone.
Bindings follow getName/setName/isName, persisted preferences move from sys to a settings
table, and gui.setRotation takes degrees like settings does. A bar that dies mid-run now
keeps its rows reserved rather than silently resizing the running app.
Leaving an app was the app's own responsibility, so one that shipped without
an exit could only be escaped with a reset. The bar now paints a back button
into its leading square and the firmware treats that rect as home, acting on
release so a press sliding into the app cancels. The app it returns to is
/apps/home, which is what it is to the user.
Card grids in home and settings centre left to right as a unit.
The bar is host-owned chrome: the firmware clips apps into a viewport below
it, so no app can paint over it, while /lib/statusbar.lua owns the height,
repaint interval and painting. gui.fullscreen() lets touch calibration take
the physical panel back.
Launcher and settings become grids of square cards (3 across landscape, 2
portrait) via the new gui.setTextSize, ui.label and ui.cardSide. The one
function on the `app` table moves to sys.setTickInterval, alongside the new
sys.appName the bar needs.