Mahjong solitaire (tile-matching) built natively for the RayNeo X3 Pro AR glasses. Clear a layered board by removing pairs of matching free tiles. Move a cursor with right-temple swipes, click to pick a tile — and when a tile can't be taken, TapMahjong tells you why.
Part of the X3 game suite, so it inherits every on-device-proven pattern: 640×480 logical canvas, binocular side-by-side rendering, pure-black waveguide background, one-swipe-per-step navigation, dwell-to-commit, auto-save/resume — zero vendor AARs, zero permissions, zero binary assets (engine + sounds are pure Kotlin, synthesized at runtime).
- Tiles are stacked in layers. A tile is free when nothing rests on top of it and at least one of its left/right sides is open.
- Remove two free tiles that match: identical faces — or any flower with any flower, any season with any season.
- Clear the whole board to win. Every deal is generated by reverse-solving, so a solution always exists; if you paint yourself into a corner, Shuffle (in settings) re-deals the remaining tiles solvably.
| Gesture | Action |
|---|---|
| Swipe ↑ ↓ ← → | Move the cursor to the nearest tile that way |
| Click (temple tap) | Select a tile · match · confirm |
| Double-tap | Open / close settings any time |
| Left temple pad | System volume (ignored) |
Click a free tile to select it (it highlights), swipe to its match, let the ring fill briefly, then click to clear the pair. Click the selected tile again to deselect. Covered/blocked tiles explain themselves when tapped. Free tiles render bright; covered tiles are dimmed. Also plays on a touchscreen.
Three sizes on the title screen (swipe) or in settings:
| Layout | Tiles |
|---|---|
| 1 · Easy | 36 (3 layers) |
| 2 · Medium | 72 |
| 3 · Hard | 104 |
Layout · timer on/off · Hint (highlights a matchable pair) · Shuffle · show free-dots · sound volume · swipe sensitivity · flip vertical/horizontal · safe tap · particles · frame cap · new deal · undo match · reset stats · reset settings (at the bottom). One-swipe-per-step navigation.
An optional timer tracks your solve time and records a best time per layout. The game auto-saves after every match (and on pause) and resumes on next launch.
cd ~/Projects/TapMahjong
./gradlew assembleDebug && adb install -r app/build/outputs/apk/debug/app-debug.apkA built TapMahjong.apk also ships in this repo's root for a quick sideload.
Toolchain: gradle 8.9 · AGP 8.7.3 · Kotlin 2.0.21 · JDK 17 · compileSdk 35 / minSdk 29.
- Black is transparency: the tiles float as light on the world
- No
ar_modemeta-data (it would halve the display to one lens) - Temple click read as a KEY event; swipes classified on finger-up; one gesture = one step everywhere; cursor jumps to the nearest tile in the swiped direction
cyttsp6(left volume pad) filtered out by device name- RayNeo hardware detected by manufacturer/brand/product, not
Build.MODEL(the X3 Pro reportsARGF20); SBS auto-defaults on - Dwell-to-commit guards against finicky swipes; the sleep button auto-pauses into settings; the game persists after every match