Multi-application development environment for building and testing Even G2 apps with the Even Hub Simulator.
➜ even-dev git:(main) ./start-even.sh
Starting Even Hub development environment... http://127.0.0.1:5173
░░███
██████ █████ █████ ██████ ████████ ███████ ██████ █████ █████
███░░███░░███ ░░███ ███░░███░░███░░███ ██████ ███░░███ ███░░███░░███ ░░███
░███████ ░███ ░███ ░███████ ░███ ░███ ░░░░░░ ░███ ░███ ░███████ ░███ ░███
░███░░░ ░░███ ███ ░███░░░ ░███ ░███ ░███ ░███ ░███░░░ ░░███ ███
░░██████ ░░█████ ░░██████ ████ █████ ░░████████░░██████ ░░█████
░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░ ░░░░░░ ░░░░░
Command hints:
./start-even.sh # interactive app selection
./start-even.sh <app-name> # run one app directly
./start-even.sh --update # refresh all git apps from apps.json
./start-even.sh --update <name> # refresh one git app from apps.json
Starting Vite dev server...
Available apps:
ID NAME SOURCE
---- -------------------- ----------------------------------------
1 base_app apps/base_app
2 timer apps/timer
3 restapi apps/restapi
4 clock apps/clock
5 quicktest apps/quicktest
6 chess .apps-cache: github.com/dmyster145/EvenChess
7 epub .apps-cache: github.com/chortya/epub-reader-g2
8 reddit .apps-cache: github.com/fuutott/rdt-even-g2-rddit-client
9 smart-cart .apps-cache: github.com/bryan-datastorm/smart-cart-even-g2
10 stars .apps-cache: github.com/thibautrey/even-stars
11 transit .apps-cache: github.com/langerhans/even-transit
12 weather .apps-cache: github.com/nickustinov/weather-even-g2.git
13 snake .apps-cache: github.com/nickustinov/snake-even-g2
14 pong .apps-cache: github.com/nickustinov/pong-even-g2
15 stt .apps-cache: github.com/nickustinov/stt-even-g2
16 tetris .apps-cache: github.com/nickustinov/tetris-even-g2
Select app [1-15] (default 1): 1For general G2 development documentation, see the G2 development notes.
| App | Description | Visual |
|---|---|---|
| base_app | base_app – simple one pager app template | ![]() |
| clock | Clock app – app refresh test showcase | ![]() |
| timer | Countdown timer (1, 5 ... min, click to start, double-click to stop) | ![]() |
| restapi | Simple REST API client (micrOS integration) | ![]() |
| quicktest | Fast test app for UI generated by misc/editor |
![]() |
| chess | Chess HUD app by @dmyster145 | ![]() |
| epub | Epub reader by @chortya | ![]() |
| Reddit feed and comments browser by @fuutott | ![]() |
|
| smart-cart | Glanceable, hands-free grocery list by @bryan-datastorm | ![]() |
| stars | Real-time sky chart by @thibautrey | ![]() |
| transit | Public transport planner by @langerhans | ![]() |
| weather | Weather forecast by @nickustinov | ![]() |
| stt | Real-time speech-to-text via Soniox by @nickustinov |
- Node.js
- npm
- curl (used by
start-even.sh) - Even Hub Simulator
npm install
./start-even.shThe launcher lists all available apps (built-in + external) and prompts you to pick one.
misc/editor is an auxiliary helper project tracked as a git submodule under misc/. It is not a runtime app in the apps/* selection list.
Use --update to refresh git-based apps from apps.json:
./start-even.sh --updateUpdate one registry app only:
./start-even.sh --update weatherIf a cached app has local changes (for example package-lock.json edits), the updater auto-stashes those changes before pull and prints the stash name.
Refresh the root launcher environment (start-even.sh, root Vite, vite-plugins/*):
./start-even.sh --devenv-updateStandalone apps under apps/* keep their own dependencies in apps/<app>/package.json.
APP_NAME=timer ./start-even.shOr as a positional argument:
./start-even.sh timerIf you have an app checked out locally, point to it directly – no need to edit apps.json:
APP_PATH=../my-app ./start-even.shThis resolves the directory, installs its dependencies if needed, and launches it. The app name is derived from the directory basename.
Some apps (like stt) need microphone audio from the simulator. Pass AUDIO_DEVICE with the exact device ID:
AUDIO_DEVICE="coreaudio:AppleUSBAudioEngine:Apple Inc.:Studio Display:00008030-00065D000C10802E:6,7" ./start-even.sh stt
OR
AUDIO_DEVICE="coreaudio:BuiltInMicrophoneDevice" ./start-even.sh sttTo find available device IDs, run:
npx @evenrealities/evenhub-simulator@latest -b default --list-audio-input-devicesThis prints a table of IDs and names. Copy the full ID string from the left column. Note that default is not a valid device ID – you must use the exact ID.
The AUDIO_DEVICE value is passed to the simulator's --aid flag. When set, the simulator captures audio from that device, resamples it to 16 kHz S16LE PCM mono, and delivers it to your app via bridge.audioControl(true) / event.audioEvent.audioPcm.
There are two kinds of apps:
Apps under apps/ are standalone web apps with their own index.html, package.json, and src/main.* entrypoint (they may share helpers from apps/_shared).
The launcher (start-even.sh) treats built-in apps as standalone-only and passes the selected app directory through APP_PATH.
Standalone web apps with their own index.html, package.json, and vite.config.ts. They run independently – even-dev just serves their index.html through Vite with the correct filesystem access.
External apps are registered in apps.json:
{
"chess": "https://github.com/dmyster145/EvenChess",
"weather": "https://github.com/nickustinov/weather-even-g2.git",
"my-local-app": "../my-local-app"
}Values can be:
- Git URLs – cloned into
.apps-cache/on first run - Local paths – resolved relative to the even-dev root
Use ./start-even.sh --update (or ./start-even.sh --update <app>) to refresh cloned git entries in .apps-cache/.
For one-off testing without editing apps.json, use APP_PATH instead (see above).
A G2 app is a regular web app. There is no special framework or wrapper required – just HTML, TypeScript, and the Even Hub SDK for communicating with the glasses.
See chess and reddit for well-structured examples.
my-app/
index.html <- entry point
package.json <- dependencies and scripts
vite.config.ts <- dev server config
src/
main.ts <- app bootstrap
app.json <- app metadata (for packaging)
A standard HTML page that loads your app:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>My App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>At minimum, you need the Even Hub SDK and Vite:
{
"name": "my-even-app",
"scripts": {
"dev": "vite --host 0.0.0.0 --port 5173",
"build": "vite build"
},
"dependencies": {
"@evenrealities/even_hub_sdk": "^0.0.7"
},
"devDependencies": {
"typescript": "^5.9.3",
"vite": "^7.3.1"
}
}Metadata file used by evenhub-cli for packaging and deployment:
{
"package_id": "com.example.myapp",
"edition": "202601",
"name": "my-app",
"version": "0.1.0",
"min_app_version": "0.1.0",
"tagline": "Short one-line summary for the app",
"description": "What my app does",
"author": "Your Name",
"entrypoint": "index.html"
}evenhub-cli pack validates this schema. package_id must be a valid lowercase dot-separated package name (for example com.example.myapp).
See the reddit app's app.json for a full example with permissions.
import { waitForEvenAppBridge } from '@evenrealities/even_hub_sdk'
const bridge = await waitForEvenAppBridge()
bridge.onEvenHubEvent((event) => {
// Handle tap, double-tap, swipe, etc.
})
// Send UI to the glasses
bridge.sendStartUpPage(container)- Use inline styles or plain CSS – avoid CSS frameworks like Tailwind that require build plugins, since your app may be served through even-dev's Vite config which won't have those plugins.
- Keep it standalone – your app should work with just
npm run dev. Don't depend on even-dev's infrastructure. - If your app needs a backend server, put it in a
server/directory with its ownpackage.json. Even-dev will auto-detect and start it (seevite-plugins/app-server.ts). - Use
@jappyjan/even-realities-uifor settings pages if you want consistent UI components across apps. - Use
@evenrealities/evenhub-clifor packaging and deploying to the Even Hub. See reddit forpackandqrscript examples.
Even-dev has a vite-plugins/ directory for app-specific Vite configuration that runs when serving external apps. Current plugins:
| Plugin | Purpose |
|---|---|
app-server.ts |
Auto-starts an app's server/ process (e.g., Tesla's Tessie API proxy) |
browser-launcher.ts |
Opens the browser when the dev server is ready |
chess-stockfish.ts |
Serves Stockfish WASM assets for the chess app |
reddit-proxy.ts |
Proxies Reddit API requests to avoid CORS issues |
restapi-proxy.ts |
Proxies REST API requests for the restapi app |
If your app needs custom server-side behaviour (API proxying, asset serving, etc.), add a plugin here. Plugins receive a PluginContext with externalApps – a map of app names to their resolved directory paths. Return null if the plugin doesn't apply to the current app.
Use this flow when you build UI in misc/editor and want to test it quickly in the simulator with apps/quicktest.
- Ensure submodules are initialized once:
git submodule update --init --recursive - Start the editor helper app:
./misc/editor.sh - In the editor UI, generate TypeScript source.
- Either paste that source into the quicktest textarea, or replace
apps/quicktest/src/generated-ui.ts. - Start quicktest:
APP_NAME=quicktest ./start-even.sh - In quicktest, click Connect glasses (auto-renders on connect), then use Render Page for rerenders.
Quicktest expectations for generated source:
- Source should define
const container = new CreateStartUpPageContainer(...). - Source can include
import ... from '@evenrealities/even_hub_sdk'andexport default container; quicktest strips those automatically. - First render creates startup UI; additional renders rebuild the page container.
apps.json -> External app registry (git URLs or local paths)
start-even.sh -> CLI launcher: app selection, deps, Vite, simulator
apps/ -> Standalone built-in apps (each has its own index.html + src/main.ts)
apps/_shared/ -> Shared helpers for standalone apps (dev/test/runtime utilities)
scripts/ -> Helper scripts (for example pack-app.sh)
vite-plugins/ -> Custom Vite plugins for root dev server / registry apps
.apps-cache/ -> Auto-cloned external app repositories (gitignored)
vite.config.ts -> Root Vite config (serves the selected standalone app HTML, fs.allow, plugins)
flowchart TD
A["start-even.sh"] --> B["Vite dev server (APP_NAME + APP_PATH)"]
B --> C["Selected app's own index.html"]
C --> D["Selected app's src/main.ts"]
D --> E["Even Hub SDK / bridge"]
E <--> F["Even Hub Simulator"]
G["vite-plugins/"] --> B
- SDK: even_hub_sdk
- CLI: evenhub-cli
- Simulator: evenhub-simulator
- Community SDK: even-better-sdk by @JappyJan
- UI components: even-realities-ui by @JappyJan
- UIUX guidelines: Figma
- G2 development notes: G2.md
Before packaging/deploying, log in to Even Hub CLI:
npx @evenrealities/evenhub-cli loginFor built-in standalone apps under apps/*, use the helper script:
./scripts/pack-app.sh timerThis will build the app, then run evenhub-cli pack app.json dist, and produce apps/timer/out.ehpk.
Manual equivalent:
cd apps/timer
npm run build
npx @evenrealities/evenhub-cli pack app.json distThis is a development environment intended for experimentation and building Even G2 apps. APIs and structure may change as the Even ecosystem evolves.













