refactor(api)!: declare callbacks as classes an app composes

The runtime has always called fields on the table main.lua returns, but
@lua-global declared them as loose functions, so the stubs type-checked
something that does not exist and read as "define a global".

Callbacks are now @lua-app blocks that generate a class: App for the core
contract, TouchHandlers and ButtonHandlers beside the namespaces they belong
to. An app composes what it implements:

  ---@class PaintApp : App, TouchHandlers

Names follow the rest of the surface: onTouchDown rather than on_touch_down,
with the field names the runtime looks up renamed to match. @lua-field carries
the plain fields (home, data) that were prose in a preamble before.
This commit is contained in:
2026-08-05 10:42:01 -04:00
parent 75b3a2c490
commit b9f7c9347c
11 changed files with 153 additions and 87 deletions
+8 -11
View File
@@ -4,20 +4,17 @@
-- The firmware loads /.lua/main.lua into every fresh state and calls these on the
-- table it returns. Where apps live, what surrounds them and which of these an app
-- itself sees are all main.lua's to decide.
-- itself sees are all main.lua's to decide, which is why an app composes the
-- classes for the features it handles:
--
-- Fields the firmware reads: home, the route sys.back() lands on once history is
-- empty, and data, the sys.getAppDataPath() template whose ? is the app id.
-- ---@class PaintApp : App, TouchHandlers
--
-- The firmware does not clear the frame before calling draw(), and commits changed
-- display content after each callback batch using the panel's own refresh policy.
-- Timer callbacks are registered directly with timer.after/every.
---Required. Mounts the route; failing here leaves no app running.
---@param route string The app path sys.launch, sys.back or the boot recorded.
---@param arg? string The string passed to sys.launch or sys.replace.
function start(route, arg) end
---Optional frame loop, called once after start and then at most 30 FPS, best effort.
---@param deltaMs integer Monotonic milliseconds since the previous draw; zero on the first.
function draw(deltaMs) end
---@class App
---@field home? string The route sys.back() lands on once history is empty.
---@field data? string The sys.getAppDataPath() template whose ? is the app id.
---@field start fun(route: string, arg?: string) Required. Mounts the route; failing here leaves no app running.
---@field draw? fun(deltaMs: integer) Optional frame loop, called once after start and then at most 30 FPS, best effort.