refactor(api)!: one namespace per feature, screen split out

Namespaces were shared across features: `settings` was written by core, the
panel and touch, and `input` by touch and buttons. That made "does this
firmware implement the whole feature?" a question no pointer could answer.

Each namespace now belongs to exactly one feature or to core, so a feature is
a provider pointer and the compiler validates completeness:

  gui, node       -> screen, tree, under the screen feature
  settings        -> screen (rotation, theme), sys (timezone),
                     touch (calibration)
  input           -> touch, buttons

Runtime::open() no longer requires a GuiProvider; a firmware without one runs
with no screen/tree globals and reports sys.hasFeature("screen") false.
Rotation is one value again: GuiProvider::setRotation applies and persists, so
an app rotating the panel transiently puts the old value back itself.
This commit is contained in:
2026-08-05 10:26:38 -04:00
parent 445a9b2b8f
commit 75b3a2c490
26 changed files with 556 additions and 626 deletions
+11 -7
View File
@@ -26,10 +26,14 @@ native/
```
Every firmware implements all files under `lua/api/core/`. `sys.hasFeature(name)` declares
optional features; claiming one guarantees every API and behavior in its matching file. Features
compose, so a device may expose both `touch` and `buttons`. Display technology is not a feature:
an e-ink `GuiProvider` flattens a gradient the way `gui.color()` quantizes to grayscale, and the
firmware owns publication and waveform policy on every panel.
optional features; claiming one guarantees every API and behavior in its matching file or
directory. Features compose, so a device may expose both `touch` and `buttons`. A panel is the
`screen` feature -- the `screen` and `tree` namespaces, including the saved rotation and theme --
because a headless firmware supplies no `GuiProvider`. Every namespace belongs to exactly one
feature or to core, which is why touch calibration is `touch.setCalibration()` rather than a
shared settings namespace three features write to. Display technology is still not a feature:
an e-ink `GuiProvider` flattens a gradient the way `screen.color()` quantizes to grayscale, and
the firmware owns publication and waveform policy on every panel.
The contract is the app-facing Lua API, not the provider C++ interface. Shared binding
registrations carry LuaLS annotations; `tools/gen_api.py` mirrors them into `lua/api/`. Generated
@@ -47,7 +51,7 @@ provider is how `sys.hasFeature()` answers false, and its namespace additions ar
registered.
The declarations are a clean target, not the intersection of today's APIs. Existing apps and
firmwares migrate to it without compatibility aliases. Safe filesystem mutation, `node`, app
firmwares migrate to it without compatibility aliases. Safe filesystem mutation, app
navigation, module loading, and `ble` are core even where a firmware does not implement them yet.
Every app may use `require`; modules resolve from its app directory and `/.lua/lib`. This repository
owns portable shared modules such as `ui.lua`; firmware-specific modules stay with their firmware.
@@ -84,7 +88,7 @@ its provider is a wiring bug and says so.
The firmware commits dirty display content after callback batches and owns e-ink waveform
policy; apps do not refresh the panel manually. Apps are fully trusted with the complete core API.
Theme persistence and application belong to shared `ui.lua`, not the firmware `settings` binding.
Theme application belongs to shared `ui.lua`; `screen.setTheme()` only stores the name.
The native library vendors Lua 5.4.8 from GitHub tag `v5.4.8` and compiles it with `LUA_32BITS`.
Command-line and upstream test entry points are excluded; `luaconf.h` carries one documented guard
@@ -92,7 +96,7 @@ that lets the build flag select 32-bit number mode.
## Shared UI
Portable apps normally use the declarative `ui.lua` toolkit; `node` remains the low-level escape
Portable apps normally use the declarative `ui.lua` toolkit; `tree` remains the low-level escape
hatch. The baseline constructors are `screen`, `box`, `spacer`, `text`, `label`, `button`,
`custom`, and `confirm`. A screen accepts both touch and physical-button input.