@glassly/engine 0.3.7-beta.934 → 0.3.7-beta.966

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 (57) hide show
  1. package/build/generated/releaseMetadata.js +3 -3
  2. package/build/generated/releaseMetadata.js.map +1 -1
  3. package/build/services/BlobStore.d.ts.map +1 -1
  4. package/build/services/BlobStore.js +5 -12
  5. package/build/services/BlobStore.js.map +1 -1
  6. package/build/services/DisplayProcessor.d.ts.map +1 -1
  7. package/build/services/DisplayProcessor.js +3 -1
  8. package/build/services/DisplayProcessor.js.map +1 -1
  9. package/build/services/GlassesTouchInput.d.ts.map +1 -1
  10. package/build/services/GlassesTouchInput.js +4 -2
  11. package/build/services/GlassesTouchInput.js.map +1 -1
  12. package/build/services/PhoneCalendarService.d.ts.map +1 -1
  13. package/build/services/PhoneCalendarService.js +8 -0
  14. package/build/services/PhoneCalendarService.js.map +1 -1
  15. package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
  16. package/build/services/PhoneNotificationsSync.js +7 -3
  17. package/build/services/PhoneNotificationsSync.js.map +1 -1
  18. package/build/services/controllers.d.ts.map +1 -1
  19. package/build/services/controllers.js +1 -0
  20. package/build/services/controllers.js.map +1 -1
  21. package/build/services/pages/pageEligibility.d.ts.map +1 -1
  22. package/build/services/pages/pageEligibility.js +8 -1
  23. package/build/services/pages/pageEligibility.js.map +1 -1
  24. package/build/types/capabilities/memomind-one.d.ts +3 -0
  25. package/build/types/capabilities/memomind-one.d.ts.map +1 -0
  26. package/build/types/capabilities/memomind-one.js +41 -0
  27. package/build/types/capabilities/memomind-one.js.map +1 -0
  28. package/build/types/enums.d.ts +4 -2
  29. package/build/types/enums.d.ts.map +1 -1
  30. package/build/types/enums.js +2 -0
  31. package/build/types/enums.js.map +1 -1
  32. package/build/types/hardware.d.ts +3 -1
  33. package/build/types/hardware.d.ts.map +1 -1
  34. package/build/types/hardware.js +3 -1
  35. package/build/types/hardware.js.map +1 -1
  36. package/build/utils/display/index.d.ts +1 -0
  37. package/build/utils/display/index.d.ts.map +1 -1
  38. package/build/utils/display/index.js +1 -0
  39. package/build/utils/display/index.js.map +1 -1
  40. package/build/utils/display/profiles/index.d.ts +1 -0
  41. package/build/utils/display/profiles/index.d.ts.map +1 -1
  42. package/build/utils/display/profiles/index.js +1 -0
  43. package/build/utils/display/profiles/index.js.map +1 -1
  44. package/package.json +7 -7
  45. package/src/generated/releaseMetadata.ts +3 -3
  46. package/src/services/BlobStore.ts +5 -11
  47. package/src/services/DisplayProcessor.ts +5 -8
  48. package/src/services/GlassesTouchInput.ts +6 -2
  49. package/src/services/PhoneCalendarService.ts +7 -0
  50. package/src/services/PhoneNotificationsSync.ts +8 -3
  51. package/src/services/controllers.ts +1 -0
  52. package/src/services/pages/pageEligibility.ts +9 -1
  53. package/src/types/capabilities/memomind-one.ts +42 -0
  54. package/src/types/enums.ts +2 -0
  55. package/src/types/hardware.ts +14 -1
  56. package/src/utils/display/index.ts +2 -0
  57. package/src/utils/display/profiles/index.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"hardware.js","sourceRoot":"","sources":["../../src/types/hardware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAC,eAAe,EAAC,MAAM,kCAAkC,CAAA;AAChE,OAAO,EAAC,eAAe,EAAC,MAAM,kCAAkC,CAAA;AAChE,OAAO,EAAC,aAAa,EAAC,MAAM,+BAA+B,CAAA;AAC3D,OAAO,EAAC,UAAU,EAAC,MAAM,4BAA4B,CAAA;AACrD,OAAO,EAAC,gBAAgB,EAAC,MAAM,kCAAkC,CAAA;AACjE,OAAO,EAAC,IAAI,EAAC,MAAM,qBAAqB,CAAA;AACxC,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAA;AACjD,OAAO,EAAC,SAAS,EAAC,MAAM,2BAA2B,CAAA;AACnD,OAAO,EAAC,IAAI,EAAC,MAAM,qBAAqB,CAAA;AACxC,OAAO,EAAC,WAAW,EAAC,MAAM,SAAS,CAAA;AA2EnC,oEAAoE;AACpE,MAAM,CAAC,MAAM,kBAAkB,GAAmB,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAA;AAuIxH;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAiC;IACjE,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,eAAe;IAC5C,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,eAAe;IAC5C,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,aAAa;IACxC,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,UAAU;IAClC,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE,gBAAgB;IAC9C,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,SAAS;IAChC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI;IACtB,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ;IAC9B,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,mDAAmD;IACnF,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE;QAClB,GAAG,eAAe;QAClB,SAAS,EAAE,WAAW,CAAC,IAAI;QAC3B,OAAO,EAAE;YACP,GAAG,eAAe,CAAC,OAAO;YAC1B,gBAAgB,EAAE,KAAK;YACvB,+CAA+C;YAC/C,aAAa,EAAE,SAAS;SACzB;QACD,aAAa,EAAE,IAAI;QACnB,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE;YACV,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,KAAK;SACd;KACF;IACD,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI;CACvB,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,UAAuB,EAAgB,EAAE;IAC5E,MAAM,SAAS,GAAG,UAAoB,CAAA;IACtC,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,EAAE,CAAC;QACtC,OAAO,qBAAqB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IAChD,CAAC;IACD,OAAO,qBAAqB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC,CAAA;AAED,iCAAiC;AACjC,OAAO,EAAC,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAC,CAAA","sourcesContent":["/**\n * Hardware capability types\n */\n\nimport {evenRealitiesG1} from \"./capabilities/even-realities-g1\"\nimport {evenRealitiesG2} from \"./capabilities/even-realities-g2\"\nimport {mentraDisplay} from \"./capabilities/mentra-display\"\nimport {mentraLive} from \"./capabilities/mentra-live\"\nimport {simulatedGlasses} from \"./capabilities/simulated-glasses\"\nimport {nimo} from \"./capabilities/nimo\"\nimport {rayneoIO} from \"./capabilities/rayneo-io\"\nimport {vuzixZ100} from \"./capabilities/vuzix-z100\"\nimport {none} from \"./capabilities/none\"\nimport {DeviceTypes} from \"./enums\"\n\n// Canonical def lives in @glassly/miniapp; re-exported for engine consumers.\nexport type {HardwareRequirement} from \"@glassly/miniapp/hardware\"\n\n/**\n * Camera capabilities\n */\nexport interface CameraCapabilities {\n resolution?: {width: number; height: number}\n hasHDR?: boolean\n hasFocus?: boolean\n video: {\n canRecord: boolean\n canStream: boolean\n supportedStreamTypes?: string[]\n supportedResolutions?: {width: number; height: number}[]\n }\n}\n\nexport interface LevelRange {\n min: number\n max: number\n}\n\n/**\n * Display capabilities\n */\nexport interface DisplayCapabilities {\n count?: number\n isColor?: boolean\n color?: string // e.g., \"green\", \"full_color\", \"pallet\"\n canDisplayBitmap?: boolean\n resolution?: {width: number; height: number}\n fieldOfView?: {horizontal?: number; vertical?: number}\n maxTextLines?: number\n adjustBrightness?: boolean\n /** The `dashboard_height` / `dashboard_depth` steps the glasses accept, inclusive; absent ⇒ no position control. */\n positionRange?: {height: LevelRange; depth: LevelRange}\n\n // --- Scene display API (display.render()) — typed capabilities ---\n // Pure DATA the host scene pipeline acts on generically; a device without\n // canPosition renders scenes via the host degrade path instead.\n /** Public drawable canvas in px — the raw coordinate space for render() boxes. */\n width?: number\n height?: number\n /** True ⇒ the device renders positioned elements (containers / canvas components). */\n canPosition?: boolean\n /** Element budgets. Rects share the text pool on container-based devices. */\n maxTextElements?: number\n maxImageElements?: number\n /** Per-image dimension cap (box-level), when the firmware has one. */\n maxImagePx?: {width: number; height: number}\n shapes?: DisplayShape[]\n /** True ⇒ the device animates element transitions itself. */\n animation?: boolean\n /** Geometric and SVG rotations, including duration-based transitions. */\n rotation?: boolean\n /** Per-element stereo `depth` (a lens disparity) is honored; otherwise elements draw flat. */\n depth?: boolean\n intensityLevels?: number\n\n partialUpdate?: boolean\n /**\n * The views a miniapp may draw right now: \"main\" for every app, \"dashboard\"\n * (the overlay slot) only for the designated system dashboard app while the\n * glasses are eligible. Per app; filled in by the miniapp runtime.\n */\n views?: DisplayView[]\n}\n\nexport type DisplayView = \"main\" | \"dashboard\"\n\nexport type DisplayShape = \"rect\" | \"circle\" | \"arc\" | \"pie\" | \"line\" | \"triangle\" | \"quad\" | \"bezier\" | \"svg\"\n\n/** Every vector shape the Glassly CFW rasterizes on the glasses. */\nexport const ALL_DISPLAY_SHAPES: DisplayShape[] = [\"rect\", \"circle\", \"arc\", \"pie\", \"line\", \"triangle\", \"quad\", \"bezier\"]\n\n/**\n * Microphone capabilities\n */\nexport interface MicrophoneCapabilities {\n count?: number\n hasVAD?: boolean // Voice Activity Detection\n // The connected firmware can stop streaming audio below a volume floor\n // (G2 Glassly CFW revision 40+). Never set on a model profile: it is\n // reported at runtime and layered on by getEffectiveCapabilities.\n volumeGate?: boolean\n}\n\n/**\n * Speaker capabilities\n */\nexport interface SpeakerCapabilities {\n count?: number\n isPrivate?: boolean // e.g., bone conduction\n}\n\n/**\n * IMU (Inertial Measurement Unit) capabilities\n */\nexport interface IMUCapabilities {\n axisCount?: number\n hasAccelerometer?: boolean\n hasCompass?: boolean\n hasGyroscope?: boolean\n}\n\n/**\n * Button capabilities\n */\nexport interface ButtonCapabilities {\n count?: number\n buttons?: {\n type: \"press\" | \"swipe1d\" | \"swipe2d\"\n events: string[] // e.g., \"press\", \"double_press\", \"long_press\", \"swipe_up\", \"swipe_down\"\n isCapacitive?: boolean\n }[]\n}\n\n/**\n * Light capabilities\n */\nexport interface LightCapabilities {\n count?: number\n lights?: {\n id: string // Unique identifier for the LED (e.g., \"privacy\", \"user_feedback\")\n purpose: \"privacy\" | \"user_feedback\" | \"general\" // LED purpose/function\n isFullColor: boolean\n color?: string // e.g., \"white\", \"rgb\"\n position?: \"front_facing\" | \"user_facing\" | \"side\" | \"unknown\" // LED physical position\n }[]\n}\n\n/**\n * Power capabilities\n */\nexport interface PowerCapabilities {\n hasExternalBattery: boolean // e.g., a case or puck\n}\n\n/**\n * Device hardware capabilities\n * Complete information about what hardware a device has\n */\nexport interface Capabilities {\n modelName: string\n\n // Camera capabilities\n hasCamera: boolean\n camera: CameraCapabilities | null\n\n // Display capabilities\n hasDisplay: boolean\n display: DisplayCapabilities | null\n\n // Microphone capabilities\n hasMicrophone: boolean\n microphone: MicrophoneCapabilities | null\n\n // Speaker capabilities\n hasSpeaker: boolean\n speaker: SpeakerCapabilities | null\n\n // IMU capabilities\n hasIMU: boolean\n imu: IMUCapabilities | null\n\n // Button capabilities\n hasButton: boolean\n button: ButtonCapabilities | null\n\n // Light capabilities\n hasLight: boolean\n light: LightCapabilities | null\n\n // Power capabilities\n power: PowerCapabilities\n\n // WiFi capability\n hasWifi: boolean\n\n // OTA capability\n hasOta?: boolean\n\n // True when the app ships a flashable Glassly custom firmware for this\n // model, so pairing can offer to install it and Settings exposes the flasher\n hasCustomFirmware?: boolean\n\n // Native dashboard capability\n // True when the device renders its own dashboard in firmware (e.g. Even\n // Realities' built-in dashboard on G2). Glassly does not manage or expose\n // dashboard settings for these devices. Absent/false means Glassly owns the\n // dashboard.\n hasNativeDashboard?: boolean\n\n // True when the device renders its own turn-by-turn nav UI in firmware\n // (G2 nav mode: instruction card + map slots + magnetometer compass); nav\n // apps feed it structured fields and map bitmaps instead of scene elements\n hasNativeNavigation?: boolean\n\n // True when the firmware presents phone notifications itself (popup +\n // history) and takes a GlassesNotificationConfig. How it gets the content\n // (reading the phone's stream, or an upload from the phone) is the driver's\n // business; the engine only decides who presents.\n hasNativeNotifications?: boolean\n // Popup durations the firmware accepts, in seconds (0 = firmware default).\n // Drivers snap other values; the settings UI offers exactly these.\n nativeNotificationPopupSeconds?: number[]\n}\n\n/**\n * Hardware capability profiles for supported glasses models\n * Key: model_name string (e.g., \"Even Realities G1\", \"Mentra Live\")\n * Value: Capabilities object defining device features\n */\nexport const HARDWARE_CAPABILITIES: Record<string, Capabilities> = {\n [evenRealitiesG1.modelName]: evenRealitiesG1,\n [evenRealitiesG2.modelName]: evenRealitiesG2,\n [mentraDisplay.modelName]: mentraDisplay,\n [mentraLive.modelName]: mentraLive,\n [simulatedGlasses.modelName]: simulatedGlasses,\n [vuzixZ100.modelName]: vuzixZ100,\n [nimo.modelName]: nimo,\n [rayneoIO.modelName]: rayneoIO,\n [DeviceTypes.MACH1]: vuzixZ100, // Mach1 uses same Vuzix Ultralite hardware as Z100\n [DeviceTypes.AR99]: {\n ...evenRealitiesG1,\n modelName: DeviceTypes.AR99,\n display: {\n ...evenRealitiesG1.display,\n canDisplayBitmap: false,\n // The AR99 firmware takes no position command.\n positionRange: undefined,\n },\n hasMicrophone: true,\n hasOta: true,\n microphone: {\n count: 1,\n hasVAD: false,\n },\n },\n [none.modelName]: none,\n}\n\nexport const getModelCapabilities = (deviceType: DeviceTypes): Capabilities => {\n const modelName = deviceType as string\n if (!HARDWARE_CAPABILITIES[modelName]) {\n return HARDWARE_CAPABILITIES[DeviceTypes.NONE]\n }\n return HARDWARE_CAPABILITIES[modelName]\n}\n\n// export * from \"./capabilities\"\nexport {simulatedGlasses, evenRealitiesG1, evenRealitiesG2, mentraLive, vuzixZ100, mentraDisplay, nimo, rayneoIO}\n"]}
