Skip to content
SDK Docs
Discord Order Now

On the glasses

Input

Handle taps, swipes and holds from the touch bar and the MIRA Ring.

Every gesture arrives in your app_event(event) export, and the MIRA Ring sends the same events as the touch bar.

Events

ValueEvent
0Tap
1Swipe forward
2Swipe backward
3Double tap (only if your app claims it)
9Long press (only if your app claims holds)
10Hold start (only if your app claims holds)
12Hold end (only if your app claims holds)

In menus and readers, event 1 moves to the previous item (up, left or earlier) and event 2 moves to the next one (down, right or later). MIRA’s sidebar and cards follow the same rule, so keep it and your app will feel familiar. Games can map the two swipes however they like.

Handle input
#[no_mangle]
pub unsafe extern "C" fn app_event(event: i32) {
    match event {
        0 => select(),            // tap
        1 => move_focus(-1),      // previous item
        2 => move_focus(1),       // next item
        _ => {}
    }
}

Double tap and the sidebar

MIRA’s shell sees every gesture first. By default, double tap opens the sidebar so people can switch apps or go Home. To use double tap inside your app, claim it:

Claim double tap
#[path = "../Shared/content.rs"] mod content;

unsafe fn start_game() {
    content::double_tap_local(true); // double tap now reaches app_event as 3
}

A notification or an open sidebar still gets double tap first. Claims reset whenever the wearer switches apps, so claim again in app_init if you always need it.

Long press and holds

Call content::holds_local(true) to receive long press (9), hold start (10) and hold end (12).

  • Always handle hold end, even if you ignored the start.
  • Before starting a held action, check that MIRA isn’t covering your app with content::sidebar_open() and content::overlay_visible().

The cursor

MIRA draws one shared cursor that glides from control to control. Tell it where your focused control is, and MIRA animates it there:

Move the cursor
content::cursor(x, y, true);   // beside the focused item
content::cursor(0, 0, false);  // hide it on screens with nothing to select
  • Use the same position and scroll offset as your highlight, so the cursor and highlight never disagree.
  • Update it on every focus change, including frames that reuse retained content.
  • Place it beside the selection rather than on top of its label.

The sidebar, dashboard and notifications show their own pointer, so you never need to draw one yourself.

Sidebar icon

Your app’s icon in the glasses sidebar is a 32 × 32 one-color image defined in Rust, next to your code:

app_icon!
#[path = "../Shared/content.rs"] mod content;

app_icon!(content::app_icon::Icon::new()
    .circle(16, 16, 12).line(10, 16, 22, 16).line(16, 10, 16, 22).0);

The builder draws two-pixel lines, rectangle outlines and circles. You can also pass a 128-byte mask directly: four bytes per row, most significant bit first. Define the icon once per app. Apps without a valid icon get a generic one.