@glassly/miniapp 0.3.0-dev.2 → 0.3.0-dev.462

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/README.md +219 -74
  2. package/dist/background/index.d.ts +14 -8
  3. package/dist/background/index.d.ts.map +1 -1
  4. package/dist/background/index.js +4 -0
  5. package/dist/background/index.js.map +1 -1
  6. package/dist/background/register.d.ts +1 -1
  7. package/dist/background/register.js +1 -1
  8. package/dist/display/index.d.ts +23 -0
  9. package/dist/display/index.d.ts.map +1 -0
  10. package/dist/display/index.js +17 -0
  11. package/dist/display/index.js.map +1 -0
  12. package/dist/display/measurer/TextMeasurer.d.ts +160 -0
  13. package/dist/display/measurer/TextMeasurer.d.ts.map +1 -0
  14. package/dist/display/measurer/TextMeasurer.js +272 -0
  15. package/dist/display/measurer/TextMeasurer.js.map +1 -0
  16. package/dist/display/measurer/index.d.ts +10 -0
  17. package/dist/display/measurer/index.d.ts.map +1 -0
  18. package/dist/display/measurer/index.js +11 -0
  19. package/dist/display/measurer/index.js.map +1 -0
  20. package/dist/display/measurer/script-detection.d.ts +53 -0
  21. package/dist/display/measurer/script-detection.d.ts.map +1 -0
  22. package/dist/display/measurer/script-detection.js +184 -0
  23. package/dist/display/measurer/script-detection.js.map +1 -0
  24. package/dist/display/pixelArt.d.ts +22 -0
  25. package/dist/display/pixelArt.d.ts.map +1 -0
  26. package/dist/display/pixelArt.js +126 -0
  27. package/dist/display/pixelArt.js.map +1 -0
  28. package/dist/display/profiles/g1.d.ts +33 -0
  29. package/dist/display/profiles/g1.d.ts.map +1 -0
  30. package/dist/display/profiles/g1.js +214 -0
  31. package/dist/display/profiles/g1.js.map +1 -0
  32. package/dist/display/profiles/g2.d.ts +13 -0
  33. package/dist/display/profiles/g2.d.ts.map +1 -0
  34. package/dist/display/profiles/g2.js +34 -0
  35. package/dist/display/profiles/g2.js.map +1 -0
  36. package/dist/display/profiles/index.d.ts +12 -0
  37. package/dist/display/profiles/index.d.ts.map +1 -0
  38. package/dist/display/profiles/index.js +15 -0
  39. package/dist/display/profiles/index.js.map +1 -0
  40. package/dist/display/profiles/nex.d.ts +10 -0
  41. package/dist/display/profiles/nex.d.ts.map +1 -0
  42. package/dist/display/profiles/nex.js +150 -0
  43. package/dist/display/profiles/nex.js.map +1 -0
  44. package/dist/display/profiles/types.d.ts +103 -0
  45. package/dist/display/profiles/types.d.ts.map +1 -0
  46. package/dist/display/profiles/types.js +2 -0
  47. package/dist/display/profiles/types.js.map +1 -0
  48. package/dist/display/profiles/z100.d.ts +33 -0
  49. package/dist/display/profiles/z100.d.ts.map +1 -0
  50. package/dist/display/profiles/z100.js +182 -0
  51. package/dist/display/profiles/z100.js.map +1 -0
  52. package/dist/display/scene/types.d.ts +292 -0
  53. package/dist/display/scene/types.d.ts.map +1 -0
  54. package/dist/display/scene/types.js +0 -0
  55. package/dist/display/scene/types.js.map +1 -0
  56. package/dist/display/wrapper/TextWrapper.d.ts +102 -0
  57. package/dist/display/wrapper/TextWrapper.d.ts.map +1 -0
  58. package/dist/display/wrapper/TextWrapper.js +469 -0
  59. package/dist/display/wrapper/TextWrapper.js.map +1 -0
  60. package/dist/display/wrapper/index.d.ts +12 -0
  61. package/dist/display/wrapper/index.d.ts.map +1 -0
  62. package/dist/display/wrapper/index.js +12 -0
  63. package/dist/display/wrapper/index.js.map +1 -0
  64. package/dist/display/wrapper/types.d.ts +75 -0
  65. package/dist/display/wrapper/types.d.ts.map +1 -0
  66. package/dist/display/wrapper/types.js +11 -0
  67. package/dist/display/wrapper/types.js.map +1 -0
  68. package/dist/globals.d.ts +5 -5
  69. package/dist/globals.d.ts.map +1 -1
  70. package/dist/globals.js +1 -1
  71. package/dist/globals.js.map +1 -1
  72. package/dist/hardware.d.ts +4 -18
  73. package/dist/hardware.d.ts.map +1 -1
  74. package/dist/hardware.js +2 -13
  75. package/dist/hardware.js.map +1 -1
  76. package/dist/index.d.ts +16 -10
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +3 -1
  79. package/dist/index.js.map +1 -1
  80. package/dist/knownApps.d.ts +26 -0
  81. package/dist/knownApps.d.ts.map +1 -0
  82. package/dist/knownApps.js +140 -0
  83. package/dist/knownApps.js.map +1 -0
  84. package/dist/mirror/canvas.d.ts +22 -0
  85. package/dist/mirror/canvas.d.ts.map +1 -0
  86. package/dist/mirror/canvas.js +311 -0
  87. package/dist/mirror/canvas.js.map +1 -0
  88. package/dist/mirror/geometry.d.ts +69 -0
  89. package/dist/mirror/geometry.d.ts.map +1 -0
  90. package/dist/mirror/geometry.js +75 -0
  91. package/dist/mirror/geometry.js.map +1 -0
  92. package/dist/mirror/index.d.ts +3 -0
  93. package/dist/mirror/index.d.ts.map +1 -0
  94. package/dist/mirror/index.js +2 -0
  95. package/dist/mirror/index.js.map +1 -0
  96. package/dist/mirror/types.d.ts +40 -0
  97. package/dist/mirror/types.d.ts.map +1 -0
  98. package/dist/mirror/types.js +2 -0
  99. package/dist/mirror/types.js.map +1 -0
  100. package/dist/modules/auth.d.ts +1 -1
  101. package/dist/modules/auth.d.ts.map +1 -1
  102. package/dist/modules/auth.js +2 -2
  103. package/dist/modules/auth.js.map +1 -1
  104. package/dist/modules/compass.d.ts +47 -0
  105. package/dist/modules/compass.d.ts.map +1 -0
  106. package/dist/modules/compass.js +39 -0
  107. package/dist/modules/compass.js.map +1 -0
  108. package/dist/modules/display.d.ts +192 -8
  109. package/dist/modules/display.d.ts.map +1 -1
  110. package/dist/modules/display.js +40 -3
  111. package/dist/modules/display.js.map +1 -1
  112. package/dist/modules/events.d.ts +30 -2
  113. package/dist/modules/events.d.ts.map +1 -1
  114. package/dist/modules/events.js.map +1 -1
  115. package/dist/modules/input.d.ts +40 -1
  116. package/dist/modules/input.d.ts.map +1 -1
  117. package/dist/modules/input.js +45 -1
  118. package/dist/modules/input.js.map +1 -1
  119. package/dist/modules/latest-render-scheduler.d.ts +19 -0
  120. package/dist/modules/latest-render-scheduler.d.ts.map +1 -0
  121. package/dist/modules/latest-render-scheduler.js +54 -0
  122. package/dist/modules/latest-render-scheduler.js.map +1 -0
  123. package/dist/modules/lightSensor.d.ts +44 -0
  124. package/dist/modules/lightSensor.d.ts.map +1 -0
  125. package/dist/modules/lightSensor.js +33 -0
  126. package/dist/modules/lightSensor.js.map +1 -0
  127. package/dist/modules/mic.d.ts +3 -2
  128. package/dist/modules/mic.d.ts.map +1 -1
  129. package/dist/modules/mic.js +3 -2
  130. package/dist/modules/mic.js.map +1 -1
  131. package/dist/modules/miniapps.d.ts +2 -0
  132. package/dist/modules/miniapps.d.ts.map +1 -1
  133. package/dist/modules/miniapps.js.map +1 -1
  134. package/dist/modules/mirror.d.ts +16 -0
  135. package/dist/modules/mirror.d.ts.map +1 -0
  136. package/dist/modules/mirror.js +40 -0
  137. package/dist/modules/mirror.js.map +1 -0
  138. package/dist/modules/mono-text-rows.d.ts +20 -0
  139. package/dist/modules/mono-text-rows.d.ts.map +1 -0
  140. package/dist/modules/mono-text-rows.js +26 -0
  141. package/dist/modules/mono-text-rows.js.map +1 -0
  142. package/dist/modules/navigation.d.ts.map +1 -1
  143. package/dist/modules/navigation.js +21 -14
  144. package/dist/modules/navigation.js.map +1 -1
  145. package/dist/modules/phone.d.ts +26 -1
  146. package/dist/modules/phone.d.ts.map +1 -1
  147. package/dist/modules/phone.js +28 -0
  148. package/dist/modules/phone.js.map +1 -1
  149. package/dist/modules/settings.d.ts +45 -0
  150. package/dist/modules/settings.d.ts.map +1 -0
  151. package/dist/modules/settings.js +54 -0
  152. package/dist/modules/settings.js.map +1 -0
  153. package/dist/modules/system.d.ts +21 -0
  154. package/dist/modules/system.d.ts.map +1 -1
  155. package/dist/modules/system.js +12 -0
  156. package/dist/modules/system.js.map +1 -1
  157. package/dist/modules/transcription.d.ts +3 -2
  158. package/dist/modules/transcription.d.ts.map +1 -1
  159. package/dist/modules/transcription.js +3 -2
  160. package/dist/modules/transcription.js.map +1 -1
  161. package/dist/protocol.d.ts +65 -5
  162. package/dist/protocol.d.ts.map +1 -1
  163. package/dist/protocol.js +66 -5
  164. package/dist/protocol.js.map +1 -1
  165. package/dist/react/MirrorCanvas.d.ts +10 -0
  166. package/dist/react/MirrorCanvas.d.ts.map +1 -0
  167. package/dist/react/MirrorCanvas.js +23 -0
  168. package/dist/react/MirrorCanvas.js.map +1 -0
  169. package/dist/react/index.d.ts +2 -0
  170. package/dist/react/index.d.ts.map +1 -1
  171. package/dist/react/index.js +1 -0
  172. package/dist/react/index.js.map +1 -1
  173. package/dist/react/useColorScheme.d.ts +2 -3
  174. package/dist/react/useColorScheme.d.ts.map +1 -1
  175. package/dist/react/useColorScheme.js +15 -8
  176. package/dist/react/useColorScheme.js.map +1 -1
  177. package/dist/react/useRpc.js +2 -2
  178. package/dist/react/useRpc.js.map +1 -1
  179. package/dist/react/useSafeArea.d.ts.map +1 -1
  180. package/dist/react/useSafeArea.js +2 -2
  181. package/dist/react/useSafeArea.js.map +1 -1
  182. package/dist/session.d.ts +50 -4
  183. package/dist/session.d.ts.map +1 -1
  184. package/dist/session.js +35 -6
  185. package/dist/session.js.map +1 -1
  186. package/dist/transport/auto.d.ts +2 -2
  187. package/dist/transport/auto.js +2 -2
  188. package/dist/transport/dispatch.d.ts +1 -1
  189. package/dist/transport/dispatch.js +1 -1
  190. package/dist/transport/mock.d.ts +4 -4
  191. package/dist/transport/mock.d.ts.map +1 -1
  192. package/dist/transport/mock.js +31 -7
  193. package/dist/transport/mock.js.map +1 -1
  194. package/dist/ui/index.d.ts +2 -0
  195. package/dist/ui/index.d.ts.map +1 -1
  196. package/dist/ui/index.js +1 -0
  197. package/dist/ui/index.js.map +1 -1
  198. package/package.json +19 -3
  199. package/src/background/index.ts +26 -4
  200. package/src/background/register.ts +1 -1
  201. package/src/display/index.ts +83 -0
  202. package/src/display/measurer/TextMeasurer.ts +346 -0
  203. package/src/display/measurer/index.ts +21 -0
  204. package/src/display/measurer/script-detection.ts +218 -0
  205. package/src/display/pixelArt.ts +141 -0
  206. package/src/display/profiles/g1.ts +237 -0
  207. package/src/display/profiles/g2.ts +39 -0
  208. package/src/display/profiles/index.ts +28 -0
  209. package/src/display/profiles/nex.ts +166 -0
  210. package/src/display/profiles/types.ts +132 -0
  211. package/src/display/profiles/z100.ts +198 -0
  212. package/src/display/scene/types.ts +335 -0
  213. package/src/display/wrapper/TextWrapper.ts +546 -0
  214. package/src/display/wrapper/index.ts +15 -0
  215. package/src/display/wrapper/types.ts +102 -0
  216. package/src/globals.ts +5 -5
  217. package/src/hardware.ts +6 -21
  218. package/src/index.ts +34 -6
  219. package/src/knownApps.ts +170 -0
  220. package/src/mirror/canvas.ts +322 -0
  221. package/src/mirror/geometry.ts +128 -0
  222. package/src/mirror/index.ts +2 -0
  223. package/src/mirror/types.ts +38 -0
  224. package/src/modules/auth.ts +2 -2
  225. package/src/modules/compass.ts +69 -0
  226. package/src/modules/display.ts +222 -12
  227. package/src/modules/events.ts +27 -1
  228. package/src/modules/input.ts +55 -2
  229. package/src/modules/latest-render-scheduler.ts +55 -0
  230. package/src/modules/lightSensor.ts +61 -0
  231. package/src/modules/mic.ts +3 -2
  232. package/src/modules/miniapps.ts +2 -0
  233. package/src/modules/mirror.ts +42 -0
  234. package/src/modules/mono-text-rows.ts +30 -0
  235. package/src/modules/navigation.ts +20 -14
  236. package/src/modules/phone.ts +40 -1
  237. package/src/modules/settings.ts +64 -0
  238. package/src/modules/system.ts +30 -1
  239. package/src/modules/transcription.ts +3 -2
  240. package/src/protocol.ts +72 -5
  241. package/src/react/MirrorCanvas.tsx +35 -0
  242. package/src/react/index.ts +3 -0
  243. package/src/react/useColorScheme.ts +17 -8
  244. package/src/react/useRpc.ts +2 -2
  245. package/src/react/useSafeArea.ts +2 -2
  246. package/src/session.ts +78 -8
  247. package/src/transport/auto.ts +2 -2
  248. package/src/transport/dispatch.ts +1 -1
  249. package/src/transport/mock.ts +42 -11
  250. package/src/ui/index.ts +3 -0
  251. package/dist/modules/heading.d.ts +0 -16
  252. package/dist/modules/heading.d.ts.map +0 -1
  253. package/dist/modules/heading.js +0 -20
  254. package/dist/modules/heading.js.map +0 -1
  255. package/src/modules/heading.ts +0 -23
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # @glassly/miniapp
2
2
 