1
+ {"version":3,"file":"hardware.js","sourceRoot":"","sources":["../../src/types/hardware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAC,eAAe,EAAC,MAAM,kCAAkC,CAAA;AAChE,OAAO,EAAC,eAAe,EAAC,MAAM,kCAAkC,CAAA;AAChE,OAAO,EAAC,aAAa,EAAC,MAAM,+BAA+B,CAAA;AAC3D,OAAO,EAAC,UAAU,EAAC,MAAM,4BAA4B,CAAA;AACrD,OAAO,EAAC,gBAAgB,EAAC,MAAM,kCAAkC,CAAA;AACjE,OAAO,EAAC,IAAI,EAAC,MAAM,qBAAqB,CAAA;AACxC,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAA;AACjD,OAAO,EAAC,WAAW,EAAC,MAAM,6BAA6B,CAAA;AACvD,OAAO,EAAC,SAAS,EAAC,MAAM,2BAA2B,CAAA;AACnD,OAAO,EAAC,IAAI,EAAC,MAAM,qBAAqB,CAAA;AACxC,OAAO,EAAC,WAAW,EAAC,MAAM,SAAS,CAAA;AA2EnC,oEAAoE;AACpE,MAAM,CAAC,MAAM,kBAAkB,GAAmB,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAA;AAwIxH;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAiC;IACjE,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,eAAe;IAC5C,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,eAAe;IAC5C,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,aAAa;IACxC,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,UAAU;IAClC,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE,gBAAgB;IAC9C,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,SAAS;IAChC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI;IACtB,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ;IAC9B,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,WAAW;IACpC,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,mDAAmD;IACnF,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE;QAClB,GAAG,eAAe;QAClB,SAAS,EAAE,WAAW,CAAC,IAAI;QAC3B,OAAO,EAAE;YACP,GAAG,eAAe,CAAC,OAAO;YAC1B,gBAAgB,EAAE,KAAK;YACvB,+CAA+C;YAC/C,aAAa,EAAE,SAAS;SACzB;QACD,aAAa,EAAE,IAAI;QACnB,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE;YACV,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,KAAK;SACd;KACF;IACD,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI;CACvB,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,UAAuB,EAAgB,EAAE;IAC5E,MAAM,SAAS,GAAG,UAAoB,CAAA;IACtC,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,EAAE,CAAC;QACtC,OAAO,qBAAqB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IAChD,CAAC;IACD,OAAO,qBAAqB,CAAC,SAAS,CAAC,CAAA;AACzC,CAAC,CAAA;AAED,iCAAiC;AACjC,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,UAAU,EACV,SAAS,EACT,aAAa,EACb,IAAI,EACJ,QAAQ,EACR,WAAW,GACZ,CAAA","sourcesContent":["/**\n * Hardware capability types\n */\n\nimport {evenRealitiesG1} from \"./capabilities/even-realities-g1\"\nimport {evenRealitiesG2} from \"./capabilities/even-realities-g2\"\nimport {mentraDisplay} from \"./capabilities/mentra-display\"\nimport {mentraLive} from \"./capabilities/mentra-live\"\nimport {simulatedGlasses} from \"./capabilities/simulated-glasses\"\nimport {nimo} from \"./capabilities/nimo\"\nimport {rayneoIO} from \"./capabilities/rayneo-io\"\nimport {memoMindOne} from \"./capabilities/memomind-one\"\nimport {vuzixZ100} from \"./capabilities/vuzix-z100\"\nimport {none} from \"./capabilities/none\"\nimport {DeviceTypes} from \"./enums\"\n\n// Canonical def lives in @glassly/miniapp; re-exported for engine consumers.\nexport type {HardwareRequirement} from \"@glassly/miniapp/hardware\"\n\n/**\n * Camera capabilities\n */\nexport interface CameraCapabilities {\n resolution?: {width: number; height: number}\n hasHDR?: boolean\n hasFocus?: boolean\n video: {\n canRecord: boolean\n canStream: boolean\n supportedStreamTypes?: string[]\n supportedResolutions?: {width: number; height: number}[]\n }\n}\n\nexport interface LevelRange {\n min: number\n max: number\n}\n\n/**\n * Display capabilities\n */\nexport interface DisplayCapabilities {\n count?: number\n isColor?: boolean\n color?: string // e.g., \"green\", \"full_color\", \"pallet\"\n canDisplayBitmap?: boolean\n resolution?: {width: number; height: number}\n fieldOfView?: {horizontal?: number; vertical?: number}\n maxTextLines?: number\n adjustBrightness?: boolean\n /** The `dashboard_height` / `dashboard_depth` steps the glasses accept, inclusive; absent ⇒ no position control. */\n positionRange?: {height: LevelRange; depth: LevelRange}\n\n // --- Scene display API (display.render()) — typed capabilities ---\n // Pure DATA the host scene pipeline acts on generically; a device without\n // canPosition renders scenes via the host degrade path instead.\n /** Public drawable canvas in px — the raw coordinate space for render() boxes. */\n width?: number\n height?: number\n /** True ⇒ the device renders positioned elements (containers / canvas components). */\n canPosition?: boolean\n /** Element budgets. Rects share the text pool on container-based devices. */\n maxTextElements?: number\n maxImageElements?: number\n /** Per-image dimension cap (box-level), when the firmware has one. */\n maxImagePx?: {width: number; height: number}\n shapes?: DisplayShape[]\n /** True ⇒ the device animates element transitions itself. */\n animation?: boolean\n /** Geometric and SVG rotations, including duration-based transitions. */\n rotation?: boolean\n /** Per-element stereo `depth` (a lens disparity) is honored; otherwise elements draw flat. */\n depth?: boolean\n intensityLevels?: number\n\n partialUpdate?: boolean\n /**\n * The views a miniapp may draw right now: \"main\" for every app, \"dashboard\"\n * (the overlay slot) only for the designated system dashboard app while the\n * glasses are eligible. Per app; filled in by the miniapp runtime.\n */\n views?: DisplayView[]\n}\n\nexport type DisplayView = \"main\" | \"dashboard\"\n\nexport type DisplayShape = \"rect\" | \"circle\" | \"arc\" | \"pie\" | \"line\" | \"triangle\" | \"quad\" | \"bezier\" | \"svg\"\n\n/** Every vector shape the Glassly CFW rasterizes on the glasses. */\nexport const ALL_DISPLAY_SHAPES: DisplayShape[] = [\"rect\", \"circle\", \"arc\", \"pie\", \"line\", \"triangle\", \"quad\", \"bezier\"]\n\n/**\n * Microphone capabilities\n */\nexport interface MicrophoneCapabilities {\n count?: number\n hasVAD?: boolean // Voice Activity Detection\n // The connected firmware can stop streaming audio below a volume floor\n // (G2 Glassly CFW revision 40+). Never set on a model profile: it is\n // reported at runtime and layered on by getEffectiveCapabilities.\n volumeGate?: boolean\n}\n\n/**\n * Speaker capabilities\n */\nexport interface SpeakerCapabilities {\n count?: number\n isPrivate?: boolean // e.g., bone conduction\n}\n\n/**\n * IMU (Inertial Measurement Unit) capabilities\n */\nexport interface IMUCapabilities {\n axisCount?: number\n hasAccelerometer?: boolean\n hasCompass?: boolean\n hasGyroscope?: boolean\n}\n\n/**\n * Button capabilities\n */\nexport interface ButtonCapabilities {\n count?: number\n buttons?: {\n type: \"press\" | \"swipe1d\" | \"swipe2d\"\n events: string[] // e.g., \"press\", \"double_press\", \"long_press\", \"swipe_up\", \"swipe_down\"\n isCapacitive?: boolean\n }[]\n}\n\n/**\n * Light capabilities\n */\nexport interface LightCapabilities {\n count?: number\n lights?: {\n id: string // Unique identifier for the LED (e.g., \"privacy\", \"user_feedback\")\n purpose: \"privacy\" | \"user_feedback\" | \"general\" // LED purpose/function\n isFullColor: boolean\n color?: string // e.g., \"white\", \"rgb\"\n position?: \"front_facing\" | \"user_facing\" | \"side\" | \"unknown\" // LED physical position\n }[]\n}\n\n/**\n * Power capabilities\n */\nexport interface PowerCapabilities {\n hasExternalBattery: boolean // e.g., a case or puck\n}\n\n/**\n * Device hardware capabilities\n * Complete information about what hardware a device has\n */\nexport interface Capabilities {\n modelName: string\n\n // Camera capabilities\n hasCamera: boolean\n camera: CameraCapabilities | null\n\n // Display capabilities\n hasDisplay: boolean\n display: DisplayCapabilities | null\n\n // Microphone capabilities\n hasMicrophone: boolean\n microphone: MicrophoneCapabilities | null\n\n // Speaker capabilities\n hasSpeaker: boolean\n speaker: SpeakerCapabilities | null\n\n // IMU capabilities\n hasIMU: boolean\n imu: IMUCapabilities | null\n\n // Button capabilities\n hasButton: boolean\n button: ButtonCapabilities | null\n\n // Light capabilities\n hasLight: boolean\n light: LightCapabilities | null\n\n // Power capabilities\n power: PowerCapabilities\n\n // WiFi capability\n hasWifi: boolean\n\n // OTA capability\n hasOta?: boolean\n\n // True when the app ships a flashable Glassly custom firmware for this\n // model, so pairing can offer to install it and Settings exposes the flasher\n hasCustomFirmware?: boolean\n\n // Native dashboard capability\n // True when the device renders its own dashboard in firmware (e.g. Even\n // Realities' built-in dashboard on G2). Glassly does not manage or expose\n // dashboard settings for these devices. Absent/false means Glassly owns the\n // dashboard.\n hasNativeDashboard?: boolean\n\n // True when the device renders its own turn-by-turn nav UI in firmware\n // (G2 nav mode: instruction card + map slots + magnetometer compass); nav\n // apps feed it structured fields and map bitmaps instead of scene elements\n hasNativeNavigation?: boolean\n\n // True when the firmware presents phone notifications itself (popup +\n // history) and takes a GlassesNotificationConfig. How it gets the content\n // (reading the phone's stream, or an upload from the phone) is the driver's\n // business; the engine only decides who presents.\n hasNativeNotifications?: boolean\n hasNotificationRelay?: boolean\n // Popup durations the firmware accepts, in seconds (0 = firmware default).\n // Drivers snap other values; the settings UI offers exactly these.\n nativeNotificationPopupSeconds?: number[]\n}\n\n/**\n * Hardware capability profiles for supported glasses models\n * Key: model_name string (e.g., \"Even Realities G1\", \"Mentra Live\")\n * Value: Capabilities object defining device features\n */\nexport const HARDWARE_CAPABILITIES: Record<string, Capabilities> = {\n [evenRealitiesG1.modelName]: evenRealitiesG1,\n [evenRealitiesG2.modelName]: evenRealitiesG2,\n [mentraDisplay.modelName]: mentraDisplay,\n [mentraLive.modelName]: mentraLive,\n [simulatedGlasses.modelName]: simulatedGlasses,\n [vuzixZ100.modelName]: vuzixZ100,\n [nimo.modelName]: nimo,\n [rayneoIO.modelName]: rayneoIO,\n [memoMindOne.modelName]: memoMindOne,\n [DeviceTypes.MACH1]: vuzixZ100, // Mach1 uses same Vuzix Ultralite hardware as Z100\n [DeviceTypes.AR99]: {\n ...evenRealitiesG1,\n modelName: DeviceTypes.AR99,\n display: {\n ...evenRealitiesG1.display,\n canDisplayBitmap: false,\n // The AR99 firmware takes no position command.\n positionRange: undefined,\n },\n hasMicrophone: true,\n hasOta: true,\n microphone: {\n count: 1,\n hasVAD: false,\n },\n },\n [none.modelName]: none,\n}\n\nexport const getModelCapabilities = (deviceType: DeviceTypes): Capabilities => {\n const modelName = deviceType as string\n if (!HARDWARE_CAPABILITIES[modelName]) {\n return HARDWARE_CAPABILITIES[DeviceTypes.NONE]\n }\n return HARDWARE_CAPABILITIES[modelName]\n}\n\n// export * from \"./capabilities\"\nexport {\n simulatedGlasses,\n evenRealitiesG1,\n evenRealitiesG2,\n mentraLive,\n vuzixZ100,\n mentraDisplay,\n nimo,\n rayneoIO,\n memoMindOne,\n}\n"]}
@@ -172,4 +172,5 @@ export declare function createNexToolkit(): {
172
172
  composer: ColumnComposer;
173
173
  profile: DisplayProfile;
174
174
  };
175
+ export { MEMOMIND_ONE_PROFILE } from "./profiles";
175
176
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/display/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/display/index.ts"],"names":[],"mappings":"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"}
@@ -187,4 +187,5 @@ export function createNexToolkit() {
187
187
  breakMode: "character-no-hyphen",
188
188
  });
