@glassly/engine 0.3.8-dev.999 → 0.4.0-beta.1019

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 (86) hide show
  1. package/build/engine.d.ts +11 -0
  2. package/build/engine.d.ts.map +1 -1
  3. package/build/facades/ai.d.ts +6 -0
  4. package/build/facades/ai.d.ts.map +1 -1
  5. package/build/facades/ai.js +6 -0
  6. package/build/facades/ai.js.map +1 -1
  7. package/build/facades/glasses.d.ts +9 -1
  8. package/build/facades/glasses.d.ts.map +1 -1
  9. package/build/facades/glasses.js +13 -0
  10. package/build/facades/glasses.js.map +1 -1
  11. package/build/generated/releaseMetadata.js +4 -4
  12. package/build/generated/releaseMetadata.js.map +1 -1
  13. package/build/index.d.ts +1 -1
  14. package/build/index.d.ts.map +1 -1
  15. package/build/index.js.map +1 -1
  16. package/build/services/CloudClientService.d.ts +2 -1
  17. package/build/services/CloudClientService.d.ts.map +1 -1
  18. package/build/services/CloudClientService.js +8 -0
  19. package/build/services/CloudClientService.js.map +1 -1
  20. package/build/services/DeviceEventRouter.d.ts.map +1 -1
  21. package/build/services/DeviceEventRouter.js +1 -0
  22. package/build/services/DeviceEventRouter.js.map +1 -1
  23. package/build/services/GlassesSensorService.js +1 -1
  24. package/build/services/GlassesSensorService.js.map +1 -1
  25. package/build/services/LlmRouting.d.ts +1 -1
  26. package/build/services/LlmRouting.js.map +1 -1
  27. package/build/services/LocalLlmModelManager.d.ts +22 -2
  28. package/build/services/LocalLlmModelManager.d.ts.map +1 -1
  29. package/build/services/LocalLlmModelManager.js +104 -2
  30. package/build/services/LocalLlmModelManager.js.map +1 -1
  31. package/build/services/LocalLlmProvider.d.ts.map +1 -1
  32. package/build/services/LocalLlmProvider.js +11 -0
  33. package/build/services/LocalLlmProvider.js.map +1 -1
  34. package/build/services/LocalMiniappRuntime.d.ts +13 -0
  35. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  36. package/build/services/LocalMiniappRuntime.js +61 -5
  37. package/build/services/LocalMiniappRuntime.js.map +1 -1
  38. package/build/services/NavigationHandlers.js +1 -1
  39. package/build/services/NavigationHandlers.js.map +1 -1
  40. package/build/services/NavigationService.js +6 -6
  41. package/build/services/NavigationService.js.map +1 -1
  42. package/build/services/controllers.d.ts.map +1 -1
  43. package/build/services/controllers.js +1 -0
  44. package/build/services/controllers.js.map +1 -1
  45. package/build/services/neuralBand/HandwritingGate.d.ts +38 -0
  46. package/build/services/neuralBand/HandwritingGate.d.ts.map +1 -0
  47. package/build/services/neuralBand/HandwritingGate.js +89 -0
  48. package/build/services/neuralBand/HandwritingGate.js.map +1 -0
  49. package/build/services/neuralBand/NeuralBandInput.d.ts +12 -1
  50. package/build/services/neuralBand/NeuralBandInput.d.ts.map +1 -1
  51. package/build/services/neuralBand/NeuralBandInput.js +27 -0
  52. package/build/services/neuralBand/NeuralBandInput.js.map +1 -1
  53. package/build/services/neuralBand/NeuralBandSettingsSync.d.ts.map +1 -1
  54. package/build/services/neuralBand/NeuralBandSettingsSync.js +36 -3
  55. package/build/services/neuralBand/NeuralBandSettingsSync.js.map +1 -1
  56. package/build/stores/appVisibility.d.ts.map +1 -1
  57. package/build/stores/appVisibility.js +0 -1
  58. package/build/stores/appVisibility.js.map +1 -1
  59. package/build/stores/settings.d.ts.map +1 -1
  60. package/build/stores/settings.js +18 -0
  61. package/build/stores/settings.js.map +1 -1
  62. package/build/types/enums.d.ts +2 -1
  63. package/build/types/enums.d.ts.map +1 -1
  64. package/build/types/enums.js +1 -0
  65. package/build/types/enums.js.map +1 -1
  66. package/package.json +7 -7
  67. package/src/facades/ai.ts +6 -0
  68. package/src/facades/glasses.ts +17 -0
  69. package/src/generated/releaseMetadata.ts +4 -4
  70. package/src/index.ts +1 -0
  71. package/src/services/CloudClientService.ts +8 -0
  72. package/src/services/DeviceEventRouter.ts +1 -0
  73. package/src/services/GlassesSensorService.ts +1 -1
  74. package/src/services/LlmRouting.ts +1 -1
  75. package/src/services/LocalLlmModelManager.ts +110 -3
  76. package/src/services/LocalLlmProvider.ts +8 -0
  77. package/src/services/LocalMiniappRuntime.ts +66 -5
  78. package/src/services/NavigationHandlers.ts +1 -1
  79. package/src/services/NavigationService.ts +6 -6
  80. package/src/services/controllers.ts +1 -0
  81. package/src/services/neuralBand/HandwritingGate.ts +111 -0
  82. package/src/services/neuralBand/NeuralBandInput.ts +37 -1
  83. package/src/services/neuralBand/NeuralBandSettingsSync.ts +46 -3
  84. package/src/stores/appVisibility.ts +0 -1
  85. package/src/stores/settings.ts +18 -0
  86. package/src/types/enums.ts +1 -0
@@ -6,7 +6,12 @@
6
6
  * latest claim is also kept on its own, since the pairing screen runs before
7
7
  * the band's id reaches JS.
8
8
  */
9
- import type {NeuralBandClaimEvent, NeuralBandHandwritingEvent, NeuralBandPointerEvent} from "@glassly/bluetooth-sdk"
9
+ import type {
10
+ NeuralBandClaimEvent,
11
+ NeuralBandFirmwareEvent,
12
+ NeuralBandHandwritingEvent,
13
+ NeuralBandPointerEvent,
14
+ } from "@glassly/bluetooth-sdk"
10
15
  import {MiniappStreamType} from "@glassly/miniapp"
11
16
 
12
17
  import type {KeyboardEventPayload} from "../GlassesKeyboardInput"
@@ -34,6 +39,8 @@ export interface NeuralBandHandwritingUpdate {
34
39
  status: NeuralBandHandwritingStatus
35
40
  }
36
41
 
42
+ export type NeuralBandFirmwareStatus = Omit<NeuralBandFirmwareEvent, "type" | "controllerId"> & {known: boolean}
43
+
37
44
  export interface NeuralBandInputOptions {
38
45
  forward?: (stream: string, payload: unknown) => void
39
46
  now?: () => number
@@ -67,13 +74,25 @@ function codeFor(char: string): string {
67
74
 
68
75
  const IDLE_CLAIM: NeuralBandClaimStatus = {stage: "idle", sessionExpired: false}
69
76
  const IDLE_HANDWRITING: NeuralBandHandwritingStatus = {phase: "idle", message: "", text: ""}
77
+ const IDLE_FIRMWARE: NeuralBandFirmwareStatus = {
78
+ known: false,
79
+ connected: false,
80
+ hasMetaSession: false,
81
+ checked: false,
82
+ updateAvailable: false,
83
+ phase: "idle",
84
+ progress: 0,
85
+ message: "",
86
+ }
70
87
 
71
88
  export class NeuralBandInput {
72
89
  private latestClaim: NeuralBandClaimStatus = IDLE_CLAIM
73
90
  private claims = new Map<string, NeuralBandClaimStatus>()
74
91
  private handwriting = new Map<string, NeuralBandHandwritingStatus>()
92
+ private firmware = new Map<string, NeuralBandFirmwareStatus>()
75
93
  private claimListeners = new Set<(status: NeuralBandClaimStatus) => void>()
76
94
  private handwritingListeners = new Set<(update: NeuralBandHandwritingUpdate) => void>()
95
+ private firmwareListeners = new Set<(update: {id: string; status: NeuralBandFirmwareStatus}) => void>()
77
96
  private readonly forward: (stream: string, payload: unknown) => void
78
97
  private readonly now: () => number
79
98
 
@@ -102,6 +121,15 @@ export class NeuralBandInput {
102
121
  return () => this.handwritingListeners.delete(cb)
103
122
  }
104
123
 
124
+ firmwareStatus(controllerId: string): NeuralBandFirmwareStatus {
125
+ return this.firmware.get(controllerId) ?? IDLE_FIRMWARE
126
+ }
127
+
128
+ onFirmwareStatus(cb: (update: {id: string; status: NeuralBandFirmwareStatus}) => void): () => void {
129
+ this.firmwareListeners.add(cb)
130
+ return () => this.firmwareListeners.delete(cb)
131
+ }
132
+
105
133
  /** A new pairing attempt starts from a clean slate. */
106
134
  resetClaim(): void {
107
135
  this.latestClaim = IDLE_CLAIM
@@ -112,6 +140,14 @@ export class NeuralBandInput {
112
140
  forget(controllerId: string): void {
113
141
  this.claims.delete(controllerId)
114
142
  this.handwriting.delete(controllerId)
143
+ this.firmware.delete(controllerId)
144
+ }
145
+
146
+ handleFirmware(event: NeuralBandFirmwareEvent): void {
147
+ const {type: _type, controllerId, ...rest} = event
148
+ const status: NeuralBandFirmwareStatus = {...rest, known: true}
149
+ this.firmware.set(controllerId, status)
150
+ for (const cb of this.firmwareListeners) cb({id: controllerId, status})
115
151
  }
116
152
 
117
153
  handleClaim(event: NeuralBandClaimEvent): void {
@@ -1,16 +1,23 @@
1
1
  /**
2
- * Pushes the Neural Band user settings (air mouse, wearing hand) to every
3
- * connected band: to each band as it connects, and to all of them whenever
4
- * either setting changes. The native side keeps nothing across connections.
2
+ * Pushes the Neural Band user settings (air mouse, wearing hand, vibration) to
3
+ * every connected band: to each band as it connects, and to all of them
4
+ * whenever a setting changes. The native side keeps nothing across
5
+ * connections. Handwriting is gated, not pushed: HandwritingGate runs it while
6
+ * the setting is on and a miniapp has a text field open.
5
7
  */
6
8
  import BluetoothSdk from "@glassly/bluetooth-sdk/internal"
7
9
 
8
10
  import {useGlassesStore} from "../../stores/glasses"
9
11
  import {SETTINGS, useSettingsStore} from "../../stores/settings"
10
12
  import {ControllerTypes} from "../../types/enums"
13
+ import {BgTimer} from "../../utils/timers"
11
14
  import {readyControllers} from "../controllers"
15
+ import localMiniappRuntime from "../LocalMiniappRuntime"
16
+ import {HandwritingGate} from "./HandwritingGate"
17
+ import neuralBandInput from "./NeuralBandInput"
12
18
 
13
19
  let unsubscribers: (() => void)[] = []
20
+ let handwriting: HandwritingGate | null = null
14
21
 
15
22
  function connectedBandIds(): string[] {
16
23
  return readyControllers(useGlassesStore.getState().controllers)
@@ -32,10 +39,39 @@ function pushHand(id: string): void {
32
39
  )
33
40
  }
34
41
 
42
+ function pushVibration(id: string): void {
43
+ const enabled = useSettingsStore.getState().getSetting(SETTINGS.neural_band_vibration.key) !== false
44
+ void BluetoothSdk.neuralBandSetGestureHaptics(id, enabled).catch((err) =>
45
+ console.warn("NeuralBandSettingsSync: vibration push failed:", err),
46
+ )
47
+ }
48
+
49
+ function startHandwritingGate(): (() => void)[] {
50
+ const gate = new HandwritingGate({
51
+ enabled: () => useSettingsStore.getState().getSetting(SETTINGS.neural_band_handwriting.key) !== false,
52
+ textFieldOpen: () => localMiniappRuntime.hasOpenTextField(),
53
+ setHandwriting: (id, enabled) => BluetoothSdk.neuralBandSetHandwriting(id, enabled),
54
+ setTimeout: (fn, ms) => BgTimer.setTimeout(fn, ms),
55
+ clearTimeout: (handle) => BgTimer.clearTimeout(handle as number),
56
+ })
57
+ handwriting = gate
58
+ gate.setBands(connectedBandIds())
59
+ return [
60
+ useSettingsStore.subscribe(
61
+ (s) => s.getSetting(SETTINGS.neural_band_handwriting.key),
62
+ () => gate.update(),
63
+ ),
64
+ localMiniappRuntime.onTextFieldChange(() => gate.update()),
65
+ neuralBandInput.onHandwritingStatus(({id, status}) => gate.status(id, status.phase)),
66
+ () => gate.dispose(),
67
+ ]
68
+ }
69
+
35
70
  export function startNeuralBandSettingsSync(): void {
36
71
  if (unsubscribers.length > 0) return
37
72
  let connected = new Set(connectedBandIds())
38
73
  unsubscribers = [
74
+ ...startHandwritingGate(),
39
75
  useGlassesStore.subscribe(
40
76
  () => connectedBandIds().sort().join(","),
41
77
  () => {
@@ -44,8 +80,10 @@ export function startNeuralBandSettingsSync(): void {
44
80
  if (connected.has(id)) continue
45
81
  pushAirMouse(id)
46
82
  pushHand(id)
83
+ pushVibration(id)
47
84
  }
48
85
  connected = next
86
+ handwriting?.setBands([...next])
49
87
  },
50
88
  ),
51
89
  useSettingsStore.subscribe(
@@ -56,10 +94,15 @@ export function startNeuralBandSettingsSync(): void {
56
94
  (s) => s.getSetting(SETTINGS.neural_band_hand.key),
57
95
  () => connectedBandIds().forEach(pushHand),
58
96
  ),
97
+ useSettingsStore.subscribe(
98
+ (s) => s.getSetting(SETTINGS.neural_band_vibration.key),
99
+ () => connectedBandIds().forEach(pushVibration),
100
+ ),
59
101
  ]
60
102
  }
61
103
 
62
104
  export function stopNeuralBandSettingsSync(): void {
63
105
  for (const unsubscribe of unsubscribers) unsubscribe()
64
106
  unsubscribers = []
107
+ handwriting = null
65
108
  }
@@ -28,7 +28,6 @@ export const DEV_TOOLS_PACKAGES: ReadonlySet<string> = new Set([
28
28
  "com.glassly.example",
29
29
  "com.glassly.tetris",
30
30
  "com.glassly.compass",
31
- "com.glassly.showcase",
32
31
  ])
33
32
 
34
33
  /** True when the app is dev-only and developer tools are off. */
@@ -848,6 +848,24 @@ export const SETTINGS: Record<string, Setting> = {
848
848
  saveOnServer: false,
849
849
  persist: true,
850
850
  },
851
+ // Meta Neural Band handwriting typing into miniapps. Enabled means the band runs
852
+ // its handwriting model while a miniapp has a text field open on the glasses
853
+ // (HandwritingGate); the model streams the whole time it runs, so never otherwise.
854
+ neural_band_handwriting: {
855
+ key: "neural_band_handwriting",
856
+ defaultValue: () => true,
857
+ writable: true,
858
+ saveOnServer: false,
859
+ persist: true,
860
+ },
861
+ // The band's own buzz on each gesture (its haptics pattern 1; pattern 2 is silent).
862
+ neural_band_vibration: {
863
+ key: "neural_band_vibration",
864
+ defaultValue: () => true,
865
+ writable: true,
866
+ saveOnServer: false,
867
+ persist: true,
868
+ },
851
869
  // Watch (Apple Watch, Wear OS): draw the glasses' current frame behind the watch
852
870
  // trackpad. Frames cross the watch link while the watch app is up, so it stays off
853
871
  // unless asked for.
@@ -24,4 +24,5 @@ export enum ControllerTypes {
24
24
  GAMEBRICK = "IINE Gamebrick",
25
25
  IINE_ANANKE = "IINE Ananke Gen 2",
26
26
  ZERO2 = "8BitDo Zero 2",
27
+ MICRO = "8BitDo Micro",
27
28
  }