3
- SDK for building Glassly local miniapps — static web apps that run inside the Glassly phone app's WebView and talk to smart glasses via a typed session API.
3
+ SDK for building Glassly local miniapps: static web apps that run inside the Glassly App's WebView and talk to smart glasses via a typed session API.
4
4
 
5
5
  > Developing this SDK or running the in-repo example from a fresh clone? Start at the **[SDK developer guide](../../../sdk/README.md)** (setup, build loop, doc map).
6
6
  > Per-module deep dives (return shapes, events, error codes): **[`sdk/docs/`](../../../sdk/docs/README.md)**.
7
- > Companion package: **[`@glassly/miniapp-cli`](../../../sdk/miniapp-cli/README.md)** — `glassly-miniapp` CLI (`dev`, `release`, `pack`, `manifest`, `permission`, `hardware`, `schema`). Per-command docs live there.
8
- > Scaffolder: `bunx create-miniapp my-app`.
7
+ > Companion package: **[`@glassly/miniapp-cli`](../../../sdk/miniapp-cli/README.md)**, the `glassly-miniapp` CLI (`dev`, `release`, `pack`, `manifest`, `permission`, `hardware`, `schema`). Per-command docs live there.
8
+ > Scaffolder: `bunx @glassly/create-miniapp my-app`.
9
9
  > Reference miniapp: [`miniapps/example-miniapp/`](../../../miniapps/example-miniapp).
10
- > High-level walkthrough: [`agents/miniapp-sdk-overview.md`](../../../agents/miniapp-sdk-overview.md).
10
+ > High-level walkthrough: [`notes/miniapp-sdk-overview.md`](../../../notes/miniapp-sdk-overview.md).
11
11
 
12
12
  ## Install
13
13
 
@@ -17,17 +17,19 @@ bun add @glassly/miniapp
17
17
  npm install @glassly/miniapp