189
189
  }
190
+ export { MEMOMIND_ONE_PROFILE } from "./profiles";
190
191
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/display/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @glassly/display-utils\n *\n * Glasses-agnostic, pixel-accurate text measurement and wrapping library\n * for smart glasses displays.\n *\n * Key features:\n * - Pixel-perfect measurement (no abstract units or averages)\n * - Multiple break modes (character, word, strict-word)\n * - Full script support (Latin, CJK, Korean, Cyrillic)\n * - Configurable display profiles for different glasses hardware\n *\n * @example\n * ```typescript\n * import {\n * TextMeasurer,\n * TextWrapper,\n * DisplayHelpers,\n * G1_PROFILE\n * } from '@glassly/display-utils'\n *\n * // Create measurer and wrapper for G1 glasses\n * const measurer = new TextMeasurer(G1_PROFILE)\n * const wrapper = new TextWrapper(measurer, { breakMode: 'character' })\n * const helpers = new DisplayHelpers(measurer, wrapper)\n *\n * // Wrap text for display\n * const result = wrapper.wrap(\"Hello, world! This is a long text.\")\n * console.log(result.lines)\n * // [\"Hello, world! This is a long text th-\", \"at needs wrapping.\"]\n * ```\n */\n\n// =============================================================================\n// Profiles - Hardware configurations for different glasses\n// =============================================================================\n\n// Import for factory functions\nimport {G1_PROFILE_LEGACY, G2_PROFILE, Z100_PROFILE, NEX_PROFILE} from \"./profiles\"\n\n// =============================================================================\n// Convenience factory functions\n// =============================================================================\n\nimport {TextMeasurer} from \"./measurer\"\nimport {TextWrapper} from \"./wrapper\"\nimport {DisplayHelpers} from \"./helpers\"\nimport {ColumnComposer} from \"./composer\"\nimport {G1_PROFILE} from \"./profiles\"\nimport type {DisplayProfile} from \"./profiles\"\nimport type {WrapOptions} from \"./wrapper\"\n\nexport type {\n DisplayProfile,\n FontMetrics,\n UniformScriptWidths,\n FallbackConfig,\n DisplayConstraints,\n ScriptType,\n} from \"./profiles\"\n\nexport {G1_PROFILE, G1_PROFILE_LEGACY, G1_HYPHEN_WIDTH_PX, G1_SPACE_WIDTH_PX} from \"./profiles\"\n\n// G2 Profile\nexport {G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX} from \"./profiles\"\n\n// Z100 Profile\nexport {Z100_PROFILE, Z100_HYPHEN_WIDTH_PX, Z100_SPACE_WIDTH_PX} from \"./profiles\"\n\n// Mentra Nex Profile (a.k.a. Mentra Display)\nexport {NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX} from \"./profiles\"\n\n// RayNeo iO Profiles (stock subtitle page, Glassly CFW scene page)\nexport {RAYNEO_IO_PROFILE, RAYNEO_IO_CFW_PROFILE, RAYNEO_IO_HYPHEN_WIDTH_PX, RAYNEO_IO_SPACE_WIDTH_PX} from \"./profiles\"\n\n// =============================================================================\n// Measurer - Pixel-accurate text measurement\n// =============================================================================\n\nexport {TextMeasurer} from \"./measurer\"\nexport type {CharMeasurement, TextMeasurement} from \"./measurer\"\n\n// Script detection utilities\nexport {\n detectScript,\n isCJKCharacter,\n isKoreanCharacter,\n isUniformWidthScript,\n isUnsupportedScript,\n needsHyphenForBreak,\n SCRIPT_RANGES,\n} from \"./measurer\"\n\n// =============================================================================\n// Wrapper - Text wrapping with multiple break modes\n// =============================================================================\n\nexport {TextWrapper} from \"./wrapper\"\nexport type {WrapOptions, WrapResult, LineMetrics, BreakMode} from \"./wrapper\"\nexport {DEFAULT_WRAP_OPTIONS} from \"./wrapper\"\n\n// =============================================================================\n// Helpers - Optional convenience utilities\n// =============================================================================\n\nexport {DisplayHelpers, ScrollView} from \"./helpers\"\nexport type {TruncateResult, Page, Chunk, ScrollPosition, ScrollViewport} from \"./helpers\"\n\n// =============================================================================\n// Composer - Multi-column layout composition\n// =============================================================================\n\nexport {ColumnComposer, createColumnComposer} from \"./composer\"\nexport type {ColumnConfig, ComposeOptions, ComposeResult} from \"./composer\"\n\n/**\n * Create a complete display toolkit for a given profile.\n *\n * @param profile - Display profile (defaults to G1)\n * @param wrapOptions - Default wrap options\n * @returns Object with measurer, wrapper, and helpers\n *\n * @example\n * ```typescript\n * const { measurer, wrapper, helpers } = createDisplayToolkit()\n * const lines = wrapper.wrapToLines(\"Hello, world!\")\n * ```\n */\nexport function createDisplayToolkit(\n profile: DisplayProfile = G1_PROFILE,\n wrapOptions?: WrapOptions,\n): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n const measurer = new TextMeasurer(profile)\n const wrapper = new TextWrapper(measurer, wrapOptions)\n const helpers = new DisplayHelpers(measurer, wrapper)\n const composer = new ColumnComposer(profile, wrapOptions?.breakMode || \"word\")\n\n return {\n measurer,\n wrapper,\n helpers,\n composer,\n profile,\n }\n}\n\n/**\n * Create a G1-configured display toolkit with character breaking.\n * This is the recommended setup for captions and similar high-utilization use cases.\n *\n * @returns Object with measurer, wrapper, and helpers configured for G1\n *\n * @example\n * ```typescript\n * const { wrapper, composer } = createG1Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * const columns = composer.composeDoubleTextWall(\"Left\", \"Right\")\n * ```\n */\nexport function createG1Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G1_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a G1-configured display toolkit for LEGACY mobile clients.\n *\n * Use this when the mobile client has old wrapping logic that re-wraps\n * text received from the cloud. This profile uses a reduced display width\n * (~522px instead of 576px) to prevent double-wrapping overflow.\n *\n * @returns Object with measurer, wrapper, and helpers configured for legacy G1 clients\n *\n * @example\n * ```typescript\n * // For old mobile clients that double-wrap\n * const { wrapper } = createG1LegacyToolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * // Lines will be shorter to account for mobile re-wrapping\n * ```\n */\nexport function createG1LegacyToolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G1_PROFILE_LEGACY, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a G2-configured display toolkit with character breaking.\n * G2 uses EvenHub protocol with the same display hardware as G1.\n *\n * @returns Object with measurer, wrapper, and helpers configured for Even G2\n *\n * @example\n * ```typescript\n * const { wrapper } = createG2Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createG2Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G2_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a Z100-configured display toolkit with character breaking.\n *\n * @returns Object with measurer, wrapper, and helpers configured for Vuzix Z100\n *\n * @example\n * ```typescript\n * const { wrapper } = createZ100Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createZ100Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(Z100_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a Mentra Nex-configured display toolkit with character breaking.\n * Also known as \"Mentra Display\".\n *\n * @returns Object with measurer, wrapper, and helpers configured for Mentra Nex\n *\n * @example\n * ```typescript\n * const { wrapper } = createNexToolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createNexToolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(NEX_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/display/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @glassly/display-utils\n *\n * Glasses-agnostic, pixel-accurate text measurement and wrapping library\n * for smart glasses displays.\n *\n * Key features:\n * - Pixel-perfect measurement (no abstract units or averages)\n * - Multiple break modes (character, word, strict-word)\n * - Full script support (Latin, CJK, Korean, Cyrillic)\n * - Configurable display profiles for different glasses hardware\n *\n * @example\n * ```typescript\n * import {\n * TextMeasurer,\n * TextWrapper,\n * DisplayHelpers,\n * G1_PROFILE\n * } from '@glassly/display-utils'\n *\n * // Create measurer and wrapper for G1 glasses\n * const measurer = new TextMeasurer(G1_PROFILE)\n * const wrapper = new TextWrapper(measurer, { breakMode: 'character' })\n * const helpers = new DisplayHelpers(measurer, wrapper)\n *\n * // Wrap text for display\n * const result = wrapper.wrap(\"Hello, world! This is a long text.\")\n * console.log(result.lines)\n * // [\"Hello, world! This is a long text th-\", \"at needs wrapping.\"]\n * ```\n */\n\n// =============================================================================\n// Profiles - Hardware configurations for different glasses\n// =============================================================================\n\n// Import for factory functions\nimport {G1_PROFILE_LEGACY, G2_PROFILE, Z100_PROFILE, NEX_PROFILE} from \"./profiles\"\n\n// =============================================================================\n// Convenience factory functions\n// =============================================================================\n\nimport {TextMeasurer} from \"./measurer\"\nimport {TextWrapper} from \"./wrapper\"\nimport {DisplayHelpers} from \"./helpers\"\nimport {ColumnComposer} from \"./composer\"\nimport {G1_PROFILE} from \"./profiles\"\nimport type {DisplayProfile} from \"./profiles\"\nimport type {WrapOptions} from \"./wrapper\"\n\nexport type {\n DisplayProfile,\n FontMetrics,\n UniformScriptWidths,\n FallbackConfig,\n DisplayConstraints,\n ScriptType,\n} from \"./profiles\"\n\nexport {G1_PROFILE, G1_PROFILE_LEGACY, G1_HYPHEN_WIDTH_PX, G1_SPACE_WIDTH_PX} from \"./profiles\"\n\n// G2 Profile\nexport {G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX} from \"./profiles\"\n\n// Z100 Profile\nexport {Z100_PROFILE, Z100_HYPHEN_WIDTH_PX, Z100_SPACE_WIDTH_PX} from \"./profiles\"\n\n// Mentra Nex Profile (a.k.a. Mentra Display)\nexport {NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX} from \"./profiles\"\n\n// RayNeo iO Profiles (stock subtitle page, Glassly CFW scene page)\nexport {RAYNEO_IO_PROFILE, RAYNEO_IO_CFW_PROFILE, RAYNEO_IO_HYPHEN_WIDTH_PX, RAYNEO_IO_SPACE_WIDTH_PX} from \"./profiles\"\n\n// =============================================================================\n// Measurer - Pixel-accurate text measurement\n// =============================================================================\n\nexport {TextMeasurer} from \"./measurer\"\nexport type {CharMeasurement, TextMeasurement} from \"./measurer\"\n\n// Script detection utilities\nexport {\n detectScript,\n isCJKCharacter,\n isKoreanCharacter,\n isUniformWidthScript,\n isUnsupportedScript,\n needsHyphenForBreak,\n SCRIPT_RANGES,\n} from \"./measurer\"\n\n// =============================================================================\n// Wrapper - Text wrapping with multiple break modes\n// =============================================================================\n\nexport {TextWrapper} from \"./wrapper\"\nexport type {WrapOptions, WrapResult, LineMetrics, BreakMode} from \"./wrapper\"\nexport {DEFAULT_WRAP_OPTIONS} from \"./wrapper\"\n\n// =============================================================================\n// Helpers - Optional convenience utilities\n// =============================================================================\n\nexport {DisplayHelpers, ScrollView} from \"./helpers\"\nexport type {TruncateResult, Page, Chunk, ScrollPosition, ScrollViewport} from \"./helpers\"\n\n// =============================================================================\n// Composer - Multi-column layout composition\n// =============================================================================\n\nexport {ColumnComposer, createColumnComposer} from \"./composer\"\nexport type {ColumnConfig, ComposeOptions, ComposeResult} from \"./composer\"\n\n/**\n * Create a complete display toolkit for a given profile.\n *\n * @param profile - Display profile (defaults to G1)\n * @param wrapOptions - Default wrap options\n * @returns Object with measurer, wrapper, and helpers\n *\n * @example\n * ```typescript\n * const { measurer, wrapper, helpers } = createDisplayToolkit()\n * const lines = wrapper.wrapToLines(\"Hello, world!\")\n * ```\n */\nexport function createDisplayToolkit(\n profile: DisplayProfile = G1_PROFILE,\n wrapOptions?: WrapOptions,\n): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n const measurer = new TextMeasurer(profile)\n const wrapper = new TextWrapper(measurer, wrapOptions)\n const helpers = new DisplayHelpers(measurer, wrapper)\n const composer = new ColumnComposer(profile, wrapOptions?.breakMode || \"word\")\n\n return {\n measurer,\n wrapper,\n helpers,\n composer,\n profile,\n }\n}\n\n/**\n * Create a G1-configured display toolkit with character breaking.\n * This is the recommended setup for captions and similar high-utilization use cases.\n *\n * @returns Object with measurer, wrapper, and helpers configured for G1\n *\n * @example\n * ```typescript\n * const { wrapper, composer } = createG1Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * const columns = composer.composeDoubleTextWall(\"Left\", \"Right\")\n * ```\n */\nexport function createG1Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G1_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a G1-configured display toolkit for LEGACY mobile clients.\n *\n * Use this when the mobile client has old wrapping logic that re-wraps\n * text received from the cloud. This profile uses a reduced display width\n * (~522px instead of 576px) to prevent double-wrapping overflow.\n *\n * @returns Object with measurer, wrapper, and helpers configured for legacy G1 clients\n *\n * @example\n * ```typescript\n * // For old mobile clients that double-wrap\n * const { wrapper } = createG1LegacyToolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * // Lines will be shorter to account for mobile re-wrapping\n * ```\n */\nexport function createG1LegacyToolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G1_PROFILE_LEGACY, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a G2-configured display toolkit with character breaking.\n * G2 uses EvenHub protocol with the same display hardware as G1.\n *\n * @returns Object with measurer, wrapper, and helpers configured for Even G2\n *\n * @example\n * ```typescript\n * const { wrapper } = createG2Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createG2Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(G2_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a Z100-configured display toolkit with character breaking.\n *\n * @returns Object with measurer, wrapper, and helpers configured for Vuzix Z100\n *\n * @example\n * ```typescript\n * const { wrapper } = createZ100Toolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createZ100Toolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(Z100_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\n/**\n * Create a Mentra Nex-configured display toolkit with character breaking.\n * Also known as \"Mentra Display\".\n *\n * @returns Object with measurer, wrapper, and helpers configured for Mentra Nex\n *\n * @example\n * ```typescript\n * const { wrapper } = createNexToolkit()\n * const result = wrapper.wrap(\"Your text here\")\n * ```\n */\nexport function createNexToolkit(): {\n measurer: TextMeasurer\n wrapper: TextWrapper\n helpers: DisplayHelpers\n composer: ColumnComposer\n profile: DisplayProfile\n} {\n return createDisplayToolkit(NEX_PROFILE, {\n breakMode: \"character-no-hyphen\",\n })\n}\n\nexport {MEMOMIND_ONE_PROFILE} from \"./profiles\"\n"]}
@@ -10,4 +10,5 @@ export { Z100_PROFILE, Z100_HYPHEN_WIDTH_PX, Z100_SPACE_WIDTH_PX } from "./z100"
10
10
  export { G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX } from "./g2";
