Files
2026-08-03 17:46:14 -04:00

175 lines
8.7 KiB
Markdown

# Current API Landscape
Snapshot taken 2026-08-03 from the generated LuaLS stubs in Slate32 and CrossPoint Reader.
This inventory explains the gaps between the current firmwares and the contracts under
`lua/api/core/` and `lua/api/features/`.
## Summary
| | LCD / Slate32 | E-ink / CrossPoint |
|---|---:|---:|
| Declared functions | 77 | 67 |
| Names present in both | 27 | 27 |
| Same parameter list | 21 | 21 |
| Same name, different parameter list | 6 | 6 |
Matching declarations do not guarantee matching behavior. Important differences remain in
filesystem limits and ordering, TLS verification, network ownership, colors, and lifecycle.
## Original Common Ground
These names and parameter lists matched before the clean contract was defined. They are useful
implementation inventory, not constraints on `lua/api/core/`.
| Namespace | Functions | Remaining decisions |
|---|---|---|
| `http` | `get`, `head`, `delete`, `post`, `patch`, `download`, `urlencode` | The contract now returns `HttpResponse|nil, error`, requires a response `maxBytes`, and authenticates TLS. |
| `fs` | `exists`, `readFile`, `writeFile`, `listFiles`, `listDirs` | Standardize the read cap, sorted listings, path validation, and failure returns. |
| `log` | `debug`, `info`, `error` | Mostly ready. |
| `sys` | `delay`, `setTickInterval` | The clean contract drops both; callback timers replace periodic ticks and blocking delays. |
| `wifi` | `disconnect`, `isConnected` | Decide whether disconnect ownership is app-specific or device-wide. |
The basic `gui` drawing primitives are also intended for core. Colors will be opaque,
platform-native integers produced by `gui.color(r, g, b)`: RGB565 on LCD and quantized grayscale
on e-ink. Apps that need to be portable use `gui.color` rather than hard-coded values.
## Same Name, Different Signature
| Function | LCD | E-ink |
|---|---|---|
| `gui.clear` | `(color)` | `()` |
| `gui.drawLine` | `(x1, y1, x2, y2, color)` | `(x1, y1, x2, y2, width, color)` |
| `gui.drawText` | `(text, x, y, color, bg)` | `(font, x, y, text, color, style)` |
| `gui.fillCircle` | `(x, y, radius, color, bg)` | `(cx, cy, radius, color)` |
| `gui.getTextWidth` | `(text)` | `(font, text, style)` |
| `wifi.connect` | `(ssid, password)` | `()` using stored credentials |
These GUI differences are current implementation drift, not permanent display features. Wi-Fi
is also generic drift: both connection forms are useful, so the eventual shared signature can
make credentials optional after both firmwares implement both behaviors.
## Agreed GUI Direction
Basic geometry and text measurement belong in core with identical signatures:
```lua
gui.getWidth()
gui.getHeight()
gui.color(r, g, b)
gui.clear(color?)
gui.fillRect(x, y, w, h, color)
gui.drawRect(x, y, w, h, color)
gui.drawLine(x1, y1, x2, y2, color, width?)
gui.fillCircle(x, y, radius, color, background?)
gui.getTextWidth(font, text, style?)
gui.getFontHeight(font, style?)
gui.drawText(font, x, y, text, color?, style?, background?)
```
Fonts are opaque, zero-based integer IDs selected through shared semantic constants:
```lua
gui.FONT_SMALL
gui.FONT_UI
gui.FONT_BODY
gui.FONT_LARGE
```
Each implementation maps those roles to its available fonts or scales. Portable apps use the
named constants and metric functions rather than literal IDs or assumed pixel dimensions.
Physical names such as Bookerly and Noto Sans remain legacy implementation APIs, not part of
the core or e-ink feature contracts.
The optional background describes the surface behind anti-aliased output; it can have no visible
effect on a renderer without partial edge pixels. E-ink refresh policy and LCD live-frame
behavior remain feature-specific.
## Generic Features to Converge
These are not inherently LCD or e-ink concerns and should not be permanently assigned to a
display feature.
### Present only on E-ink
- Filesystem mutation and paging: `fileSize`, `mkdir`, `readLineAt`, `remove`, `removeTree`, `rename`.
These are intentionally under `lua/api/core/`; Slate32 must still implement them.
- Independent timers: `timer.after`, `timer.every`, `timer.cancel`
- `sys.uptime` / `sys.millis` naming
### Present only on LCD
- App routing: `sys.launch`, `sys.replace`, `sys.back`
- Runtime state: `sys.getAppName`, `setAppName`, `getMemory`, `isClockSynced`
- Wi-Fi management: `scan`, explicit credential connection, `forget`
- SD-backed `require` and app-local modules (runtime behavior, not a binding declaration)
- Native compact widget tree in `node.*`
The contract intentionally includes all of these generic capabilities. Both firmwares are under
our control, so they migrate to the clean API without compatibility aliases. The compact node
tree remains useful on e-ink for layout, painting, invalidation, and directional focus. Focus is
tree-level state with a deliberate appearance; moving it invalidates only the old and new nodes.
## Feature Contracts
- `buttons` guarantees physical-button polling/callbacks and button hints.
- `touch` guarantees calibrated/raw coordinates, touch callbacks, and calibration persistence.
A feature exists only where an app can call something a device may not have. Panel technology is
not such a case: firmware-owned publication and waveform policy already hold for every display, and
`gui.setFullscreen()` and `gui.roundRect()` are core, with a panel that has no gradient flattening
it exactly as `gui.color()` quantizes to grayscale. So the display is never a feature, and input is
never inferred from it. BLE/GATT remains
required core `ble`; a future `bt` namespace is reserved for Classic Bluetooth. Generic BMP,
polygon, shape, rotation, color, and text operations are core. Rotation and timezone settings are
also core, while theme persistence and application belong to shared `ui.lua`.
## Lifecycle Differences
| Concern | LCD | E-ink |
|---|---|---|
| Entry | required `init(arg)` | required `init()` |
| Navigation | Lua route stack | exit to C++ launcher |
| Input callbacks | touch down/move/up/tap | button callback and polling |
| Publication | drawing is immediately visible | apps currently call explicit refresh |
| Modules | app-local and shared `require` | effectively single-file apps |
The contract standardizes `init(arg?)`, navigation, and module loading. Optional `draw(deltaMs)`
runs once after initialization and then at most 30 FPS, best effort. The host passes monotonic
elapsed milliseconds, with zero on the first frame. Callback timers replace `on_tick`. Input
callbacks remain feature-specific. Firmware commits dirty content after callback batches and owns panel
refresh policy, including e-ink waveforms. `sys.getAPIVersion()` identifies the integer contract
version implemented by the firmware.
## Contract Rules
1. This is a clean API. Backward compatibility has no weight because all consumers are controlled
and migrate with the implementations.
2. A core function matches in name, parameters, returns, and observable behavior.
3. GUI coordinates use a top-left origin, including text; implementations translate driver
baselines and orientation details.
4. Invalid arguments raise Lua errors. Runtime failures return `nil, error`; filesystem reads
take an explicit `maxBytes` up to 64 KiB and fail rather than truncate. `fs.writeFile()` is
atomic: failure leaves the previous contents intact.
5. Apps live under `/.lua/apps`, shared modules under `/.lua/lib`, and persistent app data under
`/.lua/data/<AppId>`. Launch paths name directories relative to `apps`; firmware appends
`main.lua`. The first path component is the immutable app ID and determines `getAppDataPath()`.
6. `node` owns one focused ID outside its 16-byte nodes. Directional movement is geometric and
non-wrapping, with a distinct focused appearance.
7. `draw(deltaMs)` is the optional frame loop, capped at 30 FPS; the host supplies elapsed
monotonic milliseconds and callback-based `timer.after/every` handle periodic work.
8. Firmware commits dirty display content and owns panel refresh policy; no refresh API is
exposed to apps.
9. Apps are fully trusted; the contract adds no permissions or sandbox.
10. BLE/GATT is core `ble`; Classic Bluetooth remains undefined rather than sharing an inaccurate
namespace.
11. This repository owns portable modules under `lua/lib/`, including global theme behavior and the
declarative widget toolkit in `ui.lua`. Widgets expose only `on_enter`, `on_exit`, and
`on_click`: touch and directional focus map onto the same active-state lifecycle.
12. HTTPS authenticates certificates.
13. Generated firmware stubs are checked against this repository rather than copied here as
competing sources of truth.
14. Feature contracts contain only their declared hardware capability.
15. Runtime smoke tests cover semantics that LuaLS declarations cannot express.