A Flappy Bird clone for Even Realities G2 smart glasses.
| Constraint | Value | Impact |
|---|---|---|
| Display | 576×288 px | Full canvas, but... |
| Image container | 200×100 px max | Game renders in this window |
| Color depth | 4-bit greyscale (16 levels) | Simple sprites |
| Input | Tap (click event) | Single action = flap |
| Frame rate | ~10-15 FPS realistic | BLE bandwidth limited |
┌─────────────────────────────────────────────────────────────┐
│ G2 Display (576×288) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Text Container (ID: 1) │ │
│ │ [Hidden behind image, captures events] │ │
│ │ │ │
│ │ ┌────────────────────────────────────────┐ │ │
│ │ │ Image Container (ID: 2) │ │ │
│ │ │ 200×100 px game area │ │ │
│ │ │ │ │ │
│ │ │ ● ┃ │ │ │
│ │ │ ┃ ┃ │ │ │
│ │ │ ┃ ┃ ┃ │ │ │
│ │ │ ┃ │ │ │
│ │ └────────────────────────────────────────┘ │ │
│ │ │ │
│ │ Score: 7 TAP TO FLAP │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Container Strategy:
- Text container (full screen,
isEventCapture: 1) — receives tap events, displays score/instructions - Image container (200×100, centered) — game graphics rendered via Canvas → greyscale BMP
| Element | Size | Notes |
|---|---|---|
| Bird | 8×8 px | Simple circle or square |
| Pipe width | 15 px | Thick enough to see |
| Pipe gap | 30 px | Generous for small screen |
| Scroll speed | 2 px/frame | Slower for playability |
| Gravity | 0.3 px/frame² | Gentle |
| Flap velocity | -4 px | Upward impulse |
flappy-g2/
├── PLAN.md # This file
├── README.md # User-facing docs
├── LICENSE # MIT
├── package.json # Dependencies
├── vite.config.ts # Vite config
├── app.json # Even Hub manifest
├── index.html # Entry point
├── src/
│ ├── main.ts # App bootstrap, SDK init
│ ├── game.ts # Game loop, physics, rendering
│ ├── renderer.ts # Canvas → greyscale conversion
│ ├── types.ts # Type definitions
│ └── styles.css # Minimal styles
└── assets/
└── (optional sprites)
- Initialize npm project
- Configure Vite + TypeScript
- Create app.json manifest
- Display "Hello G2" on text container
- Verify event capture works
- Create 200×100 Canvas
- Convert Canvas → 4-bit greyscale buffer
- Send to image container via
updateImageRawData - Display static test image
- Bird with gravity physics
- Tap event → flap (negative velocity)
- Ground collision detection
- Basic game over state
- Pipe generation (random gap position)
- Pipe scrolling (right to left)
- Collision detection (bird vs pipes)
- Score increment on pass
- Start screen ("TAP TO START")
- Game over screen with score
- High score persistence (localStorage)
- Sound effects (if audio API available)
- Test on real G2 hardware
- Create .ehpk package
- Write README with install instructions
- Publish to GitHub
function canvasToGreyscale(ctx: CanvasRenderingContext2D): Uint8Array {
const imageData = ctx.getImageData(0, 0, 200, 100);
const pixels = imageData.data; // RGBA
const grey = new Uint8Array(200 * 100);
for (let i = 0; i < grey.length; i++) {
const r = pixels[i * 4];
const g = pixels[i * 4 + 1];
const b = pixels[i * 4 + 2];
// Convert to 4-bit (0-15)
grey[i] = Math.round((0.299 * r + 0.587 * g + 0.114 * b) / 255 * 15);
}
return grey;
}// CLICK_EVENT = 0 becomes undefined due to SDK bug
if (event.textEvent?.eventType === OsEventTypeList.CLICK_EVENT ||
event.textEvent?.eventType === undefined) {
bird.flap();
}Target ~100ms per frame (10 FPS). Use setTimeout not requestAnimationFrame since we're not rendering to browser canvas directly.
const FRAME_MS = 100;
function gameLoop() {
update();
render();
sendToGlasses();
setTimeout(gameLoop, FRAME_MS);
}{
"@evenrealities/even_hub_sdk": "^0.0.7",
"typescript": "^5.x",
"vite": "^7.x"
}- Simulator: Use even-dev environment
- Real device: Sideload via QR code from Even Hub
MIT — open source for the Even Realities community.