A fast, glanceable tactical HUD for Even Realities G2.
Warning
Development status: Sandevistan is still under active development and has not been officially published on Even Hub. Builds from this repository are experimental and intended for local testing on supported G2 hardware.
Sandevistan is an unofficial, fan-made personal HUD for the Even Realities G2.
It renders a 576×288 tactical interface to Canvas, splits it into four 288×144
images, and sends those tiles through a bounded four-call SDK pipeline. The
current product candidate is /hud-canvas-fast.
The project favors useful information, predictable controls, and hardware-proven
behavior over browser-only effects. It has been tested on physical G2 glasses
with the Even Hub SDK pinned to 0.0.13, Even App 2.2.6, and updated G2
firmware.
- Why Sandevistan
- Phone companion
- HUD pages
- Interaction model
- Transport design
- Live data
- Localization
- Optional navigation
- Local development
- Build, test, and package
- Project structure
- SDK compatibility
- Privacy, attribution, and limitations
- Contributing
- License and trademarks
G2 is a constrained display, not a miniature phone. Sandevistan is designed around that fact:
- Large, high-contrast typography that remains legible on the optical display.
- Dense overview information distributed across four focused pages.
- Full-screen detail decks for maps, news, tasks, weather, and navigation.
- Canvas-first rendering for visual consistency and fast page changes.
- Four-call, fail-fast image transport with no deferred refresh queue.
- Keyless location, weather, news, and map data.
- Optional OpenRouteService routing with a device-local key or development fallback.
- An Even-style phone companion for configuration and live status.
- A dedicated developer screen for physical-hardware diagnostics.
The same /hud-canvas-fast entry point provides a light, touch-friendly
companion UI around the persistent G2 Canvas. Its home screen follows the Even
app's compact two-column card rhythm and keeps the live HUD preview mounted
while settings screens are open.
Eight cards open their settings directly, without an intermediate management menu:
| Card | Phone capability |
|---|---|
| Devices | G2/R1 availability, battery, and transport state |
| HUD layout | Enable and reorder glasses pages while keeping Overview |
| News | Enable, rename, add, or remove up to six HTTPS RSS/Atom sources |
| TODO | Add, edit, complete, reopen, and delete up to six tasks |
| Weather | Inspect current conditions and request one immediate refresh |
| Navigation | Validate and store a user-owned ORS key on the device |
| Language | Follow the system language or select one of 30 bundled languages |
| Developer | Inspect, copy, and clear the WebView trace |
The footer identifies the project, app-manifest version, development status, and GitHub repository. The phone UI never remounts the Canvas during navigation, so opening settings does not restart the G2 transport.
The dashboard keeps a 288×288 live map on the left and a page-specific information panel on the right.
| Page | Purpose |
|---|---|
OVERVIEW |
Local time, full date, current weather, and the connected device battery |
NEWS |
Current headlines from the enabled local RSS source list |
TODO |
Three persistent checklist items and today's completion progress |
WEATHER |
Current conditions, apparent temperature, humidity, precipitation, and wind |
NAVIGATION (active route only) |
Route state, remaining distance, next maneuver, and destination |
A single tap opens the active page's four-tile detail deck:
OVERVIEWopens the full-screen map.NEWSopens one real RSS story at a time with paginated body text.TODOopens the full checklist and selected item.WEATHERopens current conditions, hourly context, and a large tactical weather icon.NAVIGATIONopens the current maneuver and route progress.
The same gestures work from the G2 temple and the R1 ring:
- Scroll: move between dashboard pages.
- Single tap: open the active detail deck or activate its selected item.
- Fast double tap: return from a detail deck to its dashboard page.
- Dashboard double tap: replace all tiles with black images while leaving the app and event listeners alive; double tap again to restore the latest view.
Within full-screen details:
- News scrolls through the current article body before advancing to another story.
- TODO scroll selects an item; tapping toggles it in either direction.
- Navigation scroll selects route instructions; tapping returns to the active step.
- Map scroll direction is reserved for zoom: down zooms in and up zooms out.
The map zoom radius is remembered across dashboard, detail, and location updates:
850m, 650m, 500m, 375m, or 280m.
The display is divided into four named G2 image containers:
| Container | Image ID | Bounds |
|---|---|---|
sandevistanTL |
2 | left, top — 288×144 |
sandevistanTR |
3 | right, top — 288×144 |
sandevistanBL |
4 | left, bottom — 288×144 |
sandevistanBR |
5 | right, bottom — 288×144 |
The hardware-proven send order is:
- Initial display, restore, and full-screen detail:
3 → 5 → 2 → 4. - Dashboard page change: right side only,
3 → 5. - Map movement: left side only,
2 → 4. - Visible minute or battery change: top-right only,
3.
Only one accepted refresh owns the transport at a time. Up to four SDK tile
calls belonging to that refresh may be in flight; missing or invalid pipeline
values resolve to four, while explicit values from 1 through 4 remain
available for diagnosis. A tile whose encoded bytes match the last successful
send is skipped. Any refresh request arriving while transport is busy is
dropped immediately: it is not queued, merged, replayed, or retried. A failed
refresh remains failed and the next independent event may try again.
Content tiles use a four-level grayscale palette by default. On physical G2
hardware this reduced the measured full-frame payload by 54.4% and the median
restore latency by 24.8%. Solid-black hide frames bypass palette conversion
because their encoded payload is already minimal. Use
?pipeline=1&levels=original for the complete serial/original rollback.
See the pipeline hardware gate
and palette comparison.
This policy replaced an earlier backlog design that could accumulate tens of thousands of stale minute and location operations and eventually freeze the WebView.
Core features do not require an API key.
| Feature | Source | Refresh policy |
|---|---|---|
| Current location | Even Hub SDK | Initial reading, then accepted at 15s / 15m |
| Weather | Open-Meteo | 15-minute cache plus foreground recheck |
| News | Device-selected HTTPS RSS/Atom through a hardened same-origin proxy | Progressive library up to 100 stories; one-hour refill while idle |
| Roads and place labels | OpenStreetMap via Overpass | When the rounded location cell changes |
| Clock | Local device time | Minute boundary, skipped if that minute was already rendered |
| Battery | Even SDK device-state event | Only when the visible value changes |
If live position is unavailable, Sandevistan uses a recent cached position. If
there is no cached position, the HUD clearly identifies demo data instead of
presenting it as live. Missing map data renders NO DATA; missing GPS renders
NO GPS DATA. A location without a heading uses a hollow position circle rather
than a directional arrow.
Weather, news, and map failures retain the last successful value as stale data. RSS and Overpass access use same-origin server routes. Custom feeds are limited to validated public HTTPS URLs, reject credentials, fragments, non-default ports, IP literals, local/private host suffixes, redirects, non-feed content, responses over 1 MB, and requests over eight seconds.
Persistent values use the sandevistan:*:v1 local-storage namespace.
Sandevistan ships thirty structurally complete, offline locale packs:
Korean, English, Japanese, Simplified Chinese, Traditional Chinese,
Spanish, French, German, Italian, Portuguese, Dutch, Polish,
Russian, Ukrainian, Turkish, Arabic, Hebrew, Hindi, Bengali,
Indonesian, Vietnamese, Thai, Malay, Filipino, Swedish,
Norwegian, Danish, Finnish, Czech, and Romanian.
Each pack owns all phone, HUD, route, weather, default-task, and weekday copy. There is no runtime translation service and no English fallback for a registered language. Arabic and Hebrew set the phone companion to RTL while the fixed tactical HUD geometry remains LTR.
Every language receives exactly three built-in news channels from the shared
server catalog. The catalog contains ninety unique HTTPS URLs and can be
checked live, one request at a time, with npm run verify:rss-live. See
Adding a Sandevistan language for the
type-safe extension workflow.
Only destination search and route calculation require a key. The preferred flow is to enter a user-owned key in the Navigation card. Sandevistan validates it, stores it through the Even local-storage bridge, and sends it only in a dedicated same-origin request header. The server uses it for that request and never stores, returns, or logs it.
ORS_API_KEY remains an optional local-development fallback. Neither key path
uses Vite client variables or embeds a key in source, browser responses, logs,
or the EHPK package.
Without a key, location, weather, news, and the OSM map continue to work. Routing controls stay out of the way rather than occupying a disabled HUD panel.
With a key, the companion WebView can search Korean destinations and request
walking, cycling, or driving routes. During active guidance, location sampling
increases to 2s / 5m. Three consecutive positions at least 35m off route trigger
a recalculation, limited to one request every 30 seconds. Ending guidance clears
the route and restores the normal 15s / 15m location policy.
Recent routes are stored for at most six hours and return as stale context; the app never resumes guidance automatically.
Requirements:
- Node.js 22 or newer.
- npm.
- Even Realities app with Even Hub access for physical G2 transport.
- Tailscale or another phone-accessible local network when testing on hardware.
Install dependencies:
npm installStart the development server:
npm run dev -- --host 0.0.0.0 --port 4176 --strictPortOptionally enable the server-side development fallback:
ORS_API_KEY='<server-only-key>' \
npm run dev -- --host 0.0.0.0 --port 4176 --strictPortOpen the app through Even Hub → Scan QR:
http://<PHONE-REACHABLE-IP>:4176/hud-canvas-fast?sdk=0.0.13&build=<BUILD-ID>
No performance query is required. For an explicit transport rollback, use:
http://<PHONE-REACHABLE-IP>:4176/hud-canvas-fast?sdk=0.0.13&pipeline=1&levels=original&build=<BUILD-ID>
You can generate the configured QR code with:
npm run qr
npm run qr:rollbackA normal desktop or mobile browser shows the Canvas preview. G2 transfer starts only when the page is opened through the Even app bridge.
All test execution is serial to avoid resource contention with the G2 development environment.
npm test
npm run test:repo
npm run typecheck
npm run build
npm run test:sites
node --test --test-concurrency=1 tests/*.test.mjs
npm run verify:rss-live
git diff --checkConfirm that the client cannot access the ORS secret:
git grep -n "ORS_API_KEY" -- src app.json package.jsonBuild an Even Hub package locally:
npm run packThe resulting sandevistan.ehpk is a local artifact. The npm package is marked
private, and this repository does not publish to npm or Even Hub.
src/ Phone companion, Canvas renderers, G2 transport, live state
server/ Same-origin weather, news, map, and optional route APIs
tests/ Node tests for API and production-worker behavior
scripts/ Build preparation and repository policy checks
docs/design/ Selected HUD visual direction
docs/hardware/ Physical G2 checkpoints and measured transport records
docs/research/ Even Hub and G2 constraint research
docs/superpowers/ Historical design specifications and implementation plans
app.json Even Hub application manifest
Preserved diagnostic routes include:
/hud-canvas— original four-tile Canvas HUD./hud-hybrid— Canvas plus native Text layer experiment./hud-hybrid-z— explicit Text z-order experiment./calibration-max— 576×288 display-boundary calibration./diagnostic-v10— tap-to-send 1-bit BMP transport diagnostic.
| SDK | Physical G2 result | Status |
|---|---|---|
0.0.11 |
Four-tile bounded image transport works | Proven legacy baseline |
0.0.12 |
The old host failed immediately on its compressed image path | Historical reproduction only |
0.0.13 |
Four-tile bilateral transport, paging, detail views, and repeated hide/restore pass | Supported and pinned |
SDK 0.0.12 introduced the compressMode: 2 path that failed on the earlier
Even app and glasses combination. After the Even App and G2 firmware update,
the same compressed-image contract succeeds through SDK 0.0.13. The minimal
historical failure remains available on the unchanged
0.0.12-reproduce
branch for the Even Realities team.
Useful hardware records:
- First successful G2 image transfer
- SDK 0.0.11 transport checkpoint
- SDK 0.0.12 LZ4 experiment
- SDK 0.0.13 physical promotion gate
- Unchanged-tile skip experiment
- Current project readiness audit
- Phone companion completion audit
- Location, task, route, and cache data are stored through the Even local-storage bridge on the user's device.
- Requests to Open-Meteo, SBS RSS, OpenStreetMap/Overpass, and optional OpenRouteService necessarily disclose request data to those services.
- OpenStreetMap data is © OpenStreetMap contributors and available under the ODbL.
- Public endpoints are used conservatively for a personal, non-commercial prototype. This is not a hosted multi-user service.
- The black-tile display toggle is not an official G2 sleep mode; the app and listeners continue running.
- Hardware timing varies with the phone, Even app, glasses state, and radio link.
Issues and focused pull requests are welcome. Before opening a change:
- Keep image transport bounded and fail-fast.
- Do not add a deferred refresh queue.
- Keep credentials on the server.
- Preserve the 576×288 and 288×144 transport boundaries.
- Run the complete serial verification suite above.
- Keep tracked Markdown in English.
The source code is available under the MIT License.
Sandevistan is an unofficial fan project. It is not affiliated with, endorsed by, or sponsored by CD PROJEKT RED, the Cyberpunk franchise, Even Realities, or their respective owners. “Cyberpunk 2077,” “Sandevistan,” “Even Realities,” and related names and marks belong to their respective owners. This repository includes no game logo, extracted game UI, or proprietary game asset.