18
18
  ```
19
19
 
20
- `react` is an optional peer dependency — only required if you use `@glassly/miniapp/react`.
20
+ `react` is an optional peer dependency, required only if you use `@glassly/miniapp/react`.
21
21
 
22
22
  ## Entry points
23
23
 
24
24
  | Specifier | Contents |
25
25
  | ---------------------------- | ------------------------------------------------------------------------------------------------- |
26
26
  | `@glassly/miniapp` | `MiniappSession`, `NotConnectedError`, transports, manifest-types re-exports, module type exports |
27
- | `@glassly/miniapp/background` | `MiniappSession`, `registerMiniapp` — the always-on session layer (see two-layer note below) |
27
+ | `@glassly/miniapp/background` | `MiniappSession`, `registerMiniapp`, the always-on session layer (see two-layer note below) |
28
28
  | `@glassly/miniapp/ui` | The WebView-side `glassly` channel bridge + React adapters (`<MiniappProvider>`, `<MiniappHeader>`, hooks) |
29
29
  | `@glassly/miniapp/react` | React hooks + `<MiniappProvider>` + `<MiniappHeader>` (also re-exported from `/ui`) |
30
30
  | `@glassly/miniapp/protocol` | `MiniappRequestType`, `MiniappResponseType`, `MiniappStreamType`, `MiniappErrorCode` |
31
+ | `@glassly/miniapp/hardware` | `HardwareType`, `HardwareRequirementLevel`, `HardwareRequirement` (manifest hardware-requirement types) |
32
+ | `@glassly/miniapp/known-apps` | `KNOWN_APPS`, `knownApp`, `knownAppName`, `appGlyph` (notification app names and card glyphs by bundle id / package name) |
31
33
 
32
34
  > **Two layers.** Miniapps split into an always-on **background** layer that
33
35
  > owns the `MiniappSession` (`@glassly/miniapp/background`, entered via
@@ -47,14 +49,14 @@ import {registerMiniapp} from "@glassly/miniapp/background"
47
49
  // before invoking your handler.
48
50
  registerMiniapp((session) => {
49
51
  // render() replaces the whole frame; stable ids update in place, render([]) clears.
50
- const box = {x: 0, y: 0, w: 576, h: 288} // raw device px — see session.capabilities.display
52
+ const box = {x: 0, y: 0, w: 576, h: 288} // raw device px, see session.capabilities.display
51
53
  session.display.render([{type: "text", id: "hello", box, text: "hello"}])
52
54
  const unsub = session.transcription.on((d) => session.display.render([{type: "text", id: "hello", box, text: d.text}]))
53
55
  // later: unsub()
54
56
  })
55
57
  ```
56
58
 
57
- UI layer (WebView React app — no session here):
59
+ UI layer (WebView React app, no session here):
58
60
 
