session.display.render() draws to the glasses HUD. Each call describes the
whole frame: everything that should be on screen right now. The phone diffs it
against the previous frame, so elements with a stable id update in place (no
flicker), anything you leave out of the new frame comes off the screen, and
render([]) clears it. Your job is to describe the frame; the phone works out
what changed.
DISPLAY
hardware requirement in your manifest
so the miniapp only installs on glasses that can show anything.
Elements
Screen sizes
box is {x, y, w, h} in raw device pixels. Coordinates map 1:1 to the
device canvas, with the origin at the top-left:
We recommend designing your layout for 500 × 220. A frame that fits
500 × 220 renders as-is on every positioning device; on the G2’s larger canvas
it sits in the top-left with some margin. Boxes that run past the edge are
clamped, and elements past the device’s budget are dropped tail-first. Both
show up in the render result, so you find out.
When you want an exact fit instead (a full-screen caption, an element pinned
to the bottom edge), compute boxes from the connected device’s real canvas.
session.capabilities.display carries it, populated on the "ready" event:
Older glasses
Even Realities G1 and Vuzix Z100 show text but can’t place elements at coordinates, and their displays can’t show bitmaps. Render the same scene anyway: the phone converts it for them. Text elements collapse into a single full-view text layout in reading order (top to bottom, then left to right), and image and rect elements are dropped. The result tells you what happened (degraded: true, plus the dropped ids), and
session.capabilities.display.canPosition tells you up front which kind of
device you’re on.
In practice a text-first miniapp works everywhere with zero branching: a
caption app’s single full-canvas text element reads the same on every device.
If your layout leans on positioning or images, like a HUD with a minimap,
check canPosition and render a text-only variant for these devices.
Updating and clearing
Give any element that changes over time a stableid. Re-rendering with the
same id updates that element in place on the glasses, and unchanged elements
never re-cross Bluetooth, so pushing the whole frame on every change is cheap.
To take something off screen, leave it out of the next frame. To clear
everything:
Options and results
render(elements, options?) takes {view, durationMs} — view picks
"main" (default) or "dashboard", and durationMs auto-clears the frame
after that many milliseconds.
Awaiting is opt-in. A plain fire-and-forget call is fine, and the returned
promise never rejects:
Just showing text
The simplest useful frame is one text element covering the whole canvas — a status line, a caption, a “Saved” confirmation:style.breakMode ("character" | "character-no-hyphen" | "word" | "strict-word") controls how the text wraps inside its box.
Fitting text
The host wraps text using the connected glasses’ font metrics. The box is the available area; optionalstyle.maxLines imposes an additional line limit.
Leave it out to use the box’s capacity. Miniapps do not need device font tables.
style.textWindow chooses which end stays visible when text overflows:
"start" (default) keeps the beginning; "end" keeps the newest content.
style.overflow remains "clip" (default) or "ellipsis". An ellipsis appears
on the omitted side. These controls require Mentra App 3.2.1 or newer.
style.verticalAlign: "top" | "bottom" places the line region inside
its box. With maxLines, that region reserves the selected number of rows so
bottom captions don’t jump as partial transcripts grow. The outer box is always
a hard bound. On devices without calibrated text positioning, placement falls
back to the top and the result reports degradation for a bottom request.
G1/Z100 use their text-only row budgets; position and images degrade as above.
Text feedback
Pass{includeTextLayout: true} as the second render argument when a preview or
line-based progression needs the actual host-computed text:
end is exclusive. Source spans describe wrapped lines before an ellipsis is
applied. Inserted hyphens and ellipses do not consume source characters.
lineStarts lets a teleprompter replace its text at a host-computed line boundary
without measuring fonts. Feedback is keyed by the element id, or text[index]
for unnamed text. Dropped elements have no feedback. It describes the frame the
host compiled, not a hardware acknowledgment. Ignore older responses when a
newer frame has been submitted. Waiting for feedback is optional.
Dashboard view
render(elements, {view: "dashboard"}) targets the dashboard view, the
glasses’ status view that the user brings up with a glasses-specific gesture
(head-up on G1, a double-tap on others). The default is "main".
