How to use
- Copy the installation command and review the source package before installing it in your own agent environment.
- Check the source document for required tools, credentials and supported hosts.
- Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/even-realities/everything-evenhub --skill simulator-automationBefore you start
- Installation does not include a model subscription, API allowance or permission to access your files.
- Repository stars and installation counts describe activity, not an independent quality or security test.
Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.
EvenHub Simulator Automation
The simulator exposes an HTTP API on localhost when launched with --automation-port <PORT>.
evenhub-simulator https://my-app.example.com --automation-port 9898Base URL: http://127.0.0.1:<PORT>
API Reference
Health check
GET /api/ping
→ "pong"Glasses screenshot
Returns the current LVGL framebuffer as image/png (576×288, RGBA).
GET /api/screenshot/glasses
→ image/png binary (RGBA)RGBA format — critical for image analysis:
- Background pixels:
(R=0, G=255, B=0, A=0)— transparent (alpha = 0) - Lit/text pixels:
(R=0, G=255, B=0, A=255)— opaque (alpha = 255)
Always work in RGBA mode. Do NOT convert to RGB — it drops the alpha channel and makes background pixels indistinguishable from text pixels (both appear as pure green).
from PIL import Image
img = Image.open('glasses.png') # keep as RGBA — do NOT call img.convert('RGB')
pixels = img.load()
# Lit pixel test:
is_lit = lambda px: px[3] > 0 # alpha > 0Webview screenshot
Captures the main browser webview using html2canvas. Returns image/png. May take a few seconds; times out after 10s.
GET /api/screenshot/webview
→ image/png binaryConsole logs
Returns captured console.* output, uncaught exceptions, unhandled promise rejections, and failed fetch calls from the main webview.
GET /api/console
→ { "entries": [...], "total": N }Each entry:
{ "id": 0, "level": "log|warn|error|info|debug|trace", "message": "...", "ts": 1712150400000 }Prefixes for non-console sources:
[uncaught] ...— uncaught exception[unhandledrejection] ...— unhandled promise rejection[fetch] ...— failed fetch (non-ok status or network error)
Poll for new entries only:
GET /api/console?since_id=42
→ entries with id > 42`since_id` must be a non-negative integer. Passing a negative value (e.g. -1) causes the server to return an error, not an empty list. For the first poll, omit the parameter entirely to retrieve all current entries, then track last_id from the response:
# First poll — no since_id
resp = requests.get(f"{BASE_URL}/api/console")
entries = resp.json()["entries"]
last_id = max((e["id"] for e in entries), default=0)
# Subsequent polls
resp = requests.get(f"{BASE_URL}/api/console?since_id={last_id}")Clear the buffer:
DELETE /api/consoleTiming caution: Startup logs (e.g. a "ready" signal) are emitted once and lost if you clear the buffer before reading them. Pattern: poll for the ready signal first, then clear if needed.
# Safe: check for ready signal BEFORE clearing
poll_until(target="APP_READY")
requests.delete(f"{BASE_URL}/api/console") # only if you need a clean slate afterGlasses input
Send a touchpad action to the glasses display.
POST /api/input
Content-Type: application/json
{ "action": "up" | "down" | "click" | "double_click" }Response: { "ok": true }
Actions map to the glasses touchpad:
up/down— scroll through list items or textclick— select the current itemdouble_click— triggers a system-level double-click event (typically "back" or "dismiss")
Automation workflow
- Verify the server is running:
GET /api/ping - Poll for app ready (without clearing console first): look for a known log message.
- Observe: Use
/api/screenshot/glasses(RGBA) or/api/consoleto check state. - Act: Send input via
POST /api/input. After each action, wait briefly (~300ms) then confirm state changed. - Iterate: Use
since_idwhen polling console to avoid re-reading old entries.
Tips
- The glasses display is 576×288 pixels, monochrome green. Screenshots are RGBA PNGs.
- Input only works when the app has created an active event container. If no container is active, input is silently ignored.
double_clickis typically used to go back or dismiss the current view.- Allow 4+ seconds after launching the simulator before polling — SDK init and
createStartUpPageContainertake time.
Task
$ARGUMENTS