59
61
  ```tsx
60
62
  import {MiniappProvider, useConnected} from "@glassly/miniapp/ui"
@@ -73,6 +75,34 @@ function App() {
73
75
 
74
76
  ## Session
75
77
 
78
+ ### Shared display primitives
79
+
80
+ Import `TextMeasurer`, `TextWrapper`, display profiles, and pixel-art helpers
81
+ from `@glassly/miniapp/display`. These pure TypeScript primitives share the
82
+ host's implementation and work in either miniapp layer. See the
83
+ [display primitives reference](../../../sdk/docs/display-primitives.md).
84
+
85
+ ### Opt-in display helpers
86
+
87
+ Both the main and `/background` entry points export:
88
+
89
+ - `monoTextRows({id, text, box, fontSize})`: stable-ID row elements for G2 CFW
90
+ fixed-pitch grids. Uses its 2px text inset and rounded 1.2× line pitch.
91
+ Unsupported Unicode falls back per row instead of rasterizing the entire
92
+ grid. Check positioned-text and element budgets first; this does not make
93
+ stock firmware support dense mono grids. Submit all rows in each scene,
94
+ including blank rows, so deletions clear correctly.
95
+ - `LatestRenderScheduler(() => intervalMs)`: `request(async () => { ... })`
96
+ runs one callback at a time, keeping only the latest pending callback.
97
+ Construct the scene inside the callback and await `display.render()`;
98
+ report failures there. Call `clearPending()` when changing views and
99
+ `dispose()` on shutdown. It cannot cancel native work already submitted,
100
+ does not change global FPS/transport settings, and must never be used to
101
+ discard input bytes or other non-replaceable events.
102
+
103
+ These are optional producer-side helpers, not an automatic native Unicode
104
+ renderer change or BLE message pipelining.
105
+
76
106
  `MiniappSession` is the only object you construct. It owns the transport, the request/response correlation map, the pre-ready outbound queue, the keepalive PONG, and the cached visibility / capabilities / color-scheme / permissions state.
77
107
 
78
108
  ### Lifecycle
@@ -86,9 +116,9 @@ session.disconnect()
86
116
 
87
117
  `MiniappSessionOptions`:
88
118
 
89
- - `packageName?: string` — overrides auto-detection from `window.Glassly`
90
- - `connectTimeoutMs?: number` — defaults to 10s
91
- - transport-selection options from `createTransport` (`mode`, `transport`, `localSocket`)
119
+ - `packageName?: string`: overrides auto-detection from `window.Glassly`
120
+ - `connectTimeoutMs?: number`: defaults to 10s
121
+ - transport-selection options from `createTransport` (`transport`, `localSocketUrl`)
92
122
 
93
123
  ### Lifecycle events
94
124
 
@@ -99,52 +129,81 @@ session.off("ready", handler)
99
129
 
100
130
  | Event | Signature |
101
131
  | -------------- | --------------------------------------------- |
102
- | `ready` | `() => void` — fires after CONNECT_ACK |
103
- | `disconnect` | `(reason: string) => void` |
104
- | `error` | `(err: Error) => void` |
105
- | `visibility` | `("foreground" \| "background") => void` |
106
- | `capabilities` | `(caps: GlassesCapabilities \| null) => void` |
107
- | `colorScheme` | `("light" \| "dark") => void` |
108
- | `permissions` | `(perms: PermissionRecord) => void` |
109
- | `speakerState` | `(event: SpeakerStateEvent) => void` |
110
-
111
- Convenience wrappers: `onVisibilityChange`, `onCapabilitiesChange`, `onColorSchemeChange`. Each `on(...)` call also returns an unsubscribe function.
132
+ | `ready` | `() => void`, fires after CONNECT_ACK |
133
+ | `beforeDisconnect` | `(reason: string) => void`, last chance to send one final one-shot |
134
+ | `disconnect` | `(reason: string) => void` |
135
+ | `error` | `(err: Error) => void` |
136
+ | `visibility` | `("foreground" \| "background") => void` |
137
+ | `capabilities` | `(caps: GlassesCapabilities \| null) => void` |
138
+ | `preferences` | `(prefs: MiniappPreferences) => void` |
139
+ | `colorScheme` | `("light" \| "dark") => void` |
140
+ | `permissions` | `(perms: PermissionRecord) => void` |
141
+ | `speakerState` | `(event: SpeakerStateEvent) => void` |
142
+ | `auth` | `(auth: MiniappAuthState) => void` |
143
+
144
+ Convenience wrappers: `onVisibilityChange`, `onCapabilitiesChange`, `onPreferencesChange`, `onColorSchemeChange`, `onBeforeDisconnect`. Each `on(...)` call also returns an unsubscribe function.
112
145
 
113
146
  ### Cached state
114
147
 
115
- `session.userId`, `session.packageName`, `session.capabilities`, `session.visibility`, `session.colorScheme`, `session.ready` — populated from `CONNECT_ACK` and kept in sync via the lifecycle events above.
148
+ `session.userId`, `session.packageName`, `session.capabilities`, `session.preferences`, `session.visibility`, `session.colorScheme`, `session.launchSource`, `session.ready` are populated from `CONNECT_ACK` and kept in sync via the lifecycle events above.
149
+
150
+ `session.preferences` is `{unitSystem: "metric" | "imperial", twelveHourTime: boolean}`, mirroring the host's Settings > Appearance toggles. Follow it for distances, temperatures and clock formatting unless your miniapp offers its own override. It is `null` on runtimes that predate the preferences surface, so fall back rather than assuming a value.
151
+
152
+ `session.launchSource` is `"phone"` or `"glasses"` — where the user started this session from — and `null` until `CONNECT_ACK` arrives, or on runtimes that don't send it.
153
+
154
+ ```ts
155
+ const twelveHour = session.preferences?.twelveHourTime ?? true
156
+ session.onPreferencesChange((prefs) => rerender(prefs))
157
+
158
+ if (session.launchSource === "glasses") openGlassesFirstView()
159
+ ```
116
160
 
117
161
  ## Modules
118
162
 
119
163
  All event subscribers return an `UnsubscribeFn`. Subscriptions are ref-counted: the SDK sends `SUBSCRIBE` when a stream's active state or routing metadata changes.
120
164
 
121
- | Module | Methods |
122
- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
123
- | `session.display` | `render(elements, opts?)` — scene API: diffed frames, stable-id in-place updates, `render([])` clears |
124
- | `session.speaker` | `play({audioUrl})`, `speak(text, options?)`, `createStream({sampleRate?, volume?})` for bounded 16-bit PCM output, `stop()`, `onStateChange(handler)` |
125
- | `session.mic` | `onAudioChunk(handler)`, `onVoiceActivity(handler)`, `stop()`, `hasPermission` |
126
- | `session.transcription` | `on(handler, {forceLocal?})`, `forLanguage(lang \| [langs], handler, {forceLocal?})`, `configure({languageHints, vocabulary, diarization})`, `stop()`, `hasPermission` |
127
- | `session.translation` | `forLanguagePair(from, to, handler)`, `stop()`, `hasPermission` |
128
- | `session.input` | `onButtonPress(handler)`, `onTouch(handler \| gesture, handler \| gestures, handler)` |
129
- | `session.location` | `onUpdate(handler)`, `hasPermission` |
130
- | `session.imu` | `onHeadPosition(handler)` |
131
- | `session.glasses` | `onBattery(handler)`, `onConnection(handler)` |
132
- | `session.phone.notifications` | `on(handler)`, `onDismissed(handler)`, `stop()`, `hasPermission` |
133
- | `session.phone.calendar` | `listEvents({startsAt, endsAt, limit?})`, `hasPermission` |
134
- | `session.phone` | `onBattery(handler)` |
135
- | `session.system` | `share(opts)`, `openUrl(url)`, `copyToClipboard(text)`, `download(opts)` |
136
- | `session.camera` | `takePhoto({size?, mode?, transferMethod?, compress?, sound?, saveToGallery?, zsl?, mfnr?, timeoutMs?, ...})`, `setFov({fov, roiPosition?} \| {preset})`, `hasPermission` |
137
- | `session.led` | `turnOn({color?, ontime?, offtime?, count?})`, `turnOff()`, `blink(color, ontime, offtime, count)`, `solid(color, duration)` — resolve after the glasses acknowledge the RGB command |
138
- | `session.permissions` | `has(type)`, `getAll()`, `onUpdate(handler)`, `onPermissionError(handler)` |
139
- | `session.storage` | `get(key)`, `set(key, value)`, `delete(key)`, `list()` — strings only, scoped to `(userId, packageName)` |
140
- | `session.stream` | `startUnmanaged({streamUrl, video?, audio?, sound?})`, `startManaged({restreamDestinations?, video?, audio?, sound?, ingest?})`, `stop(streamId?)` — stream video input fields are `width`, `height`, `bitrate`, and `fps`; resolved status reports effective frame rate as `resolvedConfig.video.fps`. Start resolves with `{streamId, status, resolvedConfig?}` after glasses report the publisher is streaming; managed starts also return playback URLs; `ingest` selects `"srt"` for HLS/recording or `"whip"` for low-latency WebRTC; stop is idempotent for an already-stopped stream |
141
- | `session.dashboard` | `setContent(mode, content)` — **noop in v1**, prints a one-time `console.warn`. Cloud DashboardManager owns rendering. |
142
-
143
- `session.events` is **internal**. It exposes `subscribe(rawStreamType, handler)` only as a forward-compat escape hatch for new event types not yet wrapped on a domain module — prefer the typed module surface.
165
+ | Module | Methods |
166
+ | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
167
+ | `session.auth` | `current`, `userId`, `oemId`, `getToken(opts?)`, `getAuthHeader(opts?)`, `fetch(input, init?)`, `onUpdate(handler)`; miniapp-scoped backend auth, never a Core or runtime token |
168
+ | `session.mirror` | `getCurrent()`, `onUpdate(handler)`, `hasPermission`; DISPLAY_MIRROR-gated global glasses preview; see [mirror reference](../../../sdk/docs/mirror.md) |
169
+ | `session.display` | `showView(view)`, `onViewChange(handler)` for overlay miniapps; `render(elements, opts?)`, scene API: diffed frames, stable-id in-place updates, `render([])` clears; `sendNativeNavInfo`/`sendNativeNavMiniMap`/`sendNativeNavOverviewMap` feed firmware-rendered navigation on devices with `hasNativeNavigation` |
170
+ | `session.speaker` | `state` (`"idle" \| "loading" \| "playing" \| "stopped" \| "error"`), `isPlaying` (true iff `state === "playing"`), `play({audioUrl})`, `speak(text, options?)`, `createStream({sampleRate?, volume?})` for bounded 16-bit PCM output, `stop()`, `onStateChange(handler)` |
171
+ | `session.camera` | `takePhoto({size?, mode?, transferMethod?, compress?, sound?, saveToGallery?, zsl?, mfnr?, timeoutMs?, ...})`, `setFov({fov, roiPosition?} \| {preset})`, `warmUp(opts?)`, `startVideoRecording(opts?)`, `stopVideoRecording(recordingId, opts?)`, `hasPermission` |
172
+ | `session.cloud` | `status`, `connected`, `isConnected()`, `onStatusChanged(handler)`; read-only view of the phone-owned cloud client's connection/audio-transport status |
173
+ | `session.dashboard` | `setContent(mode, content)` (noop in v1, prints a one-time `console.warn`); `showNativeDashboard()` brings the glasses' OS idle screen to the foreground |
174
+ | `session.glasses` | `onBattery(handler)`, `onConnection(handler)`, `onWifi(handler)`, `requestWifiSetup(reason?)`, `setWifiAdbState(enabled)` (SYSTEM-only) |
175
+ | `session.imu` | `onHeadPosition(handler)`, `onAccel(handler)`, `setEnabled(enabled)` |
176
+ | `session.compass` | `onUpdate(handler)`, `onCalibration(handler)`, `start(options?)`, `stop()`; glasses heading in degrees, auto-starts on G2 custom firmware, stock nav mode only |
177
+ | `session.lightSensor` | `onUpdate(handler)`, `query()`, `start(options?)`, `stop()`; G2 custom firmware ambient light, one controlling miniapp |
178
+ | `session.input` | `setClaimedGestures(gestures, {scope?})`, `onClaimChange(handler)`, `onButtonPress(handler)`, `onTouch(handler \| gesture, handler \| gestures, handler)` |
179
+ | `session.ai` | `complete(request)` (tier-based LLM completion, tool loop support), `generate(request, opts?)` (agentic visual generation), `prompt(text, opts?)` (single-shot text convenience), `hasPermission` |
180
+ | `session.keys` | `get(provider)`, read a user-supplied provider API key (anthropic/gemini/openai/elevenlabs/mapbox), `hasPermission` |
181
+ | `session.led` | `turnOn({color?, ontime?, offtime?, count?})`, `turnOff()`, `blink(color, ontime, offtime, count)`, `solid(color, duration)`; resolve after the glasses acknowledge the RGB command |
182
+ | `session.location` | `onUpdate(handler)`, `getOnce()`, `hasPermission` |
183
+ | `session.memory` | `appendLine(input)`, `addNote(text, source?, at?)`, `removeEntry(id)`, `removeScope(scope, at)`, `sessions()`, `query(q?)`, `search(q?)`, `window(sinceMs, untilMs?)`, `exportText(scope, at?)`, `addSummary(summary)`, `summaries()`, `pendingSummaryHour(nowMs?)`, `clear()`, `hasPermission`; the user's shared phone-local memory timeline |
184
+ | `session.speakers` | `resolveName(id)`, `hasPermission`; resolve an enrolled-speaker id to its display name |
185
+ | `session.mic` | `onAudioChunk(handler)`, `onVoiceActivity(handler)`, `setVoiceActivityDetectionEnabled(enabled)`, `setLoudnessGateEnabled(enabled)`, `stop()`, `hasPermission` |
186
+ | `session.navigation` | `start(opts)`, `stop()`, `onUpdate(handler)`, `onRoute(handler)`, `getState()`, `computeRoute(opts)`, `reverseGeocodeRoad(...)`, `placeAutocomplete(opts)`, `placeDetails(opts)`, `onPivot(handler)`, `getPivots()`, `getActivePivot()`, `getUpcomingPivot()`, `requestPermission()`, `hasPermission`; Android-only turn-by-turn navigation |
187
+ | `session.permissions` | `has(type)`, `getAll()`, `onUpdate(handler)`, `onPermissionError(handler)` |
188
+ | `session.phone.notifications` | `on(handler)`, `onDismissed(handler)`, `stop()`, `hasPermission`, `installedApps()` (SYSTEM-only) |
189
+ | `session.phone.calendar` | `listEvents({startsAt, endsAt, limit?})`, `hasPermission` |
190
+ | `session.phone` | `onBattery(handler)` |
191
+ | `session.settings` | `get(key)`, `getAll(keys?)`, `set(key, value)`, `onChange(handler)`; SYSTEM-only host settings bridge; see [settings reference](../../../sdk/docs/settings.md) |
192
+ | `session.storage` | `get(key)`, `set(key, value)`, `delete(key)`, `keys()`, `has(key)`, `getAll()`, `setMultiple(values)`, `clear()`, `flush()`; strings only, scoped to `(userId, packageName)` |
193
+ | `session.blob` | `set(key, data, opts?)`, `get(key)`, `stat(key)`, `has(key)`, `keys()`, `list()`, `setFromUrl(key, url, opts?)`, `importFile(opts?)`, `createWriteStream(key, opts?)`, `createReadStream(key)`, `bytes(key)`, `usage()`, `delete(key)`, `clear()`, `share(key)`; phone-local binary storage, chunked writes/reads |
194
+ | `session.stream` | `startStream(opts?)`, `stop(streamId?)`; managed (default, returns `hlsUrl`/`dashUrl`/`webrtcUrl` and optional `destinations` fan-out) or `direct` (publish straight to your own ingest URL, no playback URLs); `opts.ingest` selects `"srt"` (default), `"whip"`, or `"rtmp"`; video config fields are `width`, `height`, `bitrate`, `fps` |
195
+ | `session.system` | `share(opts)`, `openUrl(url)`, `copyToClipboard(text)`, `download(opts)`, `scanQr(opts?)`, `exit()`, `getDisplayDiagnostics()` |
196
+ | `session.transcription` | `on(handler, {forceLocal?})`, `forLanguage(lang \| [langs], handler, {forceLocal?})`, `configure({languageHints, vocabulary, diarization})`, `stop()`, `hasPermission` |
197
+ | `session.translation` | `on(handler)`, `to(target \| [targets], handler)`, `fromTo(source, target \| [targets], handler)`, `stop()`, `hasPermission` |
198
+ | `session.ui` | `isOpen()`, `onOpen(handler)`, `onClose(handler)`, `send(channel, payload)`, `on(channel, handler)`, `handle(channel, handler)`; background-side message bus to the bound WebView; see [Wire protocol](#wire-protocol) and [`sdk/docs/two-layer.md`](../../../sdk/docs/two-layer.md) |
199
+ | `session.miniapps` | `list(opts?)`, `start(packageName)`, `stop(packageName)`, `stopSelf()`; inter-miniapp lifecycle and discovery, SYSTEM-only except `stopSelf()` |
200
+ | `session.actions` | `list()`, `invoke(packageName, actionId, params?, opts?)`, `handle(actionId, handler)`; inter-miniapp action layer (MCP-tool-shaped); `list`/`invoke` open to all, gated per-action by the target's declared `visibility` |
201
+
202
+ `session.events` is internal. It exposes `subscribe(rawStreamType, handler)` only as a forward-compat escape hatch for new event types not yet wrapped on a domain module; prefer the typed module surface.
144
203
 
145
204
  ### Camera FOV
146
205
 
147
- `await session.camera.setFov({fov, roiPosition})` applies a temporary, miniapp-owned FOV/ROI override and resolves with `CameraFovResult` after the ASG client reports the setting was applied following the camera restart cooldown. The host restores the previous live miniapp override—or the persistent 118-degree full-sensor base—when this miniapp closes. `roiPosition` accepts `"center"`, `"bottom"`, or `"top"` and defaults to `"center"`. You can also call `setFov({preset: "narrow" | "standard" | "wide"})`; presets map to 82, 102, and 118 degrees with center ROI. The call requires `CAMERA` in `miniapp.json` and rejects with `MiniappRequestError` if the host or glasses cannot apply it.
206
+ `await session.camera.setFov({fov, roiPosition})` applies a temporary, miniapp-owned FOV/ROI override and resolves with `CameraFovResult` after the ASG client reports the setting was applied following the camera restart cooldown. The host restores the previous live miniapp override, or the persistent 118-degree full-sensor base, when this miniapp closes. `roiPosition` accepts `"center"`, `"bottom"`, or `"top"` and defaults to `"center"`. You can also call `setFov({preset: "narrow" | "standard" | "wide"})`; presets map to 82, 102, and 118 degrees with center ROI. The call requires `CAMERA` in `miniapp.json` and rejects with `MiniappRequestError` if the host or glasses cannot apply it.
148
207
 
149
208
  ### Camera Photos
150
209
 
@@ -154,36 +213,36 @@ Pass `transferMethod: "ble"` to skip direct Wi-Fi upload and always relay the im
154
213
 
155
214
  ### Transcription language convention
156
215
 
157
- Transcription/translation streams use a colon-suffixed wire format: `transcription:en-US`, `translation:en-US:fr-FR`. `session.transcription.on(handler)` subscribes to `transcription:auto` (cloud auto-detects). The detected language is in the payload. A handler on `transcription:auto` receives any `transcription:<lang>` event — wildcard fan-out — so "give me transcripts in whatever language" works without manual wiring. Use `session.transcription.forLanguage(lang | [langs], handler)` to pin specific languages. Pass `{forceLocal: true}` as the final argument to either method to require on-device transcription and suppress cloud results for that subscription. Routing is per listener, so a default listener on the same stream can continue receiving cloud transcription.
216
+ Transcription/translation streams use a colon-suffixed wire format: `transcription:en-US`, `translation:en-US:fr-FR`. `session.transcription.on(handler)` subscribes to `transcription:auto` (cloud auto-detects). The detected language is in the payload. A handler on `transcription:auto` receives any `transcription:<lang>` event, a wildcard fan-out, so "give me transcripts in whatever language" works without manual wiring. Use `session.transcription.forLanguage(lang | [langs], handler)` to pin specific languages. Pass `{forceLocal: true}` as the final argument to either method to require on-device transcription and suppress cloud results for that subscription. Routing is per listener, so a default listener on the same stream can continue receiving cloud transcription.
158
217
 
159
218
  ### Permissions semantics
160
219
 
161
- `session.permissions.has("microphone")` returns whether the manifest declared the permission. Same semantics as cloud SDK v3. **It does NOT report OS-level grant state** — even when `has(...)` returns `true` the user can have denied the OS prompt and your subscriptions will silently receive no events. OS-grant tracking and `request(...)` are deferred and will land additively on the same module.
220
+ `session.permissions.has("microphone")` returns whether the manifest declared the permission. Same semantics as cloud SDK v3. It does *not* report OS-level grant state: even when `has(...)` returns `true` the user can have denied the OS prompt and your subscriptions will silently receive no events. OS-grant tracking and `request(...)` are deferred and will land additively on the same module.
162
221
 
163
- `PermissionType` is the lowercase canonical union: `"location" | "microphone" | "camera" | "notifications" | "calendar"`. Manifest UPPER_CASE names map onto these (`BACKGROUND_LOCATION` → `location`; `READ_NOTIFICATIONS`, `POST_NOTIFICATIONS` → `notifications`).
222
+ `PermissionType` is the lowercase canonical union: `"location" | "microphone" | "camera" | "notifications" | "calendar" | "apiKeys" | "memory" | "ai" | "speakers"`. Manifest UPPER_CASE names map onto these (`BACKGROUND_LOCATION` → `location`; `READ_NOTIFICATIONS`, `POST_NOTIFICATIONS` → `notifications`; `API_KEYS` → `apiKeys`; `MEMORY` → `memory`; `AI` → `ai`; `SPEAKERS` → `speakers`).
164
223
 
165
- ## React bindings — `@glassly/miniapp/ui`
224
+ ## React bindings (`@glassly/miniapp/ui`)
166
225
 
167
226
  These UI-layer hooks run inside the WebView and read host state via the injected
168
- `glassly` channel bridge / `window.Glassly` globals — they do **not** own a
227
+ `glassly` channel bridge / `window.Glassly` globals; they do not own a
169
228
  `MiniappSession` (that lives in the background layer). They are also re-exported
170
229
  from `@glassly/miniapp/react` for backwards-compat.
171
230
 
172
231
  | Hook | Returns |
173
232
  | ------------------------- | ------------------------------------------------------------------------------------------ |
174
- | `useConnected()` | `boolean` — true while the `glassly` bridge is open (`onOpen` / `onClose`) |
175
- | `useCapabilities()` | Glasses capability profile — currently always `null` on the UI side (caps arrive over a channel) |
233
+ | `useConnected()` | `boolean`, true while the `glassly` bridge is open (`onOpen` / `onClose`) |
234
+ | `useCapabilities()` | Glasses capability profile; currently always `null` on the UI side (caps arrive over a channel) |
176
235
  | `useColorScheme()` | `"light" \| "dark"` (host theme) |
177
- | `useSafeArea()` | `{insets, capsuleMenu}` — pixel insets + bounding rect of the host's floating capsule menu |
236
+ | `useSafeArea()` | `{insets, capsuleMenu}`, pixel insets and bounding rect of the host's floating capsule menu |
178
237
  | `useCapsuleHeaderStyle()` | Pre-computed CSS for a header row that aligns with the capsule menu |
179
238
  | `useRpc(...)` | Typed request helper over the `glassly` channel bridge |
180
239
 
181
240
  Components:
182
241
 
183
- - `<MiniappProvider>` — root provider. Keeps `<html class="dark">` in sync with the host color scheme during render (no FOUC).
184
- - `<MiniappHeader title="…" left={…} right={…} onBack={…} />` — drop-in header that respects the safe area and leaves room for the capsule menu.
242
+ - `<MiniappProvider>`: root provider. Keeps `<html class="dark">` in sync with the host color scheme during render (no FOUC).
243
+ - `<MiniappHeader title="…" left={…} right={…} onBack={…} />`: drop-in header that respects the safe area and leaves room for the capsule menu.
185
244
 
186
- ## Manifest — `miniapp.json`
245
+ ## Manifest (`miniapp.json`)
187
246
 
188
247
  ```json