11
11
  export { NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX } from "./nex";
12
12
  export { RAYNEO_IO_PROFILE, RAYNEO_IO_CFW_PROFILE, RAYNEO_IO_HYPHEN_WIDTH_PX, RAYNEO_IO_SPACE_WIDTH_PX, } from "./rayneo-io";
13
+ export { MEMOMIND_ONE_PROFILE } from "@glassly/miniapp/display";
13
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/display/profiles/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,UAAU,GACX,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAC,UAAU,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAGzF,OAAO,EAAC,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAC,MAAM,QAAQ,CAAA;AAG9E,OAAO,EAAC,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAGtE,OAAO,EAAC,WAAW,EAAE,mBAAmB,EAAE,kBAAkB,EAAC,MAAM,OAAO,CAAA;AAG1E,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/display/profiles/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,UAAU,GACX,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAC,UAAU,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAGzF,OAAO,EAAC,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAC,MAAM,QAAQ,CAAA;AAG9E,OAAO,EAAC,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAGtE,OAAO,EAAC,WAAW,EAAE,mBAAmB,EAAE,kBAAkB,EAAC,MAAM,OAAO,CAAA;AAG1E,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAC,oBAAoB,EAAC,MAAM,0BAA0B,CAAA"}
@@ -14,4 +14,5 @@ export { G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX } from "./g2";
14
14
  export { NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX } from "./nex";
