- Node.js 20+ (required by the SDK)
- A code editor with TypeScript support
- (Optional but recommended) An Even Realities G2 glasses pair for real hardware testing
- The Even Realities iOS or Android app on your phone (for sideloading via QR)
The fastest start is Vite with a TypeScript template:
npm create vite@latest my-g2-app -- --template vanilla-ts
cd my-g2-appOr if you want React for the phone UI:
npm create vite@latest my-g2-app -- --template react-ts
cd my-g2-appnpm install @evenrealities/even_hub_sdk
npm install --save-dev @evenrealities/evenhub-cli @evenrealities/evenhub-simulatorPin the SDK version — APIs still change between patches:
{
"dependencies": {
"@evenrealities/even_hub_sdk": "^0.0.9"
}
}At the project root:
{
"package_id": "com.yourname.myapp",
"edition": "202601",
"name": "My App",
"version": "0.1.0",
"min_app_version": "0.1.0",
"min_sdk_version": "0.0.9",
"tagline": "Short description (50 chars max)",
"description": "Longer description",
"author": "Your Name",
"entrypoint": "index.html",
"supported_languages": ["en"],
"permissions": []
}Note: supported_languages only accepts ["en", "es"] — Portuguese is NOT accepted here, even though your app can absolutely render Portuguese text. Handle PT internally if you need it.
src/main.ts:
import {
waitForEvenAppBridge,
TextContainerProperty,
CreateStartUpPageContainer,
} from '@evenrealities/even_hub_sdk'
async function init() {
// CRITICAL: always use waitForEvenAppBridge(), never `new EvenAppBridge()`
// (the constructor is private in the published SDK)
const bridge = await waitForEvenAppBridge()
// Create the initial page with ONE text container
const text = new TextContainerProperty({
xPosition: 4,
yPosition: 4,
width: 568, // 576 - 8 padding
height: 280, // 288 - 8 padding
borderWidth: 0,
borderColor: 0,
borderRadius: 0,
paddingLength: 8,
containerID: 0,
containerName: 'main',
isEventCapture: 1, // CRITICAL: exactly one container must have this
content: 'Hello, G2!',
})
bridge.createStartUpPageContainer(new CreateStartUpPageContainer({
containerTotalNum: 1,
textObject: [text],
}))
// Subscribe to events (taps, scrolls, lifecycle)
bridge.onEvenHubEvent((event) => {
console.log('event:', event)
})
}
init().catch(console.error)<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>My G2 App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>npm run dev # Vite on :5173
npx evenhub-simulator http://localhost:5173The simulator shows the 576×288 display. Click buttons on the simulator to trigger tap/scroll events.
First login to the CLI:
npx evenhub loginThen generate a QR code pointing to your dev server:
# Find your LAN IP first:
# Windows: ipconfig
# macOS: ifconfig | grep inet
# Linux: hostname -I
npx evenhub qr --ip 192.168.1.100 --port 5173Scan the QR with the Even Realities phone app (Plugins → Scan QR). Your app loads on the glasses with full Vite hot reload.
When you're ready to publish to the Hub:
npm run build # produces dist/
npx evenhub pack app.json dist -o my-app.ehpk # produces my-app.ehpkUpload the .ehpk to hub.evenrealities.com/hub under your project's "Builds" tab.
{
"scripts": {
"dev": "vite --host --port 5173",
"build": "tsc && vite build",
"pack": "npm run build && node -e \"const v=require('./package.json').version; require('child_process').execSync('npx @evenrealities/evenhub-cli pack app.json dist/ -o myapp-v'+v+'.ehpk', {stdio:'inherit'})\"",
"sim": "npx evenhub-simulator http://localhost:5173",
"qr": "npx evenhub qr --ip 192.168.1.100 --port 5173"
}
}Note the pack script: it embeds the version from package.json into the filename so you get myapp-v0.3.1.ehpk instead of overwriting a single file. Trust me, you want this.
- Read SDK quirks before writing any event handling code
- Copy the event handling template as your starting point
- Study one of the example projects for your use case