189
248
  {
@@ -200,8 +259,8 @@ Components:
200
259
  }
201
260
  ```
202
261
 
203
- - `permissions[].type` ∈ `MICROPHONE | CAMERA | CALENDAR | LOCATION | BACKGROUND_LOCATION | READ_NOTIFICATIONS | POST_NOTIFICATIONS`
204
- - `hardwareRequirements[].type` ∈ `CAMERA | DISPLAY | MICROPHONE | SPEAKER | IMU | BUTTON | LIGHT | WIFI`, `level` ∈ `REQUIRED | OPTIONAL`
262
+ - `permissions[].type` ∈ `MICROPHONE | CAMERA | CALENDAR | LOCATION | BACKGROUND_LOCATION | READ_NOTIFICATIONS | POST_NOTIFICATIONS | API_KEYS | MEMORY | AI | SPEAKERS`
263
+ - `hardwareRequirements[].type` ∈ `CAMERA | DISPLAY | MICROPHONE | SPEAKER | IMU | BUTTON | LIGHT | WIFI`, `level` ∈ `REQUIRED | OPTIONAL`. (`EXIST` also exists on the wire but the phone injects it at runtime; don't declare it.)
205
264
 
206
265
  The CLI validates the manifest on every `dev`, `release`, and `pack`. Run `glassly-miniapp schema print` for the canonical JSON Schema.
207
266
 
@@ -221,9 +280,9 @@ The author-facing CLI lives in a sibling package: **[`@glassly/miniapp-cli`](../
221
280
 
222
281
  See [the CLI README](../../../sdk/miniapp-cli/README.md) for flags, semantics, and the `miniapp://` URL schemes the QR codes encode.
