███████ ██    ██ ███████ ███    ██  ███████  ██████  ██    ██ ███    ██ ██████  ██████  ██    ██ ██    ██ ████████ ████████
  ██      ██    ██ ██      ████   ██  ██      ██    ██ ██    ██ ████   ██ ██   ██ ██   ██  ██  ██  ██    ██ ╚══██╔══╝╚══██╔══╝
  █████   ██    ██ █████   ██ ██  ██  █████   ██    ██ ██    ██ ██ ██  ██ ██   ██ ██████    ████   ██    ██    ██       ██
  ██       ██  ██  ██      ██  ██ ██  ██      ██    ██ ██    ██ ██  ██ ██ ██   ██ ██   ██    ██    ╚██  ██╔╝   ██       ██
  ███████   ████   ███████ ██   ████  ██       ██████   ██████  ██   ████ ██████  ██   ██    ██     ╚████╔╝    ██       ██

Project a glanceable HUD of your FoundryVTT D&D session onto Even Realities G2 AR glasses (576 × 288, 4-bit greyscale phosphor green), driven by tap / scroll / long-press gestures from the Even R1 smart ring. Eyes on the table, not on a laptop.

576×288px / eye
4-bitgreyscale
5–15fps target
13weeks MVP
4380+lines spec
v0.9.124 invariants · ×5 cross-check + spot-check + Phase 15 re-check

Four ideas, no magic.

The MVP is deterministic — every action is explicit gesture → tool → Foundry. AI is an optional V2 add-on, never a dependency.

Glanceable HUD

Map base · persistent status corner card · overlay panels stacked like Foundry desktop windows. A single layered UI, never a paginated app.

Gesture-driven

R1 ring: tap to cycle, double-tap to back, scroll to navigate, long-press for the Quick Action menu. No on-glass keyboard, ever.

Foundry as truth

Every action goes through Activity#use() with all rules, hooks, MidiQOL, advantage / disadvantage. The DM keeps full veto power.

Voice via MCP (V2)

Optional foundry-mcp server exposes Foundry tools as Model Context Protocol. Drive from Claude Desktop or any MCP client. Plug-out, no cascade.

Four rules. Non-negotiable.

Every PR, every audit, every release must satisfy them. They're constraints, not guidelines — ratified in §0.1 of the spec as the contract between today's design and tomorrow's implementation.

INV-1 · Layout integrity

Formatting and layout are dynamic and always perfect. Frame corners, dividers and columns align to the character in every state — HP 7 / 70 / 700, names from 4ch to 16ch, Italian to English — never misaligned for any reason. Snapshot tests + Box/TextRun render contract.

INV-2 · Online cross-validation

Every technical claim cites a canonical upstream source — Even Hub, foundryvtt.com/api, dnd5e wiki, MCP spec, vendor pricing. Re-verified before each version bump and Phase 0 GO/NO-GO. Drift is classified, fixed and logged. Three rounds completed; the fourth is the next pre-implementation audit.

INV-3 · Documentation coherence

Spec / README / showcase are always coherent and updated in the same commit for any cross-cutting change — version, fps target, phase count, hardware spec, locale set. No half-updated states. Cross-reference integrity is a hard gate.

INV-4 · Code quality

Code is clean, optimized, documented — and zero dead or unreachable code tolerated. Biome + TS strict + Vitest coverage gate enforce in CI. // TODO without an issue/ADR link fails the build. JSDoc/TSDoc on every public API. Hot-path benchmarks gate regressions.

Validated against upstream docs.

Every spec parameter below is cited verbatim from Even Realities and FoundryVTT documentation, re-verified across 3 cross-check rounds on 2026-05-10.

Even Realities G2

Smart Glasses · Display

576 × 288 · 4-bit greyscale · 16 levels green 4 image + 8 other containers · isEventCapture
Resolution576 × 288 px / eye
Color4-bit greyscale (16 levels green)
Containersmax 4 image + 8 text/list per page
Image size20–200 px W × 20–100 px H
Text container1 000 char (2 000 with upgrade)
List container20 items × 64 char, no in-place updates
Networkingfetch / XHR / WebSocket · whitelisted origins
Layoutabsolute pixel from top-left, no DOM/CSS
Microphone4-mic directional array · PCM 16 kHz s16le mono via bridge.audioControl()
Audio out❌ no speaker · feedback is visual only
Camera❌ none (intentional)
Plugin runs onpaired phone WebView (not on G2 firmware)
✓ verified · hub.evenrealities.com/docs/guides/{display, device-apis, getting-started/overview}