15
15
  // RayNeo iO Profiles (stock subtitle page, Glassly CFW scene page)
16
16
  export { RAYNEO_IO_PROFILE, RAYNEO_IO_CFW_PROFILE, RAYNEO_IO_HYPHEN_WIDTH_PX, RAYNEO_IO_SPACE_WIDTH_PX, } from "./rayneo-io";
17
+ export { MEMOMIND_ONE_PROFILE } from "@glassly/miniapp/display";
17
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/utils/display/profiles/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,cAAc;AACd,OAAO,EAAC,UAAU,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAEzF,eAAe;AACf,OAAO,EAAC,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAC,MAAM,QAAQ,CAAA;AAE9E,aAAa;AACb,OAAO,EAAC,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAEtE,6CAA6C;AAC7C,OAAO,EAAC,WAAW,EAAE,mBAAmB,EAAE,kBAAkB,EAAC,MAAM,OAAO,CAAA;AAE1E,mEAAmE;AACnE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,aAAa,CAAA","sourcesContent":["/**\n * Display Profiles\n *\n * Hardware-specific configurations for smart glasses displays.\n * Each profile defines display dimensions, font metrics, and constraints.\n */\n\n// Types\nexport type {\n DisplayProfile,\n FontMetrics,\n UniformScriptWidths,\n FallbackConfig,\n DisplayConstraints,\n ScriptType,\n} from \"./types\"\n\n// G1 Profiles\nexport {G1_PROFILE, G1_PROFILE_LEGACY, G1_HYPHEN_WIDTH_PX, G1_SPACE_WIDTH_PX} from \"./g1\"\n\n// Z100 Profile\nexport {Z100_PROFILE, Z100_HYPHEN_WIDTH_PX, Z100_SPACE_WIDTH_PX} from \"./z100\"\n\n// G2 Profile\nexport {G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX} from \"./g2\"\n\n// Mentra Nex Profile (a.k.a. Mentra Display)\nexport {NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX} from \"./nex\"\n\n// RayNeo iO Profiles (stock subtitle page, Glassly CFW scene page)\nexport {\n RAYNEO_IO_PROFILE,\n RAYNEO_IO_CFW_PROFILE,\n RAYNEO_IO_HYPHEN_WIDTH_PX,\n RAYNEO_IO_SPACE_WIDTH_PX,\n} from \"./rayneo-io\"\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/utils/display/profiles/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,cAAc;AACd,OAAO,EAAC,UAAU,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAEzF,eAAe;AACf,OAAO,EAAC,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAC,MAAM,QAAQ,CAAA;AAE9E,aAAa;AACb,OAAO,EAAC,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,MAAM,CAAA;AAEtE,6CAA6C;AAC7C,OAAO,EAAC,WAAW,EAAE,mBAAmB,EAAE,kBAAkB,EAAC,MAAM,OAAO,CAAA;AAE1E,mEAAmE;AACnE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAC,oBAAoB,EAAC,MAAM,0BAA0B,CAAA","sourcesContent":["/**\n * Display Profiles\n *\n * Hardware-specific configurations for smart glasses displays.\n * Each profile defines display dimensions, font metrics, and constraints.\n */\n\n// Types\nexport type {\n DisplayProfile,\n FontMetrics,\n UniformScriptWidths,\n FallbackConfig,\n DisplayConstraints,\n ScriptType,\n} from \"./types\"\n\n// G1 Profiles\nexport {G1_PROFILE, G1_PROFILE_LEGACY, G1_HYPHEN_WIDTH_PX, G1_SPACE_WIDTH_PX} from \"./g1\"\n\n// Z100 Profile\nexport {Z100_PROFILE, Z100_HYPHEN_WIDTH_PX, Z100_SPACE_WIDTH_PX} from \"./z100\"\n\n// G2 Profile\nexport {G2_PROFILE, G2_HYPHEN_WIDTH_PX, G2_SPACE_WIDTH_PX} from \"./g2\"\n\n// Mentra Nex Profile (a.k.a. Mentra Display)\nexport {NEX_PROFILE, NEX_HYPHEN_WIDTH_PX, NEX_SPACE_WIDTH_PX} from \"./nex\"\n\n// RayNeo iO Profiles (stock subtitle page, Glassly CFW scene page)\nexport {\n RAYNEO_IO_PROFILE,\n RAYNEO_IO_CFW_PROFILE,\n RAYNEO_IO_HYPHEN_WIDTH_PX,\n RAYNEO_IO_SPACE_WIDTH_PX,\n} from \"./rayneo-io\"\n\nexport {MEMOMIND_ONE_PROFILE} from \"@glassly/miniapp/display\"\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glassly/engine",
3
- "version": "0.3.7-beta.934",
3
+ "version": "0.3.7-beta.966",
4
4
  "description": "Glassly Engine — miniapp registry, WebView bridge, and miniapp store",
