@glassly/engine 0.3.8-dev.998 → 0.4.0-dev.1017
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.
- package/build/engine.d.ts +11 -0
- package/build/engine.d.ts.map +1 -1
- package/build/facades/ai.d.ts +6 -0
- package/build/facades/ai.d.ts.map +1 -1
- package/build/facades/ai.js +6 -0
- package/build/facades/ai.js.map +1 -1
- package/build/facades/glasses.d.ts +9 -1
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +13 -0
- package/build/facades/glasses.js.map +1 -1
- package/build/generated/releaseMetadata.js +4 -4
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/services/CloudClientService.d.ts +2 -1
- package/build/services/CloudClientService.d.ts.map +1 -1
- package/build/services/CloudClientService.js +8 -0
- package/build/services/CloudClientService.js.map +1 -1
- package/build/services/DeviceEventRouter.d.ts.map +1 -1
- package/build/services/DeviceEventRouter.js +1 -0
- package/build/services/DeviceEventRouter.js.map +1 -1
- package/build/services/GlassesSensorService.js +1 -1
- package/build/services/GlassesSensorService.js.map +1 -1
- package/build/services/LocalLlmModelManager.d.ts +22 -2
- package/build/services/LocalLlmModelManager.d.ts.map +1 -1
- package/build/services/LocalLlmModelManager.js +104 -2
- package/build/services/LocalLlmModelManager.js.map +1 -1
- package/build/services/LocalLlmProvider.d.ts.map +1 -1
- package/build/services/LocalLlmProvider.js +11 -0
- package/build/services/LocalLlmProvider.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +13 -0
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +57 -1
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/controllers.d.ts.map +1 -1
- package/build/services/controllers.js +2 -0
- package/build/services/controllers.js.map +1 -1
- package/build/services/neuralBand/HandwritingGate.d.ts +38 -0
- package/build/services/neuralBand/HandwritingGate.d.ts.map +1 -0
- package/build/services/neuralBand/HandwritingGate.js +89 -0
- package/build/services/neuralBand/HandwritingGate.js.map +1 -0
- package/build/services/neuralBand/NeuralBandInput.d.ts +12 -1
- package/build/services/neuralBand/NeuralBandInput.d.ts.map +1 -1
- package/build/services/neuralBand/NeuralBandInput.js +27 -0
- package/build/services/neuralBand/NeuralBandInput.js.map +1 -1
- package/build/services/neuralBand/NeuralBandSettingsSync.d.ts.map +1 -1
- package/build/services/neuralBand/NeuralBandSettingsSync.js +36 -3
- package/build/services/neuralBand/NeuralBandSettingsSync.js.map +1 -1
- package/build/stores/appVisibility.d.ts.map +1 -1
- package/build/stores/appVisibility.js +0 -1
- package/build/stores/appVisibility.js.map +1 -1
- package/build/stores/settings.d.ts.map +1 -1
- package/build/stores/settings.js +18 -0
- package/build/stores/settings.js.map +1 -1
- package/build/types/enums.d.ts +3 -1
- package/build/types/enums.d.ts.map +1 -1
- package/build/types/enums.js +2 -0
- package/build/types/enums.js.map +1 -1
- package/package.json +7 -7
- package/src/facades/ai.ts +6 -0
- package/src/facades/glasses.ts +17 -0
- package/src/generated/releaseMetadata.ts +4 -4
- package/src/index.ts +1 -0
- package/src/services/CloudClientService.ts +8 -0
- package/src/services/DeviceEventRouter.ts +1 -0
- package/src/services/GlassesSensorService.ts +1 -1
- package/src/services/LocalLlmModelManager.ts +110 -3
- package/src/services/LocalLlmProvider.ts +8 -0
- package/src/services/LocalMiniappRuntime.ts +62 -1
- package/src/services/controllers.ts +2 -0
- package/src/services/neuralBand/HandwritingGate.ts +111 -0
- package/src/services/neuralBand/NeuralBandInput.ts +37 -1
- package/src/services/neuralBand/NeuralBandSettingsSync.ts +46 -3
- package/src/stores/appVisibility.ts +0 -1
- package/src/stores/settings.ts +18 -0
- package/src/types/enums.ts +2 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controllers.d.ts","sourceRoot":"","sources":["../../src/services/controllers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAC,gBAAgB,EAAE,gBAAgB,EAAC,MAAM,wBAAwB,CAAA;AAE9E,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,UAAU,CAAA;AAGhD,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"controllers.d.ts","sourceRoot":"","sources":["../../src/services/controllers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAC,gBAAgB,EAAE,gBAAgB,EAAC,MAAM,wBAAwB,CAAA;AAE9E,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,UAAU,CAAA;AAGhD,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;AAoD7E,iFAAiF;AACjF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,CAErE;AAED,0CAA0C;AAC1C,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEpE;AAED,2EAA2E;AAC3E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,EAAE,CAUxE;AAED,6DAA6D;AAC7D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAE/E;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,SAAS,GAAG,gBAAgB,EAAE,CAE3G;AAED,wDAAwD;AACxD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,SAAS,GAAG,MAAM,CAKlG"}
|
|
@@ -41,6 +41,8 @@ const INPUT_SURFACES = {
|
|
|
41
41
|
[ControllerTypes.WEAR_OS]: [WATCH_SURFACE],
|
|
42
42
|
[ControllerTypes.GAMEBRICK]: [GAMEBRICK_SURFACE],
|
|
43
43
|
[ControllerTypes.IINE_ANANKE]: [GAMEBRICK_SURFACE],
|
|
44
|
+
[ControllerTypes.ZERO2]: [GAMEBRICK_SURFACE],
|
|
45
|
+
[ControllerTypes.MICRO]: [GAMEBRICK_SURFACE],
|
|
44
46
|
[ControllerTypes.R1]: [],
|
|
45
47
|
};
|
|
46
48
|
/** The input surfaces a connected controller of `model` adds to the glasses'. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controllers.js","sourceRoot":"","sources":["../../src/services/controllers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Controller registry read-model: the paired records (the native-authoritative\n * `controllers` setting) and the live driver statuses (glasses status\n * `controllers`), plus what each model adds to the input surfaces. Pure.\n */\nimport type {ControllerStatus, PairedController} from \"@glassly/bluetooth-sdk\"\n\nimport type {ButtonCapabilities} from \"../types\"\nimport {ControllerTypes} from \"../types/enums\"\n\nexport type InputSurface = NonNullable<ButtonCapabilities[\"buttons\"]>[number]\n\n/** The Neural Band's thumb swipes, pinches and dial. */\nconst NEURAL_BAND_SURFACE: InputSurface = {\n type: \"swipe2d\",\n events: [\n \"TAP\",\n \"DOUBLE_TAP\",\n \"PRESS_HOLD\",\n \"SWIPE_UP\",\n \"SWIPE_DOWN\",\n \"SWIPE_LEFT\",\n \"SWIPE_RIGHT\",\n \"DIAL_UP\",\n \"DIAL_DOWN\",\n ],\n}\n\n/** A watch trackpad's taps and four-way swipes, and the crown (Apple) or rotary bezel (Wear OS) as the dial. */\nconst WATCH_SURFACE: InputSurface = {\n type: \"swipe2d\",\n events: [\n \"TAP\",\n \"DOUBLE_TAP\",\n \"PRESS_HOLD\",\n \"SWIPE_UP\",\n \"SWIPE_DOWN\",\n \"SWIPE_LEFT\",\n \"SWIPE_RIGHT\",\n \"DIAL_UP\",\n \"DIAL_DOWN\",\n ],\n}\n\n/** The Gamebrick's D-pad is four absolute swipes; A is the press lifecycle (tap and hold) and B a double tap. */\nconst GAMEBRICK_SURFACE: InputSurface = {\n type: \"swipe2d\",\n events: [\"TAP\", \"DOUBLE_TAP\", \"PRESS_HOLD\", \"SWIPE_UP\", \"SWIPE_DOWN\", \"SWIPE_LEFT\", \"SWIPE_RIGHT\"],\n}\n\n// The R1 swipes up/down like the temples it stands in for, so it adds nothing.\nconst INPUT_SURFACES: Readonly<Record<string, readonly InputSurface[]>> = {\n [ControllerTypes.NEURAL_BAND]: [NEURAL_BAND_SURFACE],\n [ControllerTypes.APPLE_WATCH]: [WATCH_SURFACE],\n [ControllerTypes.WEAR_OS]: [WATCH_SURFACE],\n [ControllerTypes.GAMEBRICK]: [GAMEBRICK_SURFACE],\n [ControllerTypes.IINE_ANANKE]: [GAMEBRICK_SURFACE],\n [ControllerTypes.R1]: [],\n}\n\n/** The input surfaces a connected controller of `model` adds to the glasses'. */\nexport function controllerInputSurfaces(model: string): InputSurface[] {\n return (INPUT_SURFACES[model] ?? []).map((surface) => ({...surface, events: [...surface.events]}))\n}\n\n/** The model swipes in two dimensions. */\nexport function hasInput2d(model: string): boolean {\n return (INPUT_SURFACES[model] ?? []).some((surface) => surface.type === \"swipe2d\")\n}\n\nexport function isControllerModel(model: string | undefined): boolean {\n return model !== undefined && (Object.values(ControllerTypes) as string[]).includes(model)\n}\n\n/** The `controllers` setting as records; malformed entries are dropped. */\nexport function pairedControllersFrom(value: unknown): PairedController[] {\n if (!Array.isArray(value)) return []\n const records: PairedController[] = []\n for (const entry of value) {\n if (!entry || typeof entry !== \"object\") continue\n const {id, model, name} = entry as Record<string, unknown>\n if (typeof id !== \"string\" || !id || typeof model !== \"string\") continue\n records.push({id, model, name: typeof name === \"string\" ? name : id})\n }\n return records\n}\n\n/** Delivering input: link up and the route or claim done. */\nexport function isControllerReady(status: ControllerStatus | undefined): boolean {\n return status?.connected === true && status.fullyBooted === true\n}\n\nexport function readyControllers(statuses: Record<string, ControllerStatus> | undefined): ControllerStatus[] {\n return Object.values(statuses ?? {}).filter(isControllerReady)\n}\n\n/** Change key over the controllers delivering input. */\nexport function readyControllersKey(statuses: Record<string, ControllerStatus> | undefined): string {\n return readyControllers(statuses)\n .map((status) => `${status.id}=${status.model}`)\n .sort()\n .join(\",\")\n}\n"]}
|
|
1
|
+
{"version":3,"file":"controllers.js","sourceRoot":"","sources":["../../src/services/controllers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Controller registry read-model: the paired records (the native-authoritative\n * `controllers` setting) and the live driver statuses (glasses status\n * `controllers`), plus what each model adds to the input surfaces. Pure.\n */\nimport type {ControllerStatus, PairedController} from \"@glassly/bluetooth-sdk\"\n\nimport type {ButtonCapabilities} from \"../types\"\nimport {ControllerTypes} from \"../types/enums\"\n\nexport type InputSurface = NonNullable<ButtonCapabilities[\"buttons\"]>[number]\n\n/** The Neural Band's thumb swipes, pinches and dial. */\nconst NEURAL_BAND_SURFACE: InputSurface = {\n type: \"swipe2d\",\n events: [\n \"TAP\",\n \"DOUBLE_TAP\",\n \"PRESS_HOLD\",\n \"SWIPE_UP\",\n \"SWIPE_DOWN\",\n \"SWIPE_LEFT\",\n \"SWIPE_RIGHT\",\n \"DIAL_UP\",\n \"DIAL_DOWN\",\n ],\n}\n\n/** A watch trackpad's taps and four-way swipes, and the crown (Apple) or rotary bezel (Wear OS) as the dial. */\nconst WATCH_SURFACE: InputSurface = {\n type: \"swipe2d\",\n events: [\n \"TAP\",\n \"DOUBLE_TAP\",\n \"PRESS_HOLD\",\n \"SWIPE_UP\",\n \"SWIPE_DOWN\",\n \"SWIPE_LEFT\",\n \"SWIPE_RIGHT\",\n \"DIAL_UP\",\n \"DIAL_DOWN\",\n ],\n}\n\n/** The Gamebrick's D-pad is four absolute swipes; A is the press lifecycle (tap and hold) and B a double tap. */\nconst GAMEBRICK_SURFACE: InputSurface = {\n type: \"swipe2d\",\n events: [\"TAP\", \"DOUBLE_TAP\", \"PRESS_HOLD\", \"SWIPE_UP\", \"SWIPE_DOWN\", \"SWIPE_LEFT\", \"SWIPE_RIGHT\"],\n}\n\n// The R1 swipes up/down like the temples it stands in for, so it adds nothing.\nconst INPUT_SURFACES: Readonly<Record<string, readonly InputSurface[]>> = {\n [ControllerTypes.NEURAL_BAND]: [NEURAL_BAND_SURFACE],\n [ControllerTypes.APPLE_WATCH]: [WATCH_SURFACE],\n [ControllerTypes.WEAR_OS]: [WATCH_SURFACE],\n [ControllerTypes.GAMEBRICK]: [GAMEBRICK_SURFACE],\n [ControllerTypes.IINE_ANANKE]: [GAMEBRICK_SURFACE],\n [ControllerTypes.ZERO2]: [GAMEBRICK_SURFACE],\n [ControllerTypes.MICRO]: [GAMEBRICK_SURFACE],\n [ControllerTypes.R1]: [],\n}\n\n/** The input surfaces a connected controller of `model` adds to the glasses'. */\nexport function controllerInputSurfaces(model: string): InputSurface[] {\n return (INPUT_SURFACES[model] ?? []).map((surface) => ({...surface, events: [...surface.events]}))\n}\n\n/** The model swipes in two dimensions. */\nexport function hasInput2d(model: string): boolean {\n return (INPUT_SURFACES[model] ?? []).some((surface) => surface.type === \"swipe2d\")\n}\n\nexport function isControllerModel(model: string | undefined): boolean {\n return model !== undefined && (Object.values(ControllerTypes) as string[]).includes(model)\n}\n\n/** The `controllers` setting as records; malformed entries are dropped. */\nexport function pairedControllersFrom(value: unknown): PairedController[] {\n if (!Array.isArray(value)) return []\n const records: PairedController[] = []\n for (const entry of value) {\n if (!entry || typeof entry !== \"object\") continue\n const {id, model, name} = entry as Record<string, unknown>\n if (typeof id !== \"string\" || !id || typeof model !== \"string\") continue\n records.push({id, model, name: typeof name === \"string\" ? name : id})\n }\n return records\n}\n\n/** Delivering input: link up and the route or claim done. */\nexport function isControllerReady(status: ControllerStatus | undefined): boolean {\n return status?.connected === true && status.fullyBooted === true\n}\n\nexport function readyControllers(statuses: Record<string, ControllerStatus> | undefined): ControllerStatus[] {\n return Object.values(statuses ?? {}).filter(isControllerReady)\n}\n\n/** Change key over the controllers delivering input. */\nexport function readyControllersKey(statuses: Record<string, ControllerStatus> | undefined): string {\n return readyControllers(statuses)\n .map((status) => `${status.id}=${status.model}`)\n .sort()\n .join(\",\")\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decides when each connected Meta Neural Band runs its handwriting model. The
|
|
3
|
+
* model streams to the phone for as long as it runs, written on or not, so it
|
|
4
|
+
* runs only while it can type somewhere: the wearer has handwriting enabled
|
|
5
|
+
* and a miniapp has a text field open on the glasses. It outlives the last
|
|
6
|
+
* field by OFF_DELAY_MS, so moving between fields doesn't restart it. A session
|
|
7
|
+
* the band ends on its own (timeout, refused setting, silence) isn't retried
|
|
8
|
+
* until no field is open, so a band that can't run the model isn't asked again
|
|
9
|
+
* and again.
|
|
10
|
+
*/
|
|
11
|
+
import type { NeuralBandHandwritingStatus } from "./NeuralBandInput";
|
|
12
|
+
type Phase = NeuralBandHandwritingStatus["phase"];
|
|
13
|
+
export interface HandwritingGateDeps {
|
|
14
|
+
enabled: () => boolean;
|
|
15
|
+
textFieldOpen: () => boolean;
|
|
16
|
+
setHandwriting: (id: string, enabled: boolean) => Promise<void>;
|
|
17
|
+
setTimeout: (fn: () => void, ms: number) => unknown;
|
|
18
|
+
clearTimeout: (handle: unknown) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare const OFF_DELAY_MS = 5000;
|
|
21
|
+
export declare class HandwritingGate {
|
|
22
|
+
private readonly deps;
|
|
23
|
+
private bands;
|
|
24
|
+
private offTimer;
|
|
25
|
+
constructor(deps: HandwritingGateDeps);
|
|
26
|
+
/** The connected bands. A band keeps nothing across connections, so a reconnect starts fresh. */
|
|
27
|
+
setBands(ids: string[]): void;
|
|
28
|
+
/** A band reported its handwriting phase. */
|
|
29
|
+
status(id: string, phase: Phase): void;
|
|
30
|
+
/** Re-evaluate after the setting or the open text fields changed. */
|
|
31
|
+
update(): void;
|
|
32
|
+
dispose(): void;
|
|
33
|
+
private stopAll;
|
|
34
|
+
private request;
|
|
35
|
+
private clearOffTimer;
|
|
36
|
+
}
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=HandwritingGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HandwritingGate.d.ts","sourceRoot":"","sources":["../../../src/services/neuralBand/HandwritingGate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,mBAAmB,CAAA;AAElE,KAAK,KAAK,GAAG,2BAA2B,CAAC,OAAO,CAAC,CAAA;AAEjD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,OAAO,CAAA;IACtB,aAAa,EAAE,MAAM,OAAO,CAAA;IAC5B,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAA;IACnD,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;CACxC;AASD,eAAO,MAAM,YAAY,OAAQ,CAAA;AAGjC,qBAAa,eAAe;IAId,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,QAAQ,CAAgB;gBAEH,IAAI,EAAE,mBAAmB;IAEtD,iGAAiG;IACjG,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI;IAM7B,6CAA6C;IAC7C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAWtC,qEAAqE;IACrE,MAAM,IAAI,IAAI;IA2Bd,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,aAAa;CAKtB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export const OFF_DELAY_MS = 5_000;
|
|
2
|
+
const ACTIVE = new Set(["preparing", "ready", "restoring"]);
|
|
3
|
+
export class HandwritingGate {
|
|
4
|
+
deps;
|
|
5
|
+
bands = new Map();
|
|
6
|
+
offTimer = null;
|
|
7
|
+
constructor(deps) {
|
|
8
|
+
this.deps = deps;
|
|
9
|
+
}
|
|
10
|
+
/** The connected bands. A band keeps nothing across connections, so a reconnect starts fresh. */
|
|
11
|
+
setBands(ids) {
|
|
12
|
+
for (const id of [...this.bands.keys()])
|
|
13
|
+
if (!ids.includes(id))
|
|
14
|
+
this.bands.delete(id);
|
|
15
|
+
for (const id of ids)
|
|
16
|
+
if (!this.bands.has(id))
|
|
17
|
+
this.bands.set(id, { requested: false, failed: false, phase: "idle" });
|
|
18
|
+
this.update();
|
|
19
|
+
}
|
|
20
|
+
/** A band reported its handwriting phase. */
|
|
21
|
+
status(id, phase) {
|
|
22
|
+
const band = this.bands.get(id);
|
|
23
|
+
if (!band)
|
|
24
|
+
return;
|
|
25
|
+
band.phase = phase;
|
|
26
|
+
if (phase === "finished" && band.requested) {
|
|
27
|
+
band.requested = false;
|
|
28
|
+
band.failed = true;
|
|
29
|
+
}
|
|
30
|
+
this.update();
|
|
31
|
+
}
|
|
32
|
+
/** Re-evaluate after the setting or the open text fields changed. */
|
|
33
|
+
update() {
|
|
34
|
+
const enabled = this.deps.enabled();
|
|
35
|
+
if (enabled && this.deps.textFieldOpen()) {
|
|
36
|
+
this.clearOffTimer();
|
|
37
|
+
for (const [id, band] of this.bands) {
|
|
38
|
+
// A session still winding down (or one we didn't start) has to finish first.
|
|
39
|
+
if (band.requested || band.failed || ACTIVE.has(band.phase))
|
|
40
|
+
continue;
|
|
41
|
+
this.request(id, band, true);
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
for (const band of this.bands.values())
|
|
46
|
+
band.failed = false;
|
|
47
|
+
if (![...this.bands.values()].some((band) => band.requested)) {
|
|
48
|
+
this.clearOffTimer();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (!enabled) {
|
|
52
|
+
this.clearOffTimer();
|
|
53
|
+
this.stopAll();
|
|
54
|
+
}
|
|
55
|
+
else if (this.offTimer === null) {
|
|
56
|
+
this.offTimer = this.deps.setTimeout(() => {
|
|
57
|
+
this.offTimer = null;
|
|
58
|
+
if (!this.deps.textFieldOpen() || !this.deps.enabled())
|
|
59
|
+
this.stopAll();
|
|
60
|
+
}, OFF_DELAY_MS);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
dispose() {
|
|
64
|
+
this.clearOffTimer();
|
|
65
|
+
this.bands.clear();
|
|
66
|
+
}
|
|
67
|
+
stopAll() {
|
|
68
|
+
for (const [id, band] of this.bands)
|
|
69
|
+
if (band.requested)
|
|
70
|
+
this.request(id, band, false);
|
|
71
|
+
}
|
|
72
|
+
request(id, band, enabled) {
|
|
73
|
+
band.requested = enabled;
|
|
74
|
+
this.deps.setHandwriting(id, enabled).catch((err) => {
|
|
75
|
+
console.warn(`HandwritingGate: turning handwriting ${enabled ? "on" : "off"} failed:`, err);
|
|
76
|
+
if (enabled && this.bands.get(id) === band && band.requested) {
|
|
77
|
+
band.requested = false;
|
|
78
|
+
band.failed = true;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
clearOffTimer() {
|
|
83
|
+
if (this.offTimer === null)
|
|
84
|
+
return;
|
|
85
|
+
this.deps.clearTimeout(this.offTimer);
|
|
86
|
+
this.offTimer = null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=HandwritingGate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HandwritingGate.js","sourceRoot":"","sources":["../../../src/services/neuralBand/HandwritingGate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Decides when each connected Meta Neural Band runs its handwriting model. The\n * model streams to the phone for as long as it runs, written on or not, so it\n * runs only while it can type somewhere: the wearer has handwriting enabled\n * and a miniapp has a text field open on the glasses. It outlives the last\n * field by OFF_DELAY_MS, so moving between fields doesn't restart it. A session\n * the band ends on its own (timeout, refused setting, silence) isn't retried\n * until no field is open, so a band that can't run the model isn't asked again\n * and again.\n */\nimport type {NeuralBandHandwritingStatus} from \"./NeuralBandInput\"\n\ntype Phase = NeuralBandHandwritingStatus[\"phase\"]\n\nexport interface HandwritingGateDeps {\n enabled: () => boolean\n textFieldOpen: () => boolean\n setHandwriting: (id: string, enabled: boolean) => Promise<void>\n setTimeout: (fn: () => void, ms: number) => unknown\n clearTimeout: (handle: unknown) => void\n}\n\ninterface Band {\n /** What we last asked this band for. */\n requested: boolean\n failed: boolean\n phase: Phase\n}\n\nexport const OFF_DELAY_MS = 5_000\nconst ACTIVE = new Set<Phase>([\"preparing\", \"ready\", \"restoring\"])\n\nexport class HandwritingGate {\n private bands = new Map<string, Band>()\n private offTimer: unknown = null\n\n constructor(private readonly deps: HandwritingGateDeps) {}\n\n /** The connected bands. A band keeps nothing across connections, so a reconnect starts fresh. */\n setBands(ids: string[]): void {\n for (const id of [...this.bands.keys()]) if (!ids.includes(id)) this.bands.delete(id)\n for (const id of ids) if (!this.bands.has(id)) this.bands.set(id, {requested: false, failed: false, phase: \"idle\"})\n this.update()\n }\n\n /** A band reported its handwriting phase. */\n status(id: string, phase: Phase): void {\n const band = this.bands.get(id)\n if (!band) return\n band.phase = phase\n if (phase === \"finished\" && band.requested) {\n band.requested = false\n band.failed = true\n }\n this.update()\n }\n\n /** Re-evaluate after the setting or the open text fields changed. */\n update(): void {\n const enabled = this.deps.enabled()\n if (enabled && this.deps.textFieldOpen()) {\n this.clearOffTimer()\n for (const [id, band] of this.bands) {\n // A session still winding down (or one we didn't start) has to finish first.\n if (band.requested || band.failed || ACTIVE.has(band.phase)) continue\n this.request(id, band, true)\n }\n return\n }\n for (const band of this.bands.values()) band.failed = false\n if (![...this.bands.values()].some((band) => band.requested)) {\n this.clearOffTimer()\n return\n }\n if (!enabled) {\n this.clearOffTimer()\n this.stopAll()\n } else if (this.offTimer === null) {\n this.offTimer = this.deps.setTimeout(() => {\n this.offTimer = null\n if (!this.deps.textFieldOpen() || !this.deps.enabled()) this.stopAll()\n }, OFF_DELAY_MS)\n }\n }\n\n dispose(): void {\n this.clearOffTimer()\n this.bands.clear()\n }\n\n private stopAll(): void {\n for (const [id, band] of this.bands) if (band.requested) this.request(id, band, false)\n }\n\n private request(id: string, band: Band, enabled: boolean): void {\n band.requested = enabled\n this.deps.setHandwriting(id, enabled).catch((err) => {\n console.warn(`HandwritingGate: turning handwriting ${enabled ? \"on\" : \"off\"} failed:`, err)\n if (enabled && this.bands.get(id) === band && band.requested) {\n band.requested = false\n band.failed = true\n }\n })\n }\n\n private clearOffTimer(): void {\n if (this.offTimer === null) return\n this.deps.clearTimeout(this.offTimer)\n this.offTimer = null\n }\n}\n"]}
|
|
@@ -6,7 +6,7 @@
|
|
|
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 { NeuralBandClaimEvent, NeuralBandFirmwareEvent, NeuralBandHandwritingEvent, NeuralBandPointerEvent } from "@glassly/bluetooth-sdk";
|
|
10
10
|
import type { KeyboardEventPayload } from "../GlassesKeyboardInput";
|
|
11
11
|
export interface NeuralBandClaimStatus {
|
|
12
12
|
stage: "idle" | "progress" | "completed" | "failed";
|
|
@@ -27,6 +27,9 @@ export interface NeuralBandHandwritingUpdate {
|
|
|
27
27
|
id: string;
|
|
28
28
|
status: NeuralBandHandwritingStatus;
|
|
29
29
|
}
|
|
30
|
+
export type NeuralBandFirmwareStatus = Omit<NeuralBandFirmwareEvent, "type" | "controllerId"> & {
|
|
31
|
+
known: boolean;
|
|
32
|
+
};
|
|
30
33
|
export interface NeuralBandInputOptions {
|
|
31
34
|
forward?: (stream: string, payload: unknown) => void;
|
|
32
35
|
now?: () => number;
|
|
@@ -37,8 +40,10 @@ export declare class NeuralBandInput {
|
|
|
37
40
|
private latestClaim;
|
|
38
41
|
private claims;
|
|
39
42
|
private handwriting;
|
|
43
|
+
private firmware;
|
|
40
44
|
private claimListeners;
|
|
41
45
|
private handwritingListeners;
|
|
46
|
+
private firmwareListeners;
|
|
42
47
|
private readonly forward;
|
|
43
48
|
private readonly now;
|
|
44
49
|
constructor(options?: NeuralBandInputOptions);
|
|
@@ -47,10 +52,16 @@ export declare class NeuralBandInput {
|
|
|
47
52
|
onClaimStatus(cb: (status: NeuralBandClaimStatus) => void): () => void;
|
|
48
53
|
handwritingStatus(controllerId: string): NeuralBandHandwritingStatus;
|
|
49
54
|
onHandwritingStatus(cb: (update: NeuralBandHandwritingUpdate) => void): () => void;
|
|
55
|
+
firmwareStatus(controllerId: string): NeuralBandFirmwareStatus;
|
|
56
|
+
onFirmwareStatus(cb: (update: {
|
|
57
|
+
id: string;
|
|
58
|
+
status: NeuralBandFirmwareStatus;
|
|
59
|
+
}) => void): () => void;
|
|
50
60
|
/** A new pairing attempt starts from a clean slate. */
|
|
51
61
|
resetClaim(): void;
|
|
52
62
|
/** Drop an unpaired band's state. */
|
|
53
63
|
forget(controllerId: string): void;
|
|
64
|
+
handleFirmware(event: NeuralBandFirmwareEvent): void;
|
|
54
65
|
handleClaim(event: NeuralBandClaimEvent): void;
|
|
55
66
|
handleHandwriting(event: NeuralBandHandwritingEvent): void;
|
|
56
67
|
handlePointer(event: NeuralBandPointerEvent): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NeuralBandInput.d.ts","sourceRoot":"","sources":["../../../src/services/neuralBand/NeuralBandInput.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"NeuralBandInput.d.ts","sourceRoot":"","sources":["../../../src/services/neuralBand/NeuralBandInput.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,12 +32,24 @@ function codeFor(char) {
|
|
|
32
32
|
}
|
|
33
33
|
const IDLE_CLAIM = { stage: "idle", sessionExpired: false };
|
|
34
34
|
const IDLE_HANDWRITING = { phase: "idle", message: "", text: "" };
|
|
35
|
+
const IDLE_FIRMWARE = {
|
|
36
|
+
known: false,
|
|
37
|
+
connected: false,
|
|
38
|
+
hasMetaSession: false,
|
|
39
|
+
checked: false,
|
|
40
|
+
updateAvailable: false,
|
|
41
|
+
phase: "idle",
|
|
42
|
+
progress: 0,
|
|
43
|
+
message: "",
|
|
44
|
+
};
|
|
35
45
|
export class NeuralBandInput {
|
|
36
46
|
latestClaim = IDLE_CLAIM;
|
|
37
47
|
claims = new Map();
|
|
38
48
|
handwriting = new Map();
|
|
49
|
+
firmware = new Map();
|
|
39
50
|
claimListeners = new Set();
|
|
40
51
|
handwritingListeners = new Set();
|
|
52
|
+
firmwareListeners = new Set();
|
|
41
53
|
forward;
|
|
42
54
|
now;
|
|
43
55
|
constructor(options = {}) {
|
|
@@ -61,6 +73,13 @@ export class NeuralBandInput {
|
|
|
61
73
|
this.handwritingListeners.add(cb);
|
|
62
74
|
return () => this.handwritingListeners.delete(cb);
|
|
63
75
|
}
|
|
76
|
+
firmwareStatus(controllerId) {
|
|
77
|
+
return this.firmware.get(controllerId) ?? IDLE_FIRMWARE;
|
|
78
|
+
}
|
|
79
|
+
onFirmwareStatus(cb) {
|
|
80
|
+
this.firmwareListeners.add(cb);
|
|
81
|
+
return () => this.firmwareListeners.delete(cb);
|
|
82
|
+
}
|
|
64
83
|
/** A new pairing attempt starts from a clean slate. */
|
|
65
84
|
resetClaim() {
|
|
66
85
|
this.latestClaim = IDLE_CLAIM;
|
|
@@ -71,6 +90,14 @@ export class NeuralBandInput {
|
|
|
71
90
|
forget(controllerId) {
|
|
72
91
|
this.claims.delete(controllerId);
|
|
73
92
|
this.handwriting.delete(controllerId);
|
|
93
|
+
this.firmware.delete(controllerId);
|
|
94
|
+
}
|
|
95
|
+
handleFirmware(event) {
|
|
96
|
+
const { type: _type, controllerId, ...rest } = event;
|
|
97
|
+
const status = { ...rest, known: true };
|
|
98
|
+
this.firmware.set(controllerId, status);
|
|
99
|
+
for (const cb of this.firmwareListeners)
|
|
100
|
+
cb({ id: controllerId, status });
|
|
74
101
|
}
|
|
75
102
|
handleClaim(event) {
|
|
76
103
|
const status = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NeuralBandInput.js","sourceRoot":"","sources":["../../../src/services/neuralBand/NeuralBandInput.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Meta Neural Band's own event streams, past the gestures that ride `touch_event`:\n * claim progress (for the pairing screens), the handwriting model (typed into the\n * miniapp keyboard stream as synthesized key presses) and the air mouse (forwarded\n * to miniapps on the pointer stream). State is per band (`controllerId`); the\n * latest claim is also kept on its own, since the pairing screen runs before\n * the band's id reaches JS.\n */\nimport type {NeuralBandClaimEvent, NeuralBandHandwritingEvent, NeuralBandPointerEvent} from \"@glassly/bluetooth-sdk\"\nimport {MiniappStreamType} from \"@glassly/miniapp\"\n\nimport type {KeyboardEventPayload} from \"../GlassesKeyboardInput\"\nimport localMiniappRuntime from \"../LocalMiniappRuntime\"\n\nexport interface NeuralBandClaimStatus {\n stage: \"idle\" | \"progress\" | \"completed\" | \"failed\"\n message?: string\n sessionExpired: boolean\n bandName?: string\n /** The band being claimed; absent until a claim event arrives. */\n controllerId?: string\n}\n\nexport interface NeuralBandHandwritingStatus {\n phase: \"idle\" | \"preparing\" | \"ready\" | \"restoring\" | \"finished\"\n message: string\n problem?: string\n /** The last text the band produced since handwriting was switched on. */\n text: string\n}\n\nexport interface NeuralBandHandwritingUpdate {\n id: string\n status: NeuralBandHandwritingStatus\n}\n\nexport interface NeuralBandInputOptions {\n forward?: (stream: string, payload: unknown) => void\n now?: () => number\n}\n\nconst MODIFIERS = {shift: false, ctrl: false, alt: false, meta: false}\n\n/** One handwriting change as the key presses that would have typed it. */\nexport function keyEventsForTextChange(previous: string, next: string, timestamp: number): KeyboardEventPayload[] {\n let common = 0\n while (common < previous.length && common < next.length && previous[common] === next[common]) common++\n const events: KeyboardEventPayload[] = []\n const press = (key: string, code: string, text?: string) => {\n events.push({phase: \"down\", key, code, modifiers: MODIFIERS, text, repeat: false, timestamp})\n events.push({phase: \"up\", key, code, modifiers: MODIFIERS, repeat: false, timestamp})\n }\n for (let i = common; i < previous.length; i++) press(\"Backspace\", \"Backspace\")\n for (const char of Array.from(next.slice(common))) {\n if (char === \"\\n\") press(\"Enter\", \"Enter\")\n else if (char === \" \") press(\" \", \"Space\", \" \")\n else press(char, codeFor(char), char)\n }\n return events\n}\n\nfunction codeFor(char: string): string {\n if (/^[a-z]$/i.test(char)) return `Key${char.toUpperCase()}`\n if (/^[0-9]$/.test(char)) return `Digit${char}`\n return \"Unidentified\"\n}\n\nconst IDLE_CLAIM: NeuralBandClaimStatus = {stage: \"idle\", sessionExpired: false}\nconst IDLE_HANDWRITING: NeuralBandHandwritingStatus = {phase: \"idle\", message: \"\", text: \"\"}\n\nexport class NeuralBandInput {\n private latestClaim: NeuralBandClaimStatus = IDLE_CLAIM\n private claims = new Map<string, NeuralBandClaimStatus>()\n private handwriting = new Map<string, NeuralBandHandwritingStatus>()\n private claimListeners = new Set<(status: NeuralBandClaimStatus) => void>()\n private handwritingListeners = new Set<(update: NeuralBandHandwritingUpdate) => void>()\n private readonly forward: (stream: string, payload: unknown) => void\n private readonly now: () => number\n\n constructor(options: NeuralBandInputOptions = {}) {\n this.forward = options.forward ?? ((stream, payload) => localMiniappRuntime.forwardEvent(stream, payload))\n this.now = options.now ?? (() => Date.now())\n }\n\n /** One band's claim, or the latest claim of any band without an id. */\n claimStatus(controllerId?: string): NeuralBandClaimStatus {\n if (controllerId === undefined) return this.latestClaim\n return this.claims.get(controllerId) ?? IDLE_CLAIM\n }\n\n onClaimStatus(cb: (status: NeuralBandClaimStatus) => void): () => void {\n this.claimListeners.add(cb)\n return () => this.claimListeners.delete(cb)\n }\n\n handwritingStatus(controllerId: string): NeuralBandHandwritingStatus {\n return this.handwriting.get(controllerId) ?? IDLE_HANDWRITING\n }\n\n onHandwritingStatus(cb: (update: NeuralBandHandwritingUpdate) => void): () => void {\n this.handwritingListeners.add(cb)\n return () => this.handwritingListeners.delete(cb)\n }\n\n /** A new pairing attempt starts from a clean slate. */\n resetClaim(): void {\n this.latestClaim = IDLE_CLAIM\n for (const cb of this.claimListeners) cb(IDLE_CLAIM)\n }\n\n /** Drop an unpaired band's state. */\n forget(controllerId: string): void {\n this.claims.delete(controllerId)\n this.handwriting.delete(controllerId)\n }\n\n handleClaim(event: NeuralBandClaimEvent): void {\n const status: NeuralBandClaimStatus = {\n stage: event.stage,\n message: event.message,\n sessionExpired: event.sessionExpired === true,\n bandName: event.bandName,\n controllerId: event.controllerId,\n }\n if (event.controllerId) this.claims.set(event.controllerId, status)\n this.latestClaim = status\n for (const cb of this.claimListeners) cb(status)\n }\n\n handleHandwriting(event: NeuralBandHandwritingEvent): void {\n const id = event.controllerId\n const current = this.handwritingStatus(id)\n if (event.kind === \"state\") {\n const text = event.phase === \"preparing\" ? \"\" : current.text\n this.setHandwriting(id, {phase: event.phase, message: event.message, problem: event.problem, text})\n return\n }\n if (event.text !== current.text) {\n for (const key of keyEventsForTextChange(current.text, event.text, this.now())) {\n this.forward(MiniappStreamType.KEYBOARD_EVENT, key)\n }\n }\n this.setHandwriting(id, {...current, text: event.text})\n }\n\n handlePointer(event: NeuralBandPointerEvent): void {\n if (event.kind === \"move\") {\n this.forward(MiniappStreamType.POINTER_EVENT, {\n kind: \"move\",\n dx: event.dx,\n dy: event.dy,\n timestamp: event.timestamp,\n controllerId: event.controllerId,\n })\n } else {\n this.forward(MiniappStreamType.POINTER_EVENT, {\n kind: \"buttons\",\n buttons: event.buttons,\n timestamp: event.timestamp,\n controllerId: event.controllerId,\n })\n }\n }\n\n private setHandwriting(id: string, status: NeuralBandHandwritingStatus): void {\n this.handwriting.set(id, status)\n for (const cb of this.handwritingListeners) cb({id, status})\n }\n}\n\nconst neuralBandInput = new NeuralBandInput()\nexport default neuralBandInput\n"]}
|
|
1
|
+
{"version":3,"file":"NeuralBandInput.js","sourceRoot":"","sources":["../../../src/services/neuralBand/NeuralBandInput.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Meta Neural Band's own event streams, past the gestures that ride `touch_event`:\n * claim progress (for the pairing screens), the handwriting model (typed into the\n * miniapp keyboard stream as synthesized key presses) and the air mouse (forwarded\n * to miniapps on the pointer stream). State is per band (`controllerId`); the\n * latest claim is also kept on its own, since the pairing screen runs before\n * the band's id reaches JS.\n */\nimport type {\n NeuralBandClaimEvent,\n NeuralBandFirmwareEvent,\n NeuralBandHandwritingEvent,\n NeuralBandPointerEvent,\n} from \"@glassly/bluetooth-sdk\"\nimport {MiniappStreamType} from \"@glassly/miniapp\"\n\nimport type {KeyboardEventPayload} from \"../GlassesKeyboardInput\"\nimport localMiniappRuntime from \"../LocalMiniappRuntime\"\n\nexport interface NeuralBandClaimStatus {\n stage: \"idle\" | \"progress\" | \"completed\" | \"failed\"\n message?: string\n sessionExpired: boolean\n bandName?: string\n /** The band being claimed; absent until a claim event arrives. */\n controllerId?: string\n}\n\nexport interface NeuralBandHandwritingStatus {\n phase: \"idle\" | \"preparing\" | \"ready\" | \"restoring\" | \"finished\"\n message: string\n problem?: string\n /** The last text the band produced since handwriting was switched on. */\n text: string\n}\n\nexport interface NeuralBandHandwritingUpdate {\n id: string\n status: NeuralBandHandwritingStatus\n}\n\nexport type NeuralBandFirmwareStatus = Omit<NeuralBandFirmwareEvent, \"type\" | \"controllerId\"> & {known: boolean}\n\nexport interface NeuralBandInputOptions {\n forward?: (stream: string, payload: unknown) => void\n now?: () => number\n}\n\nconst MODIFIERS = {shift: false, ctrl: false, alt: false, meta: false}\n\n/** One handwriting change as the key presses that would have typed it. */\nexport function keyEventsForTextChange(previous: string, next: string, timestamp: number): KeyboardEventPayload[] {\n let common = 0\n while (common < previous.length && common < next.length && previous[common] === next[common]) common++\n const events: KeyboardEventPayload[] = []\n const press = (key: string, code: string, text?: string) => {\n events.push({phase: \"down\", key, code, modifiers: MODIFIERS, text, repeat: false, timestamp})\n events.push({phase: \"up\", key, code, modifiers: MODIFIERS, repeat: false, timestamp})\n }\n for (let i = common; i < previous.length; i++) press(\"Backspace\", \"Backspace\")\n for (const char of Array.from(next.slice(common))) {\n if (char === \"\\n\") press(\"Enter\", \"Enter\")\n else if (char === \" \") press(\" \", \"Space\", \" \")\n else press(char, codeFor(char), char)\n }\n return events\n}\n\nfunction codeFor(char: string): string {\n if (/^[a-z]$/i.test(char)) return `Key${char.toUpperCase()}`\n if (/^[0-9]$/.test(char)) return `Digit${char}`\n return \"Unidentified\"\n}\n\nconst IDLE_CLAIM: NeuralBandClaimStatus = {stage: \"idle\", sessionExpired: false}\nconst IDLE_HANDWRITING: NeuralBandHandwritingStatus = {phase: \"idle\", message: \"\", text: \"\"}\nconst IDLE_FIRMWARE: NeuralBandFirmwareStatus = {\n known: false,\n connected: false,\n hasMetaSession: false,\n checked: false,\n updateAvailable: false,\n phase: \"idle\",\n progress: 0,\n message: \"\",\n}\n\nexport class NeuralBandInput {\n private latestClaim: NeuralBandClaimStatus = IDLE_CLAIM\n private claims = new Map<string, NeuralBandClaimStatus>()\n private handwriting = new Map<string, NeuralBandHandwritingStatus>()\n private firmware = new Map<string, NeuralBandFirmwareStatus>()\n private claimListeners = new Set<(status: NeuralBandClaimStatus) => void>()\n private handwritingListeners = new Set<(update: NeuralBandHandwritingUpdate) => void>()\n private firmwareListeners = new Set<(update: {id: string; status: NeuralBandFirmwareStatus}) => void>()\n private readonly forward: (stream: string, payload: unknown) => void\n private readonly now: () => number\n\n constructor(options: NeuralBandInputOptions = {}) {\n this.forward = options.forward ?? ((stream, payload) => localMiniappRuntime.forwardEvent(stream, payload))\n this.now = options.now ?? (() => Date.now())\n }\n\n /** One band's claim, or the latest claim of any band without an id. */\n claimStatus(controllerId?: string): NeuralBandClaimStatus {\n if (controllerId === undefined) return this.latestClaim\n return this.claims.get(controllerId) ?? IDLE_CLAIM\n }\n\n onClaimStatus(cb: (status: NeuralBandClaimStatus) => void): () => void {\n this.claimListeners.add(cb)\n return () => this.claimListeners.delete(cb)\n }\n\n handwritingStatus(controllerId: string): NeuralBandHandwritingStatus {\n return this.handwriting.get(controllerId) ?? IDLE_HANDWRITING\n }\n\n onHandwritingStatus(cb: (update: NeuralBandHandwritingUpdate) => void): () => void {\n this.handwritingListeners.add(cb)\n return () => this.handwritingListeners.delete(cb)\n }\n\n firmwareStatus(controllerId: string): NeuralBandFirmwareStatus {\n return this.firmware.get(controllerId) ?? IDLE_FIRMWARE\n }\n\n onFirmwareStatus(cb: (update: {id: string; status: NeuralBandFirmwareStatus}) => void): () => void {\n this.firmwareListeners.add(cb)\n return () => this.firmwareListeners.delete(cb)\n }\n\n /** A new pairing attempt starts from a clean slate. */\n resetClaim(): void {\n this.latestClaim = IDLE_CLAIM\n for (const cb of this.claimListeners) cb(IDLE_CLAIM)\n }\n\n /** Drop an unpaired band's state. */\n forget(controllerId: string): void {\n this.claims.delete(controllerId)\n this.handwriting.delete(controllerId)\n this.firmware.delete(controllerId)\n }\n\n handleFirmware(event: NeuralBandFirmwareEvent): void {\n const {type: _type, controllerId, ...rest} = event\n const status: NeuralBandFirmwareStatus = {...rest, known: true}\n this.firmware.set(controllerId, status)\n for (const cb of this.firmwareListeners) cb({id: controllerId, status})\n }\n\n handleClaim(event: NeuralBandClaimEvent): void {\n const status: NeuralBandClaimStatus = {\n stage: event.stage,\n message: event.message,\n sessionExpired: event.sessionExpired === true,\n bandName: event.bandName,\n controllerId: event.controllerId,\n }\n if (event.controllerId) this.claims.set(event.controllerId, status)\n this.latestClaim = status\n for (const cb of this.claimListeners) cb(status)\n }\n\n handleHandwriting(event: NeuralBandHandwritingEvent): void {\n const id = event.controllerId\n const current = this.handwritingStatus(id)\n if (event.kind === \"state\") {\n const text = event.phase === \"preparing\" ? \"\" : current.text\n this.setHandwriting(id, {phase: event.phase, message: event.message, problem: event.problem, text})\n return\n }\n if (event.text !== current.text) {\n for (const key of keyEventsForTextChange(current.text, event.text, this.now())) {\n this.forward(MiniappStreamType.KEYBOARD_EVENT, key)\n }\n }\n this.setHandwriting(id, {...current, text: event.text})\n }\n\n handlePointer(event: NeuralBandPointerEvent): void {\n if (event.kind === \"move\") {\n this.forward(MiniappStreamType.POINTER_EVENT, {\n kind: \"move\",\n dx: event.dx,\n dy: event.dy,\n timestamp: event.timestamp,\n controllerId: event.controllerId,\n })\n } else {\n this.forward(MiniappStreamType.POINTER_EVENT, {\n kind: \"buttons\",\n buttons: event.buttons,\n timestamp: event.timestamp,\n controllerId: event.controllerId,\n })\n }\n }\n\n private setHandwriting(id: string, status: NeuralBandHandwritingStatus): void {\n this.handwriting.set(id, status)\n for (const cb of this.handwritingListeners) cb({id, status})\n }\n}\n\nconst neuralBandInput = new NeuralBandInput()\nexport default neuralBandInput\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NeuralBandSettingsSync.d.ts","sourceRoot":"","sources":["../../../src/services/neuralBand/NeuralBandSettingsSync.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"NeuralBandSettingsSync.d.ts","sourceRoot":"","sources":["../../../src/services/neuralBand/NeuralBandSettingsSync.ts"],"names":[],"mappings":"AAqEA,wBAAgB,2BAA2B,IAAI,IAAI,CAgClD;AAED,wBAAgB,0BAA0B,IAAI,IAAI,CAIjD"}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pushes the Neural Band user settings (air mouse, wearing hand) to
|
|
3
|
-
* connected band: to each band as it connects, and to all of them
|
|
4
|
-
*
|
|
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
|
import { useGlassesStore } from "../../stores/glasses";
|
|
8
10
|
import { SETTINGS, useSettingsStore } from "../../stores/settings";
|
|
9
11
|
import { ControllerTypes } from "../../types/enums";
|
|
12
|
+
import { BgTimer } from "../../utils/timers";
|
|
10
13
|
import { readyControllers } from "../controllers";
|
|
14
|
+
import localMiniappRuntime from "../LocalMiniappRuntime";
|
|
15
|
+
import { HandwritingGate } from "./HandwritingGate";
|
|
16
|
+
import neuralBandInput from "./NeuralBandInput";
|
|
11
17
|
let unsubscribers = [];
|
|
18
|
+
let handwriting = null;
|
|
12
19
|
function connectedBandIds() {
|
|
13
20
|
return readyControllers(useGlassesStore.getState().controllers)
|
|
14
21
|
.filter((status) => status.model === ControllerTypes.NEURAL_BAND)
|
|
@@ -22,11 +29,33 @@ function pushHand(id) {
|
|
|
22
29
|
const hand = useSettingsStore.getState().getSetting(SETTINGS.neural_band_hand.key) === "left" ? "left" : "right";
|
|
23
30
|
void BluetoothSdk.neuralBandSetHand(id, hand).catch((err) => console.warn("NeuralBandSettingsSync: hand push failed:", err));
|
|
24
31
|
}
|
|
32
|
+
function pushVibration(id) {
|
|
33
|
+
const enabled = useSettingsStore.getState().getSetting(SETTINGS.neural_band_vibration.key) !== false;
|
|
34
|
+
void BluetoothSdk.neuralBandSetGestureHaptics(id, enabled).catch((err) => console.warn("NeuralBandSettingsSync: vibration push failed:", err));
|
|
35
|
+
}
|
|
36
|
+
function startHandwritingGate() {
|
|
37
|
+
const gate = new HandwritingGate({
|
|
38
|
+
enabled: () => useSettingsStore.getState().getSetting(SETTINGS.neural_band_handwriting.key) !== false,
|
|
39
|
+
textFieldOpen: () => localMiniappRuntime.hasOpenTextField(),
|
|
40
|
+
setHandwriting: (id, enabled) => BluetoothSdk.neuralBandSetHandwriting(id, enabled),
|
|
41
|
+
setTimeout: (fn, ms) => BgTimer.setTimeout(fn, ms),
|
|
42
|
+
clearTimeout: (handle) => BgTimer.clearTimeout(handle),
|
|
43
|
+
});
|
|
44
|
+
handwriting = gate;
|
|
45
|
+
gate.setBands(connectedBandIds());
|
|
46
|
+
return [
|
|
47
|
+
useSettingsStore.subscribe((s) => s.getSetting(SETTINGS.neural_band_handwriting.key), () => gate.update()),
|
|
48
|
+
localMiniappRuntime.onTextFieldChange(() => gate.update()),
|
|
49
|
+
neuralBandInput.onHandwritingStatus(({ id, status }) => gate.status(id, status.phase)),
|
|
50
|
+
() => gate.dispose(),
|
|
51
|
+
];
|
|
52
|
+
}
|
|
25
53
|
export function startNeuralBandSettingsSync() {
|
|
26
54
|
if (unsubscribers.length > 0)
|
|
27
55
|
return;
|
|
28
56
|
let connected = new Set(connectedBandIds());
|
|
29
57
|
unsubscribers = [
|
|
58
|
+
...startHandwritingGate(),
|
|
30
59
|
useGlassesStore.subscribe(() => connectedBandIds().sort().join(","), () => {
|
|
31
60
|
const next = new Set(connectedBandIds());
|
|
32
61
|
for (const id of next) {
|
|
@@ -34,16 +63,20 @@ export function startNeuralBandSettingsSync() {
|
|
|
34
63
|
continue;
|
|
35
64
|
pushAirMouse(id);
|
|
36
65
|
pushHand(id);
|
|
66
|
+
pushVibration(id);
|
|
37
67
|
}
|
|
38
68
|
connected = next;
|
|
69
|
+
handwriting?.setBands([...next]);
|
|
39
70
|
}),
|
|
40
71
|
useSettingsStore.subscribe((s) => s.getSetting(SETTINGS.neural_band_air_mouse.key), () => connectedBandIds().forEach(pushAirMouse)),
|
|
41
72
|
useSettingsStore.subscribe((s) => s.getSetting(SETTINGS.neural_band_hand.key), () => connectedBandIds().forEach(pushHand)),
|
|
73
|
+
useSettingsStore.subscribe((s) => s.getSetting(SETTINGS.neural_band_vibration.key), () => connectedBandIds().forEach(pushVibration)),
|
|
42
74
|
];
|
|
43
75
|
}
|
|
44
76
|
export function stopNeuralBandSettingsSync() {
|
|
45
77
|
for (const unsubscribe of unsubscribers)
|
|
46
78
|
unsubscribe();
|
|
47
79
|
unsubscribers = [];
|
|
80
|
+
handwriting = null;
|
|
48
81
|
}
|
|
49
82
|
//# sourceMappingURL=NeuralBandSettingsSync.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NeuralBandSettingsSync.js","sourceRoot":"","sources":["../../../src/services/neuralBand/NeuralBandSettingsSync.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"NeuralBandSettingsSync.js","sourceRoot":"","sources":["../../../src/services/neuralBand/NeuralBandSettingsSync.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pushes the Neural Band user settings (air mouse, wearing hand, vibration) to\n * every connected band: to each band as it connects, and to all of them\n * whenever a setting changes. The native side keeps nothing across\n * connections. Handwriting is gated, not pushed: HandwritingGate runs it while\n * the setting is on and a miniapp has a text field open.\n */\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\n\nimport {useGlassesStore} from \"../../stores/glasses\"\nimport {SETTINGS, useSettingsStore} from \"../../stores/settings\"\nimport {ControllerTypes} from \"../../types/enums\"\nimport {BgTimer} from \"../../utils/timers\"\nimport {readyControllers} from \"../controllers\"\nimport localMiniappRuntime from \"../LocalMiniappRuntime\"\nimport {HandwritingGate} from \"./HandwritingGate\"\nimport neuralBandInput from \"./NeuralBandInput\"\n\nlet unsubscribers: (() => void)[] = []\nlet handwriting: HandwritingGate | null = null\n\nfunction connectedBandIds(): string[] {\n return readyControllers(useGlassesStore.getState().controllers)\n .filter((status) => status.model === ControllerTypes.NEURAL_BAND)\n .map((status) => status.id)\n}\n\nfunction pushAirMouse(id: string): void {\n const enabled = useSettingsStore.getState().getSetting(SETTINGS.neural_band_air_mouse.key) === true\n void BluetoothSdk.neuralBandSetPointer(id, enabled).catch((err) =>\n console.warn(\"NeuralBandSettingsSync: air mouse push failed:\", err),\n )\n}\n\nfunction pushHand(id: string): void {\n const hand = useSettingsStore.getState().getSetting(SETTINGS.neural_band_hand.key) === \"left\" ? \"left\" : \"right\"\n void BluetoothSdk.neuralBandSetHand(id, hand).catch((err) =>\n console.warn(\"NeuralBandSettingsSync: hand push failed:\", err),\n )\n}\n\nfunction pushVibration(id: string): void {\n const enabled = useSettingsStore.getState().getSetting(SETTINGS.neural_band_vibration.key) !== false\n void BluetoothSdk.neuralBandSetGestureHaptics(id, enabled).catch((err) =>\n console.warn(\"NeuralBandSettingsSync: vibration push failed:\", err),\n )\n}\n\nfunction startHandwritingGate(): (() => void)[] {\n const gate = new HandwritingGate({\n enabled: () => useSettingsStore.getState().getSetting(SETTINGS.neural_band_handwriting.key) !== false,\n textFieldOpen: () => localMiniappRuntime.hasOpenTextField(),\n setHandwriting: (id, enabled) => BluetoothSdk.neuralBandSetHandwriting(id, enabled),\n setTimeout: (fn, ms) => BgTimer.setTimeout(fn, ms),\n clearTimeout: (handle) => BgTimer.clearTimeout(handle as number),\n })\n handwriting = gate\n gate.setBands(connectedBandIds())\n return [\n useSettingsStore.subscribe(\n (s) => s.getSetting(SETTINGS.neural_band_handwriting.key),\n () => gate.update(),\n ),\n localMiniappRuntime.onTextFieldChange(() => gate.update()),\n neuralBandInput.onHandwritingStatus(({id, status}) => gate.status(id, status.phase)),\n () => gate.dispose(),\n ]\n}\n\nexport function startNeuralBandSettingsSync(): void {\n if (unsubscribers.length > 0) return\n let connected = new Set(connectedBandIds())\n unsubscribers = [\n ...startHandwritingGate(),\n useGlassesStore.subscribe(\n () => connectedBandIds().sort().join(\",\"),\n () => {\n const next = new Set(connectedBandIds())\n for (const id of next) {\n if (connected.has(id)) continue\n pushAirMouse(id)\n pushHand(id)\n pushVibration(id)\n }\n connected = next\n handwriting?.setBands([...next])\n },\n ),\n useSettingsStore.subscribe(\n (s) => s.getSetting(SETTINGS.neural_band_air_mouse.key),\n () => connectedBandIds().forEach(pushAirMouse),\n ),\n useSettingsStore.subscribe(\n (s) => s.getSetting(SETTINGS.neural_band_hand.key),\n () => connectedBandIds().forEach(pushHand),\n ),\n useSettingsStore.subscribe(\n (s) => s.getSetting(SETTINGS.neural_band_vibration.key),\n () => connectedBandIds().forEach(pushVibration),\n ),\n ]\n}\n\nexport function stopNeuralBandSettingsSync(): void {\n for (const unsubscribe of unsubscribers) unsubscribe()\n unsubscribers = []\n handwriting = null\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appVisibility.d.ts","sourceRoot":"","sources":["../../src/stores/appVisibility.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,eAAO,MAAM,eAAe,GAAI,KAAK;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,KAAG,OAC/B,CAAA;AAEzC,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,GAAI,gBAAgB,OAAO,EAAE,YAAY,OAAO,KAAG,OACrD,CAAA;AAE9B;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAA2D,CAAA;AAEnH,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,GAAI,aAAa,MAAM,KAAG,OAAmD,CAAA;AAE7G;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"appVisibility.d.ts","sourceRoot":"","sources":["../../src/stores/appVisibility.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,eAAO,MAAM,eAAe,GAAI,KAAK;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,KAAG,OAC/B,CAAA;AAEzC,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,GAAI,gBAAgB,OAAO,EAAE,YAAY,OAAO,KAAG,OACrD,CAAA;AAE9B;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAA2D,CAAA;AAEnH,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,GAAI,aAAa,MAAM,KAAG,OAAmD,CAAA;AAE7G;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAKjD,CAAA;AAEF,iEAAiE;AACjE,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,EAAE,iBAAiB,OAAO,KAAG,OACzB,CAAA;AAEzD;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAAkC,CAAA;AAE1F,uFAAuF;AACvF,eAAO,MAAM,kBAAkB,GAC7B,aAAa,MAAM,EACnB,iBAAiB,OAAO,EACxB,kBAAkB,OAAO,KACxB,OAA4F,CAAA"}
|
|
@@ -22,7 +22,6 @@ export const DEV_TOOLS_PACKAGES = new Set([
|
|
|
22
22
|
"com.glassly.example",
|
|
23
23
|
"com.glassly.tetris",
|
|
24
24
|
"com.glassly.compass",
|
|
25
|
-
"com.glassly.showcase",
|
|
26
25
|
]);
|
|
27
26
|
/** True when the app is dev-only and developer tools are off. */
|
|
28
27
|
export const isGatedByDevTools = (packageName, devToolsEnabled) => !devToolsEnabled && DEV_TOOLS_PACKAGES.has(packageName);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appVisibility.js","sourceRoot":"","sources":["../../src/stores/appVisibility.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAqC,EAAW,EAAE,CAChF,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,CAAA;AAEzC,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,cAAuB,EAAE,UAAmB,EAAW,EAAE,CAC3F,cAAc,IAAI,UAAU,CAAA;AAE9B;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAwB,IAAI,GAAG,CAAC,CAAC,oBAAoB,EAAE,sBAAsB,CAAC,CAAC,CAAA;AAEnH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,WAAmB,EAAW,EAAE,CAAC,uBAAuB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;AAE7G;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAC;IAC7D,wBAAwB;IACxB,qBAAqB;IACrB,oBAAoB;IACpB,qBAAqB;
|
|
1
|
+
{"version":3,"file":"appVisibility.js","sourceRoot":"","sources":["../../src/stores/appVisibility.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAqC,EAAW,EAAE,CAChF,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,CAAA;AAEzC,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,cAAuB,EAAE,UAAmB,EAAW,EAAE,CAC3F,cAAc,IAAI,UAAU,CAAA;AAE9B;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAwB,IAAI,GAAG,CAAC,CAAC,oBAAoB,EAAE,sBAAsB,CAAC,CAAC,CAAA;AAEnH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,WAAmB,EAAW,EAAE,CAAC,uBAAuB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;AAE7G;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAC;IAC7D,wBAAwB;IACxB,qBAAqB;IACrB,oBAAoB;IACpB,qBAAqB;CACtB,CAAC,CAAA;AAEF,iEAAiE;AACjE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,WAAmB,EAAE,eAAwB,EAAW,EAAE,CAC1F,CAAC,eAAe,IAAI,kBAAkB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;AAEzD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAwB,IAAI,GAAG,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAA;AAE1F,uFAAuF;AACvF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,WAAmB,EACnB,eAAwB,EACxB,gBAAyB,EAChB,EAAE,CAAC,CAAC,eAAe,IAAI,CAAC,gBAAgB,IAAI,uBAAuB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA","sourcesContent":["/** Host built-in phone pages and dashboard-type miniapps: never launched from a glasses menu. */\nexport const isSystemMiniapp = (app: {offline: boolean; type: string}): boolean =>\n app.offline || app.type === \"dashboard\"\n\n/** Combine registry-enforced visibility with the user's home-screen choice. */\nexport const resolveHiddenStatus = (registryHidden: boolean, userHidden: boolean): boolean =>\n registryHidden || userHidden\n\n/**\n * Miniapps that start off the primary home screen. They stay listed under\n * \"view all apps\", where \"Add to Home\" saves an explicit choice that wins\n * over this default from then on.\n */\nexport const DEFAULT_HIDDEN_PACKAGES: ReadonlySet<string> = new Set([\"com.glassly.camera\", \"com.glassly.recorder\"])\n\n/** The home-screen visibility of an app the user has never hidden or added. */\nexport const defaultHiddenStatus = (packageName: string): boolean => DEFAULT_HIDDEN_PACKAGES.has(packageName)\n\n/**\n * Miniapps that exist only for developers: the Miniapp Developer launcher and\n * the bundled sample/test miniapps. They are projected into the app store\n * only while the `dev_tools` setting is on; off, they are absent from every\n * launcher surface (home, all apps, glasses menu, AI listing), not merely\n * hidden from the primary home screen.\n */\nexport const DEV_TOOLS_PACKAGES: ReadonlySet<string> = new Set([\n \"com.glassly.miniappdev\",\n \"com.glassly.example\",\n \"com.glassly.tetris\",\n \"com.glassly.compass\",\n])\n\n/** True when the app is dev-only and developer tools are off. */\nexport const isGatedByDevTools = (packageName: string, devToolsEnabled: boolean): boolean =>\n !devToolsEnabled && DEV_TOOLS_PACKAGES.has(packageName)\n\n/**\n * Miniapps that unlock once a real pair of glasses has been paired on this\n * phone (`has_paired_glasses`, latched by PairedGlassesLatch and never\n * cleared, so forgetting the glasses keeps them). Developer tools open them\n * early. Until either, they are absent from every launcher surface like the\n * dev-only set above.\n */\nexport const PAIRED_GLASSES_PACKAGES: ReadonlySet<string> = new Set([\"com.glassly.store\"])\n\n/** True when the app waits on a pairing that hasn't happened and dev tools are off. */\nexport const isGatedUntilPaired = (\n packageName: string,\n devToolsEnabled: boolean,\n hasPairedGlasses: boolean,\n): boolean => !devToolsEnabled && !hasPairedGlasses && PAIRED_GLASSES_PACKAGES.has(packageName)\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/stores/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAwB,MAAM,aAAa,CAAA;AAS9D,OAAO,EAAC,wBAAwB,EAAE,gCAAgC,EAAC,MAAM,wBAAwB,CAAA;AAEjG,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,YAAY,EAAE,MAAM,GAAG,CAAA;IACvB,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,OAAO,CAAA;IAGrB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAEjC,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAA;IAEpB,OAAO,EAAE,OAAO,CAAA;IAQhB,mBAAmB,CAAC,EAAE,IAAI,CAAA;IAC1B;;;;;;;;;;;;;;;OAeG;IACH,qBAAqB,CAAC,EAAE,IAAI,CAAA;CAC7B;AAKD,eAAO,MAAM,uBAAuB,IAAI,CAAA;AAExC,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/stores/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAwB,MAAM,aAAa,CAAA;AAS9D,OAAO,EAAC,wBAAwB,EAAE,gCAAgC,EAAC,MAAM,wBAAwB,CAAA;AAEjG,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,YAAY,EAAE,MAAM,GAAG,CAAA;IACvB,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,OAAO,CAAA;IAGrB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAEjC,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAA;IAEpB,OAAO,EAAE,OAAO,CAAA;IAQhB,mBAAmB,CAAC,EAAE,IAAI,CAAA;IAC1B;;;;;;;;;;;;;;;OAeG;IACH,qBAAqB,CAAC,EAAE,IAAI,CAAA;CAC7B;AAKD,eAAO,MAAM,uBAAuB,IAAI,CAAA;AAExC,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAypCnC,CAAA;AAEV,eAAO,MAAM,eAAe,EAAE,MAAM,EAAuD,CAAA;AAI3F,eAAO,MAAM,sBAAsB,EAAE,MAAM,EA4D1C,CAAA;AAeD,eAAO,MAAM,qBAAqB,EAAE,MAAM,EAEV,CAAA;AAIhC,MAAM,WAAW,aAAa;IAE5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAE7B,aAAa,EAAE,OAAO,CAAA;IAEtB,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,YAAY,CAAC,EAAE,OAAO,KAAK,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACzF,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAC3E,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,GAAG,CAAA;IAEhC,eAAe,EAAE,MAAM,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAE/C,oBAAoB,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC/C,uBAAuB,EAAE,MAAM,IAAI,CAAA;CACpC;AAuBD,eAAO,MAAM,gBAAgB;;;;;;;;EAsX5B,CAAA;AAED,eAAO,MAAM,UAAU,GAAI,CAAC,GAAG,GAAG,EAAE,KAAK,MAAM,KAAG,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAI3F,CAAA"}
|
package/build/stores/settings.js
CHANGED
|
@@ -804,6 +804,24 @@ export const SETTINGS = {
|
|
|
804
804
|
saveOnServer: false,
|
|
805
805
|
persist: true,
|
|
806
806
|
},
|
|
807
|
+
// Meta Neural Band handwriting typing into miniapps. Enabled means the band runs
|
|
808
|
+
// its handwriting model while a miniapp has a text field open on the glasses
|
|
809
|
+
// (HandwritingGate); the model streams the whole time it runs, so never otherwise.
|
|
810
|
+
neural_band_handwriting: {
|
|
811
|
+
key: "neural_band_handwriting",
|
|
812
|
+
defaultValue: () => true,
|
|
813
|
+
writable: true,
|
|
814
|
+
saveOnServer: false,
|
|
815
|
+
persist: true,
|
|
816
|
+
},
|
|
817
|
+
// The band's own buzz on each gesture (its haptics pattern 1; pattern 2 is silent).
|
|
818
|
+
neural_band_vibration: {
|
|
819
|
+
key: "neural_band_vibration",
|
|
820
|
+
defaultValue: () => true,
|
|
821
|
+
writable: true,
|
|
822
|
+
saveOnServer: false,
|
|
823
|
+
persist: true,
|
|
824
|
+
},
|
|
807
825
|
// Watch (Apple Watch, Wear OS): draw the glasses' current frame behind the watch
|
|
808
826
|
// trackpad. Frames cross the watch link while the watch app is up, so it stays off
|
|
809
827
|
// unless asked for.
|