223
282
 
224
- ## Host-injected globals — `window.Glassly`
283
+ ## Host-injected globals (`window.Glassly`)
225
284
 
226
- The Glassly app injects this before content loads. Authors generally use the React hooks instead, but the raw shape is:
285
+ The Glassly App injects this before content loads. Authors generally use the React hooks instead, but the raw shape is:
227
286
 
228
287
  ```ts
229
288
  {
@@ -235,37 +294,41 @@ The Glassly app injects this before content loads. Authors generally use the Rea
235
294
  }
236
295
  ```
237
296
 
238
- Use `getGlasslyGlobals()` (exported from the package) to read it with the right TypeScript types.
297
+ Use `getHostGlobals()` (exported from the package) to read it with the right TypeScript types.
239
298
 
240
299
  ## Transports
241
300
 
242
- Auto-selected by `createTransport(options)`:
301
+ Auto-selected by `createTransport(options)`, in this order:
302
+
303
+ - `DispatchTransport`: the production path. Used when running in the per-miniapp background JSContext (no DOM, but the native bridge installs `__dispatch` on `globalThis`). Rides `__dispatch("__bridge", "send", ...)` outbound and the polyfill's `__deliverBridgeRaw` inbound.
304
+ - `PostMessageTransport`: used inside the Glassly WebView (`window.ReactNativeWebView` defined). `window.ReactNativeWebView.postMessage` outbound, `window` `message` listener inbound.
305
+ - `MockTransport`: explicit opt-in via `?glassly=mock` or `localStorage.MINIAPP_MOCK=1`. Synthesizes a CONNECT_ACK and REQUEST_RESULT replies so the SDK doesn't hang in a plain browser tab.
306
+ - `LocalSocketTransport`: fallback for laptop browsers with `WebSocket` available. Default endpoint `ws://127.0.0.1:8765`. Races open() against a 500ms timeout and falls back to `MockTransport` if nothing answers.
243
307
 
244
- - **`PostMessageTransport`** — used inside the Glassly WebView. `window.ReactNativeWebView.postMessage` outbound, `window` `message` listener inbound.
245
- - **`LocalSocketTransport`** — fallback for laptop browsers. Default endpoint `ws://127.0.0.1:8765`. The in-laptop-browser dev story is currently broken; see the overview doc for status.
308
+ `createTransport(options)` takes `{transport?, localSocketUrl?}`. Pass `transport` to force a specific instance (tests), or `localSocketUrl` to override the LocalSocket fallback's URL.
246
309
 
247
- Both are exported for advanced uses (forced transport, tests). `MockTransport` is also exported for unit tests.
310
+ All four are exported for advanced uses (forced transport, tests).
248
311
 
249
312
  ## Wire protocol
250
313
 
251
314
  Every message is a `{payload, requestId?}` envelope, JSON over the chosen transport. `requestId` correlates request ↔ response for methods that return a value. Constants live in `@glassly/miniapp/protocol`:
252
315
 
253
- - `MiniappRequestType` — `CONNECT`, `SUBSCRIBE`, etc.
254
- - `MiniappResponseType` — `CONNECT_ACK`, `EVENT`, `REQUEST_RESULT`, `PERMISSIONS_UPDATE`, …
255
- - `MiniappStreamType` — typed names for stream identifiers
256
- - `MiniappErrorCode` — `NOT_CONNECTED`, `PERMISSION_NOT_DECLARED`, …
316
+ - `MiniappRequestType`: `CONNECT`, `SUBSCRIBE`, etc.
317
+ - `MiniappResponseType`: `CONNECT_ACK`, `EVENT`, `REQUEST_RESULT`, `PERMISSIONS_UPDATE`, …
318
+ - `MiniappStreamType`: typed names for stream identifiers
319
+ - `MiniappErrorCode`: `NOT_CONNECTED`, `PERMISSION_NOT_DECLARED`, …
257
320
 
258
321
  Full enum listings in [`src/protocol.ts`](./src/protocol.ts).
259
322
 
260
323
  ## Controller pattern (recommended)
261
324
 
262
- Smart-glasses miniapps are **always-on services**. The webview is a UI on top of a continuously-running session. If you tie subscriptions to React component lifecycle, closing or navigating away from a page also stops the glasses behavior — wrong shape for glasses.
325
+ Smart-glasses miniapps are always-on services. The webview is a UI on top of a continuously-running session. If you tie subscriptions to React component lifecycle, closing or navigating away from a page also stops the glasses behavior, the wrong shape for glasses.
263
326
 