5
5
  "main": "build/index.js",
6
6
  "react-native": "src/index.ts",
@@ -97,17 +97,17 @@
97
97
  "registry": "https://registry.npmjs.org/"
98
98
  },
99
99
  "dependencies": {
100
- "@glassly/bluetooth-sdk": "0.3.7-beta.934",
101
- "@glassly/cloud-client": "0.3.7-beta.934",
102
- "@glassly/cloud-protocol": "0.3.7-beta.934",
103
- "@glassly/crust": "0.3.7-beta.934",
104
- "@glassly/miniapp": "0.3.7-beta.934",
100
+ "@glassly/bluetooth-sdk": "0.3.7-beta.966",
101
+ "@glassly/cloud-client": "0.3.7-beta.966",
102
+ "@glassly/cloud-protocol": "0.3.7-beta.966",
103
+ "@glassly/crust": "0.3.7-beta.966",
104
+ "@glassly/miniapp": "0.3.7-beta.966",
105
105
  "buffer": "^6.0.3",
106
106
  "events": "^3.3.0",
107
107
  "react-native-marked": "8.3.2",
108
108
  "semver": "^7.7.4",
109
109
  "typesafe-ts": "^1.7.1",
110
- "@glassly/llm-providers": "0.3.7-beta.934",
110
+ "@glassly/llm-providers": "0.3.7-beta.966",
111
111
  "@huggingface/jinja": "^0.5.9",
112
112
  "jsonrepair": "^3.12.0"
113
113
  },
@@ -12,9 +12,9 @@ export interface EngineReleaseMetadata {
12
12
  export const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({
13
13
  "schemaVersion": 1,
14
14
  "familyBaseVersion": "0.3.7",
15
- "releaseIdentity": "0.3.7-beta.934",
16
- "releaseSetId": "glassly-0.3.7-beta.934",
17
- "sourceCommit": "5ef13d1fc413aa4fb988d6e28272c8e1d8bc44d3",
15
+ "releaseIdentity": "0.3.7-beta.966",
16
+ "releaseSetId": "glassly-0.3.7-beta.966",
17
+ "sourceCommit": "302567acdb73ffa9769235e4c4ae286288ec169e",
18
18
  "otaManifestUrl": null,
19
19
  "otaManifestSha256": null
20
20
  })
@@ -504,20 +504,14 @@ export class BlobStore {
504
504
  const key = (typeof payload.key === "string" && payload.key) || this.makeId()
505
505
  const mimeFilter = payload.mimeType as string | undefined
506
506
 
507
- let picked: File | File[] | null = null
508
- try {
509
- picked = await File.pickFileAsync(undefined, mimeFilter)
510
- } catch (err) {
511
- // Picker dismissed / cancelled (or unavailable) → resolve to null, not an error.
512
- console.log(`${LOG_TAG}: blob import picker dismissed`, err)
513
- this.hooks.sendResult(packageName, requestId, true, null)
514
- return
515
- }
516
- const file = Array.isArray(picked) ? picked[0] : picked
517
- if (!file) {
507
+ // The options form resolves {canceled, result} and never throws; the deprecated
508
+ // (initialUri, mimeType) form resolves a bare File only when a mime type is passed.
509
+ const picked = await File.pickFileAsync(mimeFilter ? {mimeTypes: mimeFilter} : {})
510
+ if (picked.canceled) {
518
511
  this.hooks.sendResult(packageName, requestId, true, null)
519
512
  return
520
513
  }
514
+ const file = picked.result
521
515
  try {
522
516
  const size = file.size ?? 0
523
517
  if (this.overQuota(packageName, key, size)) {
@@ -20,6 +20,7 @@ import {
20
20
  Z100_PROFILE,
21
21
  NEX_PROFILE,
22
22
  RAYNEO_IO_PROFILE,
23
+ MEMOMIND_ONE_PROFILE,
23
24
  RAYNEO_IO_CFW_PROFILE,
24
25
  TextMeasurer,
25
26
  TextWrapper,
@@ -43,12 +44,7 @@ import {isGlassesConnected} from "./GlassesReadiness"
43
44
  * Display event types that we process
44
45
  */
45
46
  export type DisplayLayoutType =
46
- | "text_wall"
47
- | "text_line"
48
- | "text_rows"
49
- | "reference_card"
50
- | "double_text_wall"
51
- | "bitmap_view"
47
+ "text_wall" | "text_line" | "text_rows" | "reference_card" | "double_text_wall" | "bitmap_view"
52
48
 
53
49
  /**
54
50
  * Raw display event from the cloud/WebSocket
@@ -209,6 +205,7 @@ const DEVICE_PROFILES: Partial<Record<DeviceTypes, DisplayProfile>> = {
209
205
  [DeviceTypes.NEX]: NEX_PROFILE,
210
206
  [DeviceTypes.MACH1]: Z100_PROFILE, // Mach1 uses same hardware as Vuzix Z100
211
207
  [DeviceTypes.RAYNEO_IO]: RAYNEO_IO_PROFILE,
208
+ [DeviceTypes.MEMOMIND_ONE]: MEMOMIND_ONE_PROFILE,
212
209
  }
213
210
 
214
211
  /**
@@ -217,6 +214,7 @@ const DEVICE_PROFILES: Partial<Record<DeviceTypes, DisplayProfile>> = {
217
214
  */
218
215
  const CFW_SCENE_PROFILES: Partial<Record<DeviceTypes, DisplayProfile>> = {
219
216
  [DeviceTypes.RAYNEO_IO]: RAYNEO_IO_CFW_PROFILE,
217
+ [DeviceTypes.MEMOMIND_ONE]: MEMOMIND_ONE_PROFILE,
220
218
  }
221
219
 
222
220
  // =============================================================================
@@ -284,8 +282,7 @@ export class DisplayProcessor {
284
282
  // Seed the device profile from the saved default wearable, read off the engine
285
283
  // settings store directly (was a host settings hook).
286
284
  const defaultWearable = useSettingsStore.getState().getSetting(ISLAND_SETTINGS_KEYS.defaultWearable) as
287
- | string
288
- | undefined
285
+ string | undefined
289
286
  if (defaultWearable) {
290
287
  this.setDeviceModel(defaultWearable)
291
288
  console.log(`DISPLAY_PROCESSOR: Initialized DisplayProcessor with default wearable: ${defaultWearable}`)
@@ -110,7 +110,7 @@ function routeTouchEvent(event: TouchEvent): void {
110
110
  const doubleTap = gesture === "double_tap"
111
111
  // The Neural Band's middle finger (index 1) shares the tap names. Either
112
112
  // finger leaves the app on screen; the firmware dashboard is the index finger's.
113
- const osDoubleTap = doubleTap && event.index !== 1
113
+ const osDoubleTap = doubleTap && !(event.source === 3 && event.index === 1)
114
114
  const osHeadUp = gesture === "head_up"
115
115
 
116
116
  if (doubleTap) {
@@ -156,7 +156,11 @@ function routeTouchEvent(event: TouchEvent): void {
156
156
  // pagesEligible: connected Glassly CFW glasses, whose firmware leaves the
157
157
  // dashboard to the phone; other firmware opens its own on a lift.
158
158
  const opensNativeDashboard = osDoubleTap || (osHeadUp && pagesEligible())
159
- if (opensNativeDashboard && !nativeNavigationService.isActive && isGlassesConnected(useGlassesStore.getState().connection)) {
159
+ if (
160
+ opensNativeDashboard &&
161
+ !nativeNavigationService.isActive &&
162
+ isGlassesConnected(useGlassesStore.getState().connection)
163
+ ) {
160
164
  useDisplayStore.getState().setDisplayEvent({layout: {layoutType: "unavailable", reason: "firmware-dashboard"}})
161
165
  void Promise.resolve(BluetoothSdk.showDashboard()).catch((err) => {
162
166
  console.error("DeviceEventRouter: showDashboard failed:", err)
@@ -49,9 +49,16 @@ export async function listPhoneCalendarEvents(request: CalendarListRequest): Pro
49
49
  if (calendars.length === 0) return {events: [], truncated: false}
50
50
 
51
51
  const rawEvents = await Calendar.listEvents(calendars, startsAt, endsAt)
52
+ const seen = new Set<string>()
52
53
  const events = rawEvents
53
54
  .map(normalizeCalendarEvent)
54
55
  .filter((event) => calendarEventOverlapsWindow(event, startsAt, endsAt))
56
+ .filter((event) => {
57
+ const key = `${event.title}\n${event.startsAt}\n${event.endsAt}\n${event.allDay}`
58
+ if (seen.has(key)) return false
59
+ seen.add(key)
60
+ return true
61
+ })
55
62
  .sort((a, b) => Date.parse(a.startsAt) - Date.parse(b.startsAt) || Date.parse(a.endsAt) - Date.parse(b.endsAt))
56
63
 
57
64
  return {
@@ -91,6 +91,11 @@ export function nativeNotificationsSupported(): boolean {
91
91
  return getModelCapabilities(model).hasNativeNotifications === true
92
92
  }
93
93
 
94
+ function notificationRelaySupported(): boolean {
95
+ const model = useGlassesStore.getState().deviceModel as DeviceTypes
96
+ return Platform.OS === "ios" && getModelCapabilities(model).hasNotificationRelay === true
97
+ }
98
+
94
99
  /** Popup durations the firmware accepts, or an empty list when it takes any. */
95
100
  export function nativeNotificationPopupSeconds(): number[] {
96
101
  const model = useGlassesStore.getState().deviceModel as DeviceTypes
@@ -141,10 +146,10 @@ export function currentPresentationOwner(hostActive: boolean): PresentationOwner
141
146
  */
142
147
  export function captureAuthorization(): "granted" | "denied" | "unknown" | "not_needed" {
143
148
  if (Platform.OS !== "ios") return "not_needed"
144
- if (!nativeNotificationsSupported()) return "not_needed"
149
+ if (!nativeNotificationsSupported() && !notificationRelaySupported()) return "not_needed"
145
150
  const glasses = useGlassesStore.getState()
146
151
  if (!isGlassesConnected(glasses.connection)) return "unknown"
147
- return glasses.ancsAuthorized ? "granted" : "denied"
152
+ return glasses.ancsAuthorized ? "granted" : notificationRelaySupported() ? "unknown" : "denied"
148
153
  }
149
154
 
150
155
  /**
@@ -178,7 +183,7 @@ function pushListenerConfig(): void {
178
183
  }
179
184
 
180
185
  function pushGlassesConfig(): void {
181
- if (!nativeNotificationsSupported()) return
186
+ if (!nativeNotificationsSupported() && !notificationRelaySupported()) return
182
187
  if (!isGlassesConnected(useGlassesStore.getState().connection)) return
183
188
  void Promise.resolve(BluetoothSdk.setGlassesNotificationConfig(desiredGlassesNotificationConfig())).catch(
184
189
  (err: unknown) =>
@@ -54,6 +54,7 @@ const INPUT_SURFACES: Readonly<Record<string, readonly InputSurface[]>> = {
54
54
  [ControllerTypes.APPLE_WATCH]: [WATCH_SURFACE],
55
55
  [ControllerTypes.WEAR_OS]: [WATCH_SURFACE],
56
56
  [ControllerTypes.GAMEBRICK]: [GAMEBRICK_SURFACE],
57
+ [ControllerTypes.IINE_ANANKE]: [GAMEBRICK_SURFACE],
57
58
  [ControllerTypes.R1]: [],
58
59
  }
59
60
 
@@ -13,7 +13,10 @@ import {isGlassesConnected} from "../GlassesReadiness"
13
13
 
14
14
  /** The SGC appends this marker after the firmware advertises Glassly CFW capabilities (G2, RayNeo iO). */
15
15
  export function isCfwFirmwareVersion(firmwareVersion: string | null | undefined): boolean {
16
- return firmwareVersion?.toLowerCase().includes("glassly cfw") === true
16
+ return (
17
+ firmwareVersion?.toLowerCase().includes("glassly cfw") === true ||
18
+ /^GLASSLYCFW\/[0-9]+$/.test(firmwareVersion ?? "")
19
+ )
17
20
  }
18
21
 
19
22
  /**
@@ -23,6 +26,11 @@ export function isCfwFirmwareVersion(firmwareVersion: string | null | undefined)
23
26
  */
24
27
  export function isCustomDashboardEligible(info: {model?: string | null; firmwareVersion?: string | null}): boolean {
25
28
  if (!info.model) return false
29
+ if (info.model === DeviceTypes.MEMOMIND_ONE) {
30
+ const match = /^GLASSLYCFW\/([0-9]+)$/.exec(info.firmwareVersion ?? "")
31
+ const revision = match ? Number(match[1]) : 0
32
+ return Number.isSafeInteger(revision) && revision >= 5
33
+ }
26
34
  return (
27
35
  getModelCapabilities(info.model as DeviceTypes).hasCustomFirmware === true &&
28
36
  isCfwFirmwareVersion(info.firmwareVersion)
@@ -0,0 +1,42 @@
1
+ import type {Capabilities} from "../hardware"
2
+
3
+ export const memoMindOne: Capabilities = {
4
+ modelName: "MemoMind One",
5
+ hasCamera: false,
6
+ camera: null,
7
+ hasDisplay: true,
8
+ display: {
9
+ count: 1,
10
+ isColor: false,
11
+ canDisplayBitmap: true,
12
+ resolution: {width: 600, height: 350},
13
+ width: 600,
14
+ height: 350,
15
+ canPosition: true,
16
+ intensityLevels: 16,
17
+ partialUpdate: true,
18
+ adjustBrightness: true,
19
+ positionRange: {height: {min: 0, max: 8}, depth: {min: 0, max: 8}},
20
+ },
21
+ hasMicrophone: true,
22
+ microphone: {count: 1, hasVAD: false},
23
+ hasSpeaker: false,
24
+ speaker: null,
25
+ hasIMU: false,
26
+ imu: null,
27
+ hasButton: true,
28
+ button: {
29
+ count: 1,
30
+ buttons: [{type: "press", events: ["TAP", "DOUBLE_TAP", "PRESS_HOLD", "RELEASE"], isCapacitive: false}],
31
+ },
32
+ hasLight: false,
33
+ light: null,
34
+ power: {hasExternalBattery: false},
35
+ hasWifi: false,
36
+ hasOta: false,
37
+ hasCustomFirmware: true,
38
+ hasNativeDashboard: false,
39
+ hasNativeNavigation: false,
40
+ hasNativeNotifications: false,
41
+ hasNotificationRelay: true,
42
+ }
@@ -13,6 +13,7 @@ export enum DeviceTypes {
13
13
  NIMO = "NIMO",
14
14
  FRAME = "Brilliant Frame",
15
15
  RAYNEO_IO = "RayNeo iO",
16
+ MEMOMIND_ONE = "MemoMind One",
16
17
  }
17
18
 
18
19
  export enum ControllerTypes {
@@ -21,4 +22,5 @@ export enum ControllerTypes {
21
22
  APPLE_WATCH = "Apple Watch",
22
23
  WEAR_OS = "Wear OS Watch",
23
24
  GAMEBRICK = "IINE Gamebrick",
25
+ IINE_ANANKE = "IINE Ananke Gen 2",
24
26
  }
@@ -9,6 +9,7 @@ import {mentraLive} from "./capabilities/mentra-live"
9
9
  import {simulatedGlasses} from "./capabilities/simulated-glasses"
10
10
  import {nimo} from "./capabilities/nimo"
11
11
  import {rayneoIO} from "./capabilities/rayneo-io"
12
+ import {memoMindOne} from "./capabilities/memomind-one"
12
13
  import {vuzixZ100} from "./capabilities/vuzix-z100"
13
14
  import {none} from "./capabilities/none"
14
15
  import {DeviceTypes} from "./enums"
@@ -217,6 +218,7 @@ export interface Capabilities {
217
218
  // (reading the phone's stream, or an upload from the phone) is the driver's
218
219
  // business; the engine only decides who presents.
219
220
  hasNativeNotifications?: boolean
221
+ hasNotificationRelay?: boolean
220
222
  // Popup durations the firmware accepts, in seconds (0 = firmware default).
221
223
  // Drivers snap other values; the settings UI offers exactly these.
222
224
  nativeNotificationPopupSeconds?: number[]
@@ -236,6 +238,7 @@ export const HARDWARE_CAPABILITIES: Record<string, Capabilities> = {
236
238
  [vuzixZ100.modelName]: vuzixZ100,
237
239
  [nimo.modelName]: nimo,
238
240
  [rayneoIO.modelName]: rayneoIO,
241
+ [memoMindOne.modelName]: memoMindOne,
239
242
  [DeviceTypes.MACH1]: vuzixZ100, // Mach1 uses same Vuzix Ultralite hardware as Z100
240
243
  [DeviceTypes.AR99]: {
241
244
  ...evenRealitiesG1,
@@ -265,4 +268,14 @@ export const getModelCapabilities = (deviceType: DeviceTypes): Capabilities => {
265
268
  }
266
269
 
267
270
  // export * from "./capabilities"
268
- export {simulatedGlasses, evenRealitiesG1, evenRealitiesG2, mentraLive, vuzixZ100, mentraDisplay, nimo, rayneoIO}
271
+ export {
272
+ simulatedGlasses,
273
+ evenRealitiesG1,
274
+ evenRealitiesG2,
275
+ mentraLive,
276
+ vuzixZ100,
277
+ mentraDisplay,
278
+ nimo,
279
+ rayneoIO,
280
+ memoMindOne,
281
+ }
@@ -274,3 +274,5 @@ export function createNexToolkit(): {
274
274
  breakMode: "character-no-hyphen",
275
275
  })
276
276
  }
277
+
278
+ export {MEMOMIND_ONE_PROFILE} from "./profiles"
@@ -34,3 +34,5 @@ export {
34
34
  RAYNEO_IO_HYPHEN_WIDTH_PX,
35
35
  RAYNEO_IO_SPACE_WIDTH_PX,
36
36
  } from "./rayneo-io"
37
+
38
+ export {MEMOMIND_ONE_PROFILE} from "@glassly/miniapp/display"