| name | g2-sdk |
| description | Even Realities G2 smart glasses SDK v0.0.9 reference. Use when building or modifying G2 glasses features, display layouts, event handling, audio recording, IMU, container management, or anything related to the glasses hardware and firmware.
|
Even Realities G2 – SDK v0.0.9 Reference
Complete SDK API reference for the Even G2 smart glasses. Covers all APIs, hardware constraints, display rules, event handling, audio, IMU, and known quirks.
Hardware Summary
- Dual micro-LED displays (green), 576x288 px per eye, 4-bit greyscale (16 shades)
- BLE 5.x (~28m range), paired via iPhone or Android (Even App)
- Microphone (SDK accessible), IMU (SDK accessible), no camera, no speaker
- R1 control ring for scroll/click input
- Touch gestures on temple tips
Architecture
[Your server] <--HTTPS--> [Phone WebView] <--BLE--> [G2 Glasses]
- Your web app runs on your server (any hosting)
- The Even App (Flutter, iOS/Android) opens your URL in
flutter_inappwebview
- The glasses are a display + input peripheral — no code runs on them
- The SDK injects
EvenAppBridge into the WebView's window object
SDK Setup
npm install @evenrealities/even_hub_sdk@^0.0.9
import { waitForEvenAppBridge, EvenAppBridge } from '@evenrealities/even_hub_sdk'
const bridge = await waitForEvenAppBridge()
const bridge = EvenAppBridge.getInstance()
Display System
Canvas
- 576x288 pixels, origin (0,0) at top-left
- All colours converted to 4-bit greyscale (16 levels of green)
- White = bright green, black = off
Container Rules
- Max 12 containers per page — up to 8 text + up to 4 image
- Exactly one container must have
isEventCapture: 1
- Containers positioned absolutely with pixel coordinates
- No CSS, no flexbox, no DOM — firmware renders directly
- Containers can overlap; later declarations draw on top
Shared Container Properties
| Property | Type | Range | Notes |
|---|
xPosition | number | 0–576 | Left edge px |
yPosition | number | 0–288 | Top edge px |
width | number | 0–576 | (20–288 for images) |
height | number | 0–288 | (20–144 for images) |
containerID | number | any | Unique per page |
containerName | string | max 16 chars | Unique per page |
isEventCapture | number | 0 or 1 | Exactly one must be 1 |
borderWidth | number | 0–5 | 0 = no border |
borderColor | number | 0–15 (list), 0–16 (text) | Greyscale level |
borderRadius | number | 0–10 | Fixed spelling in v0.0.9 (was borderRdaius) |
paddingLength | number | 0–32 | Uniform padding all sides |
Text Containers (TextContainerProperty)
Plain text, left-aligned, top-aligned. No font size, bold, italic, or alignment options.
new TextContainerProperty({
xPosition: 0, yPosition: 0, width: 576, height: 288,
borderWidth: 0, borderColor: 5, borderRadius: 0, paddingLength: 4,
containerID: 1, containerName: 'main-text',
content: 'Hello from G2',
isEventCapture: 1,
})
Content limits:
createStartUpPageContainer: max 1000 chars
textContainerUpgrade: max 2000 chars
rebuildPageContainer: max 1000 chars
Behaviour:
- Text wraps at container width; overflows scroll if
isEventCapture: 1
\n for line breaks, Unicode works (arrows, box-drawing chars)
- ~400–500 chars fill a full-screen container
- To "centre" text, pad with spaces manually
- Paginate long text into ~400-char pages for best UX
Partial update:
await bridge.textContainerUpgrade(new TextContainerUpgrade({
containerID: 1,
containerName: 'main-text',
contentOffset: 0,
contentLength: 100,
content: 'Updated text',
}))
List Containers (ListContainerProperty)
Native scrollable list — firmware handles scroll highlighting.
new ListContainerProperty({
xPosition: 0, yPosition: 0, width: 576, height: 288,
borderWidth: 1, borderColor: 13, borderRadius: 6, paddingLength: 5,
containerID: 1, containerName: 'my-list',
isEventCapture: 1,
itemContainer: new ListItemContainerProperty({
itemCount: 5,
itemWidth: 560,
isItemSelectBorderEn: 1,
itemName: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5'],
}),
})
| Property | Range | Notes |
|---|
itemCount | 1–20 | Must match itemName.length |
itemWidth | pixels | 0 = auto-fill |
isItemSelectBorderEn | 0 or 1 | Selection highlight |
itemName | max 64 chars each | Plain text, single line |
Key: Cannot update items in-place — must rebuildPageContainer. Click events report currentSelectItemIndex and currentSelectItemName.
Image Containers (ImageContainerProperty)
new ImageContainerProperty({
xPosition: 200, yPosition: 100, width: 100, height: 50,
containerID: 3, containerName: 'logo',
})
| Constraint | Value |
|---|
| Width | 20–288 px |
| Height | 20–144 px |
| Colour | 4-bit greyscale |
| Data formats | number[], Uint8Array, ArrayBuffer, base64 string |
| Concurrent sends | Not allowed — queue sequentially |
| Startup | Cannot send data during createStartUpPageContainer — create empty, then updateImageRawData |
| Tiling | Image tiles if smaller than container — always match sizes |
Input Events
Event Types (OsEventTypeList)
| Event | Value | Source |
|---|
CLICK_EVENT | 0 | Ring tap, temple tap |
SCROLL_TOP_EVENT | 1 | Scroll reaches top boundary |
SCROLL_BOTTOM_EVENT | 2 | Scroll reaches bottom boundary |
DOUBLE_CLICK_EVENT | 3 | Double-tap |
FOREGROUND_ENTER_EVENT | 4 | App comes to foreground |
FOREGROUND_EXIT_EVENT | 5 | App goes to background |
ABNORMAL_EXIT_EVENT | 6 | Unexpected disconnect |
SYSTEM_EXIT_EVENT | 7 | System-initiated exit |
IMU_DATA_REPORT | 8 | IMU data push (v0.0.9+) |
Event Source (EventSourceType) — v0.0.9+
Distinguishes which hardware triggered the event.
| Source | Value |
|---|
TOUCH_EVENT_FORM_DUMMY_NULL | 0 |
TOUCH_EVENT_FROM_GLASSES_R | 1 |
TOUCH_EVENT_FROM_RING | 2 |
TOUCH_EVENT_FROM_GLASSES_L | 3 |
Available on sysEvent.eventSource.
Event Delivery
bridge.onEvenHubEvent((event: EvenHubEvent) => {
})
List event fields: containerID, containerName, currentSelectItemName, currentSelectItemIndex, eventType
Text event fields: containerID, containerName, eventType
System event fields: eventType, eventSource (v0.0.9+), imuData (v0.0.9+), systemExitReasonCode
Critical Event Quirks
-
CLICK_EVENT = 0 becomes undefined — SDK normalises 0 to undefined. Always check:
if (eventType === 0 || eventType === undefined) { }
-
currentSelectItemIndex missing for index 0 — fall back to tracking selection in app state.
-
Event routing depends on isEventCapture — the container with capture determines listEvent vs textEvent.
-
Simulator vs real device — simulator sends sysEvent for button clicks; real hardware sends textEvent or listEvent. Handle all three sources.
-
Swipe throttling — use a ~300ms cooldown to prevent duplicate actions.
Page Lifecycle
createStartUpPageContainer
Call exactly once at startup. Returns StartUpPageCreateResult (0=success, 1=invalid, 2=oversize, 3=outOfMemory).
await bridge.createStartUpPageContainer(new CreateStartUpPageContainer({
containerTotalNum: 3,
textObject: [textContainer],
imageObject: [imgContainer],
}))
rebuildPageContainer
Full page replace — all containers destroyed and recreated. Scroll/selection state is lost. Brief flicker on hardware.
await bridge.rebuildPageContainer(new RebuildPageContainer({
containerTotalNum: 1,
textObject: [newTextContainer],
}))
textContainerUpgrade
In-place text update. Faster, no flicker. Returns boolean.
updateImageRawData
Update image container data. Must be called after page creation. Returns ImageRawDataUpdateResult. No concurrent sends.
await bridge.updateImageRawData(new ImageRawDataUpdate({
containerID: 3,
containerName: 'logo',
imageData: pngBytes,
}))
shutDownPageContainer
await bridge.shutDownPageContainer(0)
Audio
bridge.audioControl(true)
bridge.audioControl(false)
PCM format:
- Sample rate: 16kHz
- Frame length: 10ms (dtUs 10000)
- Frame size: 40 bytes (160 samples x 2 bytes)
- Encoding: PCM S16LE (signed 16-bit little-endian)
- Channels: mono
Receiving audio:
bridge.onEvenHubEvent((event) => {
if (event.audioEvent?.audioPcm) {
const pcmData: Uint8Array = event.audioEvent.audioPcm
}
})
IMU (v0.0.9+)
Control the IMU hardware and receive real-time motion data (accelerometer/gyroscope).
import { ImuReportPace } from '@evenrealities/even_hub_sdk'
await bridge.imuControl(true)
await bridge.imuControl(true, ImuReportPace.P200)
await bridge.imuControl(false)
ImuReportPace values: P100 (100ms), P200, P300, P400, P500, P600, P700, P800, P900, P1000 (1000ms)
Receiving IMU data:
bridge.onEvenHubEvent((event) => {
if (event.sysEvent?.eventType === 8 && event.sysEvent.imuData) {
const { x, y, z } = event.sysEvent.imuData
}
})
IMU data arrives via sysEvent with eventType: IMU_DATA_REPORT (8) and imuData: { x, y, z }.
Launch Source (v0.0.9+)
Detect whether the app was launched from the App Menu or the Glasses Menu.
import { LAUNCH_SOURCE_APP_MENU, LAUNCH_SOURCE_GLASSES_MENU } from '@evenrealities/even_hub_sdk'
const unsub = bridge.onLaunchSource((source) => {
if (source === LAUNCH_SOURCE_GLASSES_MENU) {
}
})
Type: LaunchSource = 'appMenu' | 'glassesMenu'
Constants: LAUNCH_SOURCE_APP_MENU, LAUNCH_SOURCE_GLASSES_MENU
Note: Fired once by SDK after page load (not on refresh). Returns unsubscribe function.
Device Info
const device = await bridge.getDeviceInfo()
const unsub = bridge.onDeviceStatusChanged((status) => { ... })
DeviceConnectType: None, Connecting, Connected, Disconnected, ConnectionFailed
User Info
const user = await bridge.getUserInfo()
Local Storage (phone-side)
await bridge.setLocalStorage('key', 'value')
const value = await bridge.getLocalStorage('key')
What the SDK Does NOT Expose
- No direct BLE access
- No arbitrary pixel drawing (container model only)
- No audio output (no speaker)
- No text alignment (no centre/right)
- No font size, weight, or family
- No background colour or fill
- No per-item list styling
- No programmatic scroll position control
- No animations or transitions
Complete Export List (v0.0.9)
Enums: BridgeEvent, DeviceConnectType, DeviceModel, EvenAppMethod, EvenAppMessageType, EvenHubErrorCodeName, EvenHubEventType, EventSourceType, ImageRawDataUpdateResult, ImuReportPace, OsEventTypeList, StartUpPageCreateResult
Classes: CreateStartUpPageContainer, DeviceInfo, DeviceStatus, EvenAppBridge, ImageContainerProperty, ImageRawDataUpdate, ImageRawDataUpdateFields, ImuCtrlCmd, ImuCtrlCmdResponse, IMU_Report_Data, ListContainerProperty, ListItemContainerProperty, List_ItemEvent, RebuildPageContainer, ShutDownContaniner, TextContainerProperty, TextContainerUpgrade, Text_ItemEvent, UserInfo, Sys_ItemEvent
Types: AudioEventPayload, EvenHubErrorCode, EvenHubEvent, EvenHubEventPayload, JsonRecord, LaunchSource
Constants: LAUNCH_SOURCE_APP_MENU, LAUNCH_SOURCE_GLASSES_MENU
Functions: waitForEvenAppBridge, bytesToJson, createDefaultEvenHubEvent, evenHubEventFromJson, isObjectRecord, normalizeLooseKey, pick, pickLoose, readNumber, readString, toNumber, toObjectRecord, toString
Error Codes
| Context | Code | Meaning |
|---|
| Page create | 0 / success | Success |
| Page create | 1 / invalid | Invalid config |
| Page create | 2 / oversize | Oversize |
| Page create | 3 / outOfMemory | Out of memory |
| Image update | success | OK |
| Image update | imageException | Processing error |
| Image update | imageSizeInvalid | Wrong dimensions |
| Image update | imageToGray4Failed | Greyscale conversion failed |
| Image update | sendFailed | BLE send failed |
UI Patterns
Fake Buttons with Text
> Return
Delete note
Track cursor position, update via textContainerUpgrade.
Progress Bars with Unicode
const bar = '━'.repeat(n) + '─'.repeat(total - n)
Multi-Slot Layout
Multiple text containers as rows (e.g. 3 at height: 96 = 288px total). Toggle borderWidth for selection highlight. With 8 text containers now available, more complex layouts are possible.
Event Capture for Image Apps
Place a full-screen text container (content: ' ') with isEventCapture: 1 behind the image container for input events.
Page Flipping for Long Text
Pre-paginate into ~400-char pages. Track pageIndex, rebuild on scroll boundary events.
Simulator
Install: npm install -D @evenrealities/evenhub-simulator@^0.6.2
npx evenhub-simulator [OPTIONS] [targetUrl]
| Option | Description |
|---|
-c, --config | Config file path |
-g, --glow / --no-glow | Toggle display glow |
--list-audio-input-devices | List mic devices |
--aid | Select audio input device |
Simulator v0.6.2 supports: 12-container limit, 288x144 image sizes, IMU data simulation, launch source simulation.
Simulator caveats: Font rendering differs, list scrolling varies, image processing is faster, status events may not fire. Always test on real hardware.
CLI Tools (@evenrealities/evenhub-cli)
See the evenhub-cli skill for full CLI reference. Quick commands:
npx evenhub qr --url "https://your-tunnel.ngrok-free.app"
npx evenhub pack app.json ./dist -o app.ehpk
npx evenhub login
npx evenhub init
Reference Apps