264
- **Rule:** user-facing glasses logic lives in a session-scoped controller, instantiated once at module init. React pages read controller-driven state via a store (Zustand recommended) and call imperative methods on the controller for user-triggered actions. They do **not** subscribe to `session.*` directly.
327
+ User-facing glasses logic lives in a session-scoped controller, instantiated once in the background layer's `registerMiniapp` handler. The controller owns every `session.*` subscription and pushes state to the WebView over `session.ui.send` channels; UI pages read that pushed state (e.g. with a small `useChannel`-style hook wrapping `glassly.on`) and call back into the controller for user-triggered actions via `session.ui.handle`/`glassly.request`. Pages do not construct or subscribe to a `session.*` module directly. The background JSContext and the WebView are separate runtimes, so there is no shared in-memory store between them.
265
328
 
266
- See [`miniapps/example-miniapp/src/background/controllers/GlassesController.ts`](../../../miniapps/example-miniapp/src/background/controllers/GlassesController.ts) for a worked reference.
329
+ See [`miniapps/example-miniapp/src/background/controllers/GlassesController.ts`](../../../miniapps/example-miniapp/src/background/controllers/GlassesController.ts) and [`miniapps/example-miniapp/src/ui/hooks/useChannel.ts`](../../../miniapps/example-miniapp/src/ui/hooks/useChannel.ts) for a worked reference.
267
330
 
268
- **Tester pages exception:** `pages/tester/*` are diagnostic surfaces — by design they inline-subscribe to `session.*` and tear down on unmount. This is the only place where that pattern is acceptable.
331
+ Tester pages exception: `pages/tester/*` are diagnostic surfaces; by design they inline-subscribe to `session.*` and tear down on unmount. This is the only place where that pattern is acceptable.
269
332
 
270
333
  ## File map
271
334
 
@@ -273,3 +336,85 @@ See [`miniapps/example-miniapp/src/background/controllers/GlassesController.ts`]
273
336
  - CLI: [`../miniapp-cli/src/`](../../../sdk/miniapp-cli/src/)
274
337
  - Scaffolder: [`../create-miniapp/`](../../../sdk/create-miniapp/)
275
338
  - Reference miniapp: [`miniapps/example-miniapp/`](../../../miniapps/example-miniapp/)
339
+
340
+ ## SVG paths and rotation
341
+
342
+ G2 Glassly CFW revision 21 and Simulated Glasses support filled SVG paths and
343
+ clockwise rotation of geometric elements. Check
344
+ `session.capabilities.display.shapes.includes("svg")` and
345
+ `session.capabilities.display.rotation` before using them.
346
+
347
+ ```ts
348
+ const heart = {
349
+ type: "svg" as const,
350
+ id: "heart",
351
+ box: {x: 60, y: 60, w: 120, h: 120},
352
+ d: "M50 90 C-10 45 0 0 30 10 Q45 10 50 25 Q55 10 70 10 C100 0 110 45 50 90 Z",
353
+ scale: 1,
354
+ rotation: 0,
355
+ pivot: {x: 120, y: 120},
356
+ }
357
+ await session.display.render([heart])
358
+ // Keep the id and d: the firmware reuses the path while moving and turning it.
359
+ await session.display.render([{...heart, box: {...heart.box, x: 120}, scale: 1.5,
360
+ rotation: 720, transition: {durationMs: 2000, easing: "ease-in-out"}}])
361
+ ```
362
+
363
+ `d` accepts absolute/relative `M L H V Q C S T Z` and implicit repetitions.
364
+ Every contour must close with `Z`; `fillRule` is `"nonzero"` (default) or
365
+ `"evenodd"`. This is SVG path data, not an XML document: arcs, strokes, gradients,
366
+ CSS and SVG transform attributes must be converted before calling `render`.
367
+
368
+ Path coordinates are local to `box.x/y`; `scale` uniformly scales them (0–8,
369
+ quantized to 1/256). `box.w/h` describe layout bounds and do not stretch the path
370
+ or clip its curves. Source coordinates must fit signed Q4 (−2048 to 2047.9375).
371
+
372
+ ## Depth and cards on top
373
+
374
+ Every element takes an optional `depth` (−16..16 canvas px): a stereo disparity
375
+ drawn on devices whose `session.capabilities.display.depth` is true, flat
376
+ everywhere else. Positive floats the element in front of the frame. Elements
377
+ still paint in array order, so a card that should sit on top of running content
378
+ goes last in the array and at a positive depth. A `transition` animates a move
379
+ or a depth change. This example moves a card within a G2-sized canvas:
380
+
381
+ ```ts
382
+ import type {RenderElement} from "@glassly/miniapp/background"
383
+
384
+ const content: RenderElement[] = [] // the rest of your scene
385
+ const card = (x: number): RenderElement[] => [
386
+ {type: "rect" as const, id: "card", box: {x, y: 70, w: 300, h: 150},
387
+ style: {fill: true, color: 2, radius: 10}, depth: 8, transition: {durationMs: 350, easing: "ease-out"}},
388
+ {type: "text" as const, id: "card-title", box: {x: x + 16, y: 82, w: 268, h: 30}, text: "Incoming call",
389
+ style: {font: "builtin"}, depth: 8, transition: {durationMs: 350, easing: "ease-out"}},
390
+ ]
391
+ await session.display.render([...content, ...card(20)]) // initial position
392
+ await session.display.render([...content, ...card(252)]) // glides in, 8 px in front
393
+ ```
394
+
395
+ The example miniapp's **Tester → cards + depth** suite exercises static depth,
396
+ depth in motion, slide in/out, stacks and cache reopen.
397
+
398
+ The host rejects paths exceeding 8,192 command bytes, 1,024 commands or 512
399
+ flattened edges, and caps the scene at 4,096 path edges. Invalid/unsupported
400
+ elements are reported in `RenderResult.dropped`.
401
+
402
+ `rotation` uses unwrapped degrees (±36,000): 720 means two clockwise turns.
403
+ `pivot` is a fixed point in canvas coordinates; it defaults to the target box's
404
+ center. Rotation applies to rectangles, circles, lines, polygons, Béziers, arcs,
405
+ pies and SVGs. Text and images do not rotate. Rotation duration is capped at
406
+ 65,535 ms; existing geometry tweens retain their 255-frame limit (about 8.4 s).
407
+ Geometry and rotation run independently. Creating/replacing a path snaps;
408
+ stable paths tween position, scale, color and rotation. Contour morphing is not
409
+ implemented. The simulated display previews these transforms and transitions.
410
+
411
+ ### Glasses compass and light sensor
412
+
413
+ `session.compass` is the one glasses heading API: subscribing runs the sensor
414
+ (G2 custom firmware) or listens for the stock nav-mode heading; `start(options?)`
415
+ / `stop()` only set this miniapp's sampling override and the phone serves the
416
+ tightest request across miniapps. The phone's own compass is
417
+ `session.phone.heading`. `session.lightSensor` exposes `onUpdate`, `query`,
418
+ `start(options?)`, and `stop` with one controlling miniapp. See
419
+ [imu.md](../../../sdk/docs/imu.md) and [lightsensor.md](../../../sdk/docs/lightsensor.md)
420
+ for units, options, ownership, and the example miniapp testers.
@@ -16,8 +16,10 @@
16
16
  */
17
17
  export { MiniappSession, type MiniappSessionOptions } from "../session";
18
18
  export { registerMiniapp, type MiniappInitHandler, type TypedMiniappSession } from "./register";
19
- export type { TranscriptionData, TranslationData, ButtonPressData, AudioChunkData, VadData, BatteryData, ConnectionData, WifiData, HeadPositionData, AccelData, LocationData, PhoneNotificationData, NotificationDismissedData, HeadingData, TouchData, UnsubscribeFn, } from "../modules/events";
20
- export type { CalendarEvent, CalendarListOptions, CalendarListResult } from "../modules/phone";
19
+ export { monoTextRows } from "../modules/mono-text-rows";
20
+ export { LatestRenderScheduler } from "../modules/latest-render-scheduler";
21
+ export type { TranscriptionData, TranslationData, ButtonPressData, AudioChunkData, VadData, BatteryData, ConnectionData, WifiData, HeadPositionData, AccelData, LocationData, PhoneNotificationData, NotificationDismissedData, HeadingData, TouchData, KeyboardEventData, UnsubscribeFn, } from "../modules/events";
22
+ export type { CalendarEvent, CalendarListOptions, CalendarListResult, NotificationAppInfo } from "../modules/phone";
21
23
  export { MiniappRequestType, MiniappResponseType, MiniappStreamType, MiniappErrorCode } from "../protocol";
22
24
  export { MiniappValidationError, SUPPORTED_LANGUAGE_HINTS, SUPPORTED_TRANSCRIPTION_LANGUAGES, isTranscriptionLanguage, } from "../modules/languages";
23
25
  export type { LanguageHint, TranscriptionLanguage } from "../modules/languages";
@@ -27,9 +29,8 @@ export type { CameraFovPreset, CameraFovRequest, CameraFovResult, CameraModule,
27
29
  export type { CloudClientAudioTransport, CloudClientConnectionStatus, CloudClientStatus, CloudModule, } from "../modules/cloud";
28
30
  export type { DashboardAPI } from "../modules/dashboard";
29
31
  export type { GlassesModule } from "../modules/glasses";
30
- export type { HeadingModule } from "../modules/heading";
31
32
  export type { ImuModule } from "../modules/imu";
32
- export type { InputModule } from "../modules/input";
33
+ export type { InputModule, GestureClaimChange } from "../modules/input";
33
34
  export type { LedModule } from "../modules/led";
34
35
  export type { LocationModule } from "../modules/location";
35
36
  export type { MemoryModule, MemoryEntry, MemoryEntryKind, MemoryNoteSource, MemoryQuery, MemorySession, MemorySummary, } from "../modules/memory";
@@ -37,7 +38,8 @@ export type { SpeakersModule } from "../modules/speakers";
37
38
  export type { MicModule } from "../modules/mic";
38
39
  export type { NavigationModule } from "../modules/navigation";
39
40
  export type { PermissionsModule } from "../modules/permissions";
40
- export type { PhoneModule } from "../modules/phone";
41
+ export type { PhoneModule, PhoneHeadingModule } from "../modules/phone";
42
+ export type { SettingsModule, SettingsChange } from "../modules/settings";
41
43
  export type { SimpleStorage } from "../modules/storage";
42
44
  export { BlobModule, BlobWriter, BlobReader, BLOB_WRITE_CHUNK_BYTES, BLOB_READ_ALL_MAX_BYTES } from "../modules/blob";
43
45
  export type { BlobMeta, BlobSetOptions, BlobSetFromUrlOptions, BlobImportOptions } from "../modules/blob";
@@ -51,14 +53,18 @@ export type { UIModule, UIChannelHandler, UIUnsubscribe } from "../modules/ui";
51
53
  export type { Rpc, IsRpc, RpcReq, RpcRes, RpcRequestOptions, RpcHandlerContext } from "../modules/ui";
52
54
  export { RpcError, RpcTimeoutError } from "../modules/ui";
53
55
  export type { LedColor, LedControlOptions } from "../modules/led";
54
- export type { ViewType, DisplayBreakMode, RenderBox, RenderElement, RenderOptions, RenderRectStyle, RenderResult, RenderTextStyle, } from "../modules/display";
56
+ export type { ViewType, DisplayBreakMode, RenderBox, RenderElement, RenderOptions, DisplayViewChange, DisplayViewChangeReason, ShowViewResult, RenderRectStyle, RenderResult, RenderTextStyle, } from "../modules/display";
55
57
  export type { DashboardMode, ShowNativeDashboardResult } from "../modules/dashboard";
56
58
  export type { PlayAudioOptions, SpeakOptions, SpeakResult, SpeakerState, SpeakerStateEvent } from "../modules/speaker";
57
- export type { ShareOptions, ShareResult, DownloadOptions, DownloadResult, ScanQrOptions, ScanQrResult, } from "../modules/system";
59
+ export type { ShareOptions, ShareResult, DownloadOptions, DownloadResult, ScanQrOptions, ScanQrResult, DisplayDiagnostic, DisplayDiagnosticsResult, } from "../modules/system";
58
60
  export type { TranscriptionConfig, TranscriptionOptions } from "../modules/transcription";
59
61
  export type { PermissionErrorEvent } from "../modules/permissions";
60
- export type { AuthUpdatePayload, MiniappVisibility, PermissionType, PermissionRecord, GlassesCapabilities, ConnectAckPayload, MiniappAuthState, MiniappRequestError, } from "../session";
62
+ export type { AuthUpdatePayload, MiniappLaunchSource, MiniappVisibility, PermissionType, PermissionRecord, GlassesCapabilities, ConnectAckPayload, MiniappAuthState, MiniappRequestError, } from "../session";
61
63
  export type { AuthFetchOptions, AuthModule } from "../modules/auth";
62
64
  export type { MiniappColorScheme } from "../globals";
63
65
  export type { LatLng, TravelMode, ManeuverKind, RouteAvoidances, NavManeuver, NavOffRoute, NavRerouting, NavArrived, NavError, NavCancelled, NavUpdate, NavRoute, PivotOptions, Pivot, PivotEvent, NavStep, NavigationDev, StartNavigationOptions, NavState, NavPermissionResult, ComputeRouteOptions, ComputedRouteStep, ComputedRoute, ComputeRouteResult, } from "../modules/navigation";
66
+ export type { LightSensorModule, LightSensorOptions, LightSensorData } from "../modules/lightSensor";
67
+ export type { CompassModule, CompassOptions, CompassData, CompassDiagnostics, CompassCalibrationData, } from "../modules/compass";
68
+ export type { MirrorModule } from "../modules/mirror";
69
+ export type { MirrorSnapshot, MirrorContent, MirrorElement } from "../mirror/types";
64
70
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/background/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/background/index.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,10 @@
16
16
  */
17
17
  export { MiniappSession } from "../session";
18
18
  export { registerMiniapp } from "./register";
19
+ // Event / data type re-exports — these are payload shapes a miniapp's
20
+ // background-side handlers consume from session.transcription.on, etc.
21
+ export { monoTextRows } from "../modules/mono-text-rows";
22
+ export { LatestRenderScheduler } from "../modules/latest-render-scheduler";
19
23
  // Public envelope + protocol types so authors can write strongly-typed
20
24
  // glue when they need to fall back to session.sendOneShot / sendRequest.
21
25
  export { MiniappRequestType, MiniappResponseType, MiniappStreamType, MiniappErrorCode } from "../protocol";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/background/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,cAAc,EAA6B,MAAM,YAAY,CAAA;AACrE,OAAO,EAAC,eAAe,EAAoD,MAAM,YAAY,CAAA;AAwB7F,uEAAuE;AACvE,yEAAyE;AACzE,OAAO,EAAC,kBAAkB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,gBAAgB,EAAC,MAAM,aAAa,CAAA;AACxG,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,iCAAiC,EACjC,uBAAuB,GACxB,MAAM,sBAAsB,CAAA;AA+C7B,OAAO,EAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,sBAAsB,EAAE,uBAAuB,EAAC,MAAM,iBAAiB,CAAA;AAEnH,OAAO,EAAC,aAAa,EAAE,aAAa,EAAC,MAAM,mBAAmB,CAAA;AAQ9D,OAAO,EAAC,QAAQ,EAAE,eAAe,EAAC,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/background/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,cAAc,EAA6B,MAAM,YAAY,CAAA;AACrE,OAAO,EAAC,eAAe,EAAoD,MAAM,YAAY,CAAA;AAE7F,sEAAsE;AACtE,uEAAuE;AACvE,OAAO,EAAC,YAAY,EAAC,MAAM,2BAA2B,CAAA;AACtD,OAAO,EAAC,qBAAqB,EAAC,MAAM,oCAAoC,CAAA;AAuBxE,uEAAuE;AACvE,yEAAyE;AACzE,OAAO,EAAC,kBAAkB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,gBAAgB,EAAC,MAAM,aAAa,CAAA;AACxG,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,iCAAiC,EACjC,uBAAuB,GACxB,MAAM,sBAAsB,CAAA;AA+C7B,OAAO,EAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,sBAAsB,EAAE,uBAAuB,EAAC,MAAM,iBAAiB,CAAA;AAEnH,OAAO,EAAC,aAAa,EAAE,aAAa,EAAC,MAAM,mBAAmB,CAAA;AAQ9D,OAAO,EAAC,QAAQ,EAAE,eAAe,EAAC,MAAM,eAAe,CAAA"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * registerMiniapp — entry hook for the background JSContext.
3
3
  *
4
- * The GlasslyJS host loads the polyfill (which installs __dispatch /
4
+ * The JSRuntime host loads the polyfill (which installs __dispatch /
5
5
  * __deliver / timers / fetch / etc.), then evaluates the miniapp's
6
6
  * background bundle. After both scripts have evaluated successfully,
7
7
  * the host delivers a single `{kind: "init", sessionId}` envelope.