Even Realities R1

Smart Ring · Controller

tap scroll long-press
ConnectionBLE → Even App → G2
Gesturestap · scroll · long-press
BiometricsHR · HRV · SpO₂ · skin temp · steps · sleep
Materialzirconia ceramic + medical-grade stainless steel
WaterIP68 · 50 m / 30 min
Battery~4 days · ~90 min full charge
Operating temp-10 °C to 45 °C
✓ verified · evenrealities.com/smart-ring

Setup happens on the phone. The G2 stays keyboardless.

The G2 has no virtual keyboard, by design. Foundry connection bootstrap — bridge URL, auth token, character pick — lives in the Even Realities App per-plugin settings UI, the same surface Conversate / Translate / Teleprompt use. Pairing is a QR scan from the Foundry desktop module: no manual token copy-paste in the clipboard, audit trail kept by the DM. See §3.8 / §7.14.7.

┌───────────────────────────────────────────────────────────────────┐
│  EvenFoundryVTT — Setup                                       ✕   │
├───────────────────────────────────────────────────────────────────┤
│                                                                   │
│  STEP 1 / 3 · Connection profile                                  │
│  ◉ Homelab (LAN)        ○ Cloud bridge        ○ Local dev         │
│  Bridge URL                                                       │
│  ┌─────────────────────────────────────────────────────────┐      │
│  │ https://homelab.lan:8910                                │      │
│  └─────────────────────────────────────────────────────────┘      │
│                                                                   │
│  STEP 2 / 3 · Auth token                                          │
│  ┌─────────────────────────────────────────────────────────┐      │
│  │ evf_•••••••••••••••••••••••••                          │      │
│  └─────────────────────────────────────────────────────────┘      │
│  [ 📷 Scan QR from Foundry module ]   [ 📋 Paste from clipboard ] │
│                                                                   │
│  STEP 3 / 3 · Character                                           │
│  ✓ Connected to Foundry world "Homebrew 2024"                    │
│  ◉ Thorin Mountainforge  (Fighter 3 / Wizard 5, multi)            │
│  ○ Lyra Brightleaf       (Cleric 7)                               │
│  ○ Drak'val              (Barbarian 6)                            │
│  ☑ Auto-connect when G2 is worn                                   │
│                                                                   │
│              [ Back ]              [ Save & connect ▶ ]           │
└───────────────────────────────────────────────────────────────────┘

Three settings surfaces

Foundry world (server-side, all players). Even App phone settings (text input, per-device bootstrap). G2 device-local (gesture toggles only, e.g. [M] map mode, [N] language). A simple decision tree picks where each new setting lives. §7.14.6

QR pair, never paste

Foundry module Settings → "Pair a G2 device" → 24h opaque bearer + QR. Scan once, persist on phone. The bearer never sees the user's clipboard. Pairings are listed and revocable from Foundry by the DM. §7.14.7.3 / §11.5.4

Server-hosted plugin code

Plugin code lives on a server (CDN-friendly static HTML+JS). The Even Realities App fetches the URL into the WebView. Two URLs in app.json: plugin host + bridge. Local dev uses your LAN IP — not localhost (the phone can't resolve it). §3.7

The HUD, in your face.

Click a tab to mount a panel over the map base layer. The persistent status HUD never disappears — it's always there in the corner, exactly like a Foundry window with a pinned mini character sheet. Mockups taken verbatim from the spec § 7.


      
R1: scroll = pan · tap = ping · long-press = quick action mode: ▶ RASTER (toggle GLYPH)

Three boundaries, three contracts.

Every plugin slot is versioned. dnd5e v6 lands? swap the Foundry adapter — no cascade. Even SDK changes? swap the provider. New ring (R2)? swap the event source. Forward compat is a primary requirement.

▶ MVP (always-on, deterministic) Even G2 Glasses 576 × 288 · 4-bit layered HUD UI Even R1 Ring tap · scroll · long-press + biometrics BLE Bridge Service (Node.js · homelab) REST + WS · auth · CORS · rate limit tool registry · state cache · delta diff capability negotiation HTTPS / WS FoundryVTT v13.347+ · dnd5e 5.x evenfoundryvtt module · readers · writers Activity#use · MidiQOL · socketlib · hooks SINGLE SOURCE OF TRUTH ⋯ V2 OPTIONAL MCP Client Claude Desktop · Code · ChatGPT built-in STT + UI foundry-mcp stdio · Streamable HTTP cast_spell · weapon_attack · clarify resources: actor / scene / combat MCP HTTPS

Foundry canvas → 4-bit dithered phosphor.

Inspired by the Doom-on-exotic-devices pattern: state runs on capable hardware, gets rasterized + dithered server-side, frames stream to the constrained display via slow channel. Nine deterministic stages, each with a time budget.

01
Capture
PIXI extract
30–80 ms
02
Resample
OffscreenCanvas Lanczos
5–10 ms
03
Greyscale
Y = 0.299R + …
2–5 ms
04
Quantize
FS / Atkinson / Bayer
5–15 ms
05
Tile 200×100
2 × 2 split
< 1 ms
06
Delta
xxHash per tile
< 1 ms
07
Encode
PNG indexed 4-bit + RLE
5–15 ms
08
Wire
WS → BLE 4.2+ DLE
3–80 ms
09
Apply
updateImageRawData
firmware

Library stack benchmarked: image-q + upng-js + xxhash-wasm = 30–50 % compute reduction vs roll-your-own. Bundle ~ 90 KB gzipped.

Six layers, 5 to 15 fps.

BLE bandwidth is the bottleneck on a 4-bit greyscale phosphor display. The MVP commits to 5 fps event-based standard. The 15 fps stretch needs all six layers + Phase 0 favorable signals (partial-update API, BLE 4.2 DLE).

L0
naïve baseline4 tiles full PNG, no delta
~ 1.5 fps
L1
Per-tile delta hashxxHash · push only changed tiles
~ 3–6 fps
L3
Static layer cachingwalls/floors recomputed only on scene change
~ 5–8 fps
L4
Custom RLE 4-bituniform regions 1.5–25× compression
~ 5–10 fps
L2
Sub-tile delta 20×20partial updates · token move = 4–9 sub-tiles
~ 8–12 fps
L5
BLE 4.2+ DLEMTU 244 byte · 700–1000 kbps real-world
15 fps ✓
L6 — adaptive frame rate (idle 0.3 / slow 3–5 / active 8–15 / storm 0.5–2 fps) reduces battery drain ~ 50 % across a session.

Locale follows Foundry. Override on the glasses.

Internationalization is wired in from the MVP — the locale auto-detects from game.i18n.lang in Foundry and broadcasts at handshake; the player can override it directly from the glasses without touching the world setting. Catalogs live in Foundry (dnd5e + module languages), the G2 carries no strings of its own. See §7.16 of the spec.

╔═══════════════════════════════════════════════════════════════════════════════╗
║                              ◈  LANGUAGE                                      ║
║                                                                               ║
║                       ▶ [ • ]  Auto (Foundry: it)                             ║
║                         [ ◦ ]  English        (en)                            ║
║                         [ ◦ ]  Italiano       (it)                            ║
║                         [ ◦ ]  Deutsch        (de)                            ║
║                         [ ◦ ]  Español        (es)                            ║
║                         [ ◦ ]  Français       (fr)                            ║
║                         [ X ]  Cancel                                         ║
║                                                                               ║
║                       R1 scroll=select  tap=apply  long=cancel                ║
╚═══════════════════════════════════════════════════════════════════════════════╝

Source of truth: Foundry

Locale is read from game.i18n.lang at handshake. Catalogs come from dnd5e (en/de/es/fr/it/ja/ko/pl/pt-BR/ru/zh-CN) and the evenfoundryvtt module. The G2 ships no strings.

Override on glasses

Long-press R1 → Quick Action → [N] Language. Selection is device-local: it never modifies the world setting. Auto mode follows the GM live; explicit override sticks per-device.

Width-budget by key

Every i18n key carries a _max width. The build verifies all locales fit, otherwise falls back to English. Layout integrity (INV-1) holds even when Italian strings run 30% longer than English.

Phase 0–13. MVP in 13 weeks.

P0Week 0
Hardware / SDK validation
R1 events · updateImageRawData format · BLE bandwidth · partial-update API · DLE 4.2+ · GO/NO-GO decision tree (Branch A / B / C)
P1Week 1–2
Foundation
monorepo skeleton (pnpm + TypeScript) · shared protocol · CI pipeline · ADR-0001 to ADR-0004
P2Week 2–3
Foundry module core
readers (character / combat / scene / log) · WS server · capability handshake · contract fixtures
P3Week 3–4
Bridge skeleton
Fastify + ws · auth bearer 24 h · tool registry · CORS · /healthz /readyz /metrics · Docker
P4Week 4–7
G2 layered engine + map modes
layer manager · raster pipeline (Layers 1+3+4+6 base, 2+5 conditional) · glyph fallback · boot splash · render primitives
P5Week 6–8
Panel plugin system
Sheet 6-tab · Combat · Log · Spellbook · Inventory · auto-discovered panels · snapshot fixtures
P6Week 7–8
R1 + event plumbing
ring-r1 provider · Quick Action menu · gesture latency telemetry
P7Week 8–9
Foundry write path
Activity#use wrapper · v13 targeting · AbilityTemplate AoE · socketlib GM forward · MidiQOL workflow
P8Week 9–10
Manual action UX
tap-to-cast · tap-to-use · target picker · toast banner · action economy widget
P9Week 10–11
Action economy + edge cases
precondition checks · concentration drop · multi-attack · slot consumption · reaction prompts
P10Week 11–13
Polish + 4 h field test
offline mode · latency profiling · real D&D session · runbook + video demo
— end MVP — V2 OPTIONAL below —
P11Week 14–15V2
foundry-mcp server
MCP TS SDK · tools mirror Tool Registry · resources actor/scene/combat · Claude Desktop integration
P12Week 15–16V2
Voice UX tuning
system prompt template · IT↔EN spell name lookup · worked examples A/B/C end-to-end
P13post-V2V2
Stretch goals
reaction bot · biometric narrative cues · multi-player bridge · dnd5e 6.x adapter · PF2e adapter · portrait images · Dice So Nice raster · headless Foundry session

"I cast Fireball on the goblins" · ~1.2 s.

V2 only — never required. The MCP server lives outside the core, exposes the same tool registry the MVP already uses for manual actions. Add Claude Desktop or any MCP client; remove it without touching anything else.

Mic capture: hardware-feasible ✓

Verified upstream (hub.evenrealities.com/docs/guides/device-apis): G2 4-mic array streams PCM 16 kHz s16le mono to plugins via bridge.audioControl(true). No extra hardware. §3.5

AI on-glasses: NOT possible

EvenAI ("Hey Even") is proprietary, cloud-backed, and exposes no API to dev apps — not us, not anyone. The voice/transcript event types simply aren't in the SDK taxonomy. Our MCP-via-external-client is therefore a platform constraint, not a design choice. §3.6

No speaker → visual feedback only

The G2 has no speaker, bone-conduction or audio output (verbatim Even docs: "no audio output, no arbitrary pixel drawing, no camera"). Every result lands as a toast banner (§7.15.2) or status HUD update — never a beep, never a TTS line.

▸ 01
Player long-presses R1 and speaks naturally
~ 0 ms
▸ 02
MCP client captures audio + STT
~ 250–310 ms · AssemblyAI / built-in
▸ 03
LLM tool call streamed
~ 600 ms · Claude Sonnet 4.6
▸ 04
cast_spell tool received by foundry-mcp
~ 5 ms
▸ 05
POST /v1/action/use-activity on bridge
~ 10 ms
▸ 06
activity.use() + MidiQOL + AbilityTemplate
~ 150 ms · saves rolled, damage applied
▸ 07
Foundry hooks → bridge WS → G2 toast
~ 60 ms · HUD updated

The G2 itself never runs an LLM. It receives the result, renders a 3-second toast banner over the map, and the persistent status HUD updates (HP, slots, conditions). The LLM is free to be replaced — every component is a plugin slot.

Open-source, mostly TypeScript.

Library choices are research-driven and documented as ADRs. Every external dependency was evaluated against alternatives in § 11.5.7 of the spec.

TypeScript pnpm workspaces Vitest Biome Changesets Node.js 22 Fastify ws Redis (opt) Docker Compose FoundryVTT v13.347+ dnd5e 5.x socketlib MidiQOL Even Hub SDK image-q v4 upng-js v2 xxhash-wasm v1 sharp (bridge) OffscreenCanvas @modelcontextprotocol/sdk AssemblyAI Anthropic Claude GitHub Actions pino Prometheus