Status: preview. The Glassly OEM Integration Engine covers the full surface documented below. The runtime is not yet packaged for external install — reach out to [email protected] to integrate today.

What it is

The Glassly OEM Integration Engine is the API an OEM host app (the phone-side app that talks to your glasses) calls to run Glassly. It ships as the @glassly/engine module and exposes a single namespaced object, engine:
The dividing line:
  • The host owns UI, navigation, and login. Your screens, your router, your auth.
  • The engine owns the runtime and the device. Connection, device state, wifi, on-device speech models, the display pipeline, the miniapp runtime.
So an OEM builds its own UI and calls engine.<domain>.<method>() for everything device- and runtime-related. The engine is device-agnostic: the same calls work across glasses models.

Lifecycle

The host hands the engine its auth + config once, then starts it.
auth.getSubjectToken() is the only must-have seam — the host owns login and returns a fresh token on demand; the engine owns everything downstream.

engine.glasses

Connection actions, a curated status/info read-model, capabilities, version, and the discrete input events.

Connection

Status & info (read-models)

status() returns a snapshot projected from the runtime’s glasses store, in a stable shape that doesn’t leak the internal store layout:

Input events

Every on*() returns an unsubscribe function.

engine.glasses.wifi

connect() propagates the bluetooth layer’s coded errors (bluetooth_powered_off, request_timeout, …) unchanged, so your UI keeps its own error mapping.

engine.glasses.settings

Keyed device settings (brightness, head-up angle, dashboard, camera/button, sensing, …). set() persists and auto-syncs to the connected glasses.
available() is the authoritative list at runtime (it varies by model/capabilities). The current keys, their types, and defaults:
Device identity (paired-device id/name/address, controller address) and internal runtime flags (e.g. STT-fallback state) are intentionally not in this surface — read the connected device via engine.glasses.info().

engine.pairing

First-time glasses discovery + pairing. (Reconnecting the already-paired default is engine.glasses.connectDefault().)

engine.speech

On-device STT/TTS model management.

engine.display.mirror

A typed read facade for a phone-side preview of the glasses screen.

Scene rendering, shapes, and the canvas

Miniapps draw through the engine’s scene API; the engine rasterizes or translates each frame for the connected device. Two things vary by firmware, and both are read off the device’s effective capabilities rather than hard-coded. Vector shapes. Firmware that draws vectors declares rect · circle · arc · pie · line · triangle · quad · bezier, plus svg on Glassly CFW. Elements carry a style — border/fill/radius on closed shapes, width on open strokes (line, bezier, arc) — and a gray color. Devices without vector support render scenes through the host degrade path instead. Intensity. The baseline is 4-bit grayscale: every drawable’s color is a gray level 0–15, where 15 is brightest and 0 means “not drawn”. Stock G2 firmware reports intensityLevels: 2; CFW reports the full ramp. Animation. An element with a stable id can carry a transition ({durationMs, easing}, easing one of linear · ease · ease-in · ease-out · ease-in-out). The device tweens the geometry change itself when its capabilities declare animation; on images the tween reads as a fade. rotation is a separate capability covering geometric and SVG rotations. Depth. Devices with two lenses may declare depth: per-element depth (a disparity of -16..16 canvas px) is then drawn depth px further right on the left lens and further left on the right, so positive values float in front of the frame. Glassly CFW declares it and sends each lens its own object-cache SHOW once a frame uses depth. Devices without it draw every element flat; depth never drops anything. Canvas negotiation. The drawable canvas is not fixed. 576×288 is the pre-report fallback — the stock G2 scene canvas, which firmware blits 1:1 into the 640×480 panel. Glassly CFW rasterizes scenes phone-side straight into the panel and publishes its real canvas in the glasses status; the engine then overrides the model profile with the reported size. Because CFW frames are not bound by the stock container pools (6 text / 4 image), element budgets are lifted alongside the canvas: 24 text / 16 image on a raster CFW build, and 120 shared elements on a CFW build that reports vector support (shapes and images each cost one cached slot, so shape-heavy frames get one larger budget).
Read the budgets and canvas from engine.glasses.capabilities() at runtime. They change when the glasses reconnect with different firmware — never bake 576×288 or the stock pools into a host.

engine.session

The cloud (cloud-v2) live-session surface. engine owns the cloud client — it constructs it from engine-owned transports + the auth you passed to configure() — so this reads the session it manages.
status is one of connected | connecting | reconnecting | disconnected; audioTransport is udp | ws | offline | none.

engine.settings

Typed keyed user settings over the engine-owned settings store.

engine.reports

Bug report and feedback submission. The OEM writes its own report screen, trigger labels, rating controls, and screenshot picker UX; engine owns runtime context collection, recent phone logs, Cloud V2 submission, artifact upload, dedupe, and glasses notification.

engine.dev

Developer/debug surface — backend + cloud-v2 URL overrides, reconnect, version gate.

engine.permissions

OS permissions — the raw check/request ops (your UI adds the rationale dialogs).
Feature keys: microphone · camera · calendar · location · background_location · bluetooth · phone_state · post_notifications.

engine.phoneNotifications

Forward phone notifications to the glasses, with a per-app blocklist. Android-only (getters return safe defaults on iOS).

engine.notifications

Inbound alerts engine→host — conditions engine detects, your UI renders.

engine.ota

Firmware OTA. Engine owns availability checks and install orchestration; the host progress screen is a pure renderer over the coordinator snapshot.
engine.ota.installSession fronts the install state machine for a progress screen: prepare(result), attach(), detach(), retry(), finish(), discard(), snapshot(), onSnapshot(cb). Every watchdog, retry, and reconnect rule lives in the coordinator — the screen only renders the snapshot. Gallery sync (hotspot → wifi → HTTP fetch → process → store). Engine orchestrates; the host renders its own alerts and navigation off onNotice.

engine.miniapps

Miniapp lifecycle. The miniapp WebView is a host component — engine ships the bridge primitives (buildMiniappGlobalsScript, buildUiShim, the JSRuntime router), exported from @glassly/engine directly; your app mounts the <WebView> and wires it to those. This facade is the lifecycle half.

What the host provides

The boundary is small and explicit: the host provides its UI, its login, and optional config — engine owns the entire runtime. The only required seam is auth.getSubjectToken (passed to configure()); engine owns token exchange, refresh, storage, the cloud client, glasses/BLE, settings, speech, display, and the miniapp runtime from there.
You may see internal configureRuntime(...) wiring in the first-party Glassly App — that’s transitional scaffolding for migrating Glassly’s own screens, not part of the OEM contract. It deletes itself as each domain lands in engine. An OEM only ever calls configure({auth, config?}) + start().