5.7 KiB
SNAKE — Xiaomi Watch S4
Textured Snake on a 368px circular arena, centered on the round 466px
screen. 32px tiles (60% larger than 0.7) occupy 89 legal cells of an 11×11
bounding grid; every tile corner stays inside the actual circle. The square
board frame is gone. Directional sprite artwork and user icon are preserved. Package identity: com.ilias.snake.
Version 0.8 (versionCode 8): locally tested and release-built; the new features still need an on-watch check. Earlier versions rendered and played on the user's Watch S4 41mm. Node tests and numeric layout checks are not device tests.
Play
- Swipe to steer. A two-turn queue accepts rapid corners, consumes one turn per tick, and rejects duplicate directions and reversals against the last queued direction. Excess inputs are ignored, not allowed to replace a turn.
- Tap the board, snake or apple to pause. Tap RESUME (or an exposed part of the board) to resume. Pausing clears queued turns.
- In the pause or game-over panel, select CLASSIC (the circular boundary ends the run) or WRAP (cross the circular boundary to appear at the opposite legal end of the same row or column). Changing mode starts a fresh, paused game; tap RESUME to begin. Selecting the current mode does not reset the run. The current mode is shown below the board.
- Both modes end on self-collision. Moving into the vacating tail is legal.
- PLAY AGAIN is a large 216×56px retry target. Retry keeps the selected mode, resets score/speed/queued turns, and starts playing. Filling the board displays YOU WIN at 89 occupied cells (86 points) and hides the apple safely.
- Leaving the page pauses it and stops the timer. Returning requires an explicit resume; game-over never resumes automatically. The system back action remains untouched. No crown, rotary, side-button or back interception APIs are used.
Score, speed and persistence
Each apple is one point. The always-visible header shows score and best. One
best score is shared across Classic and Wrap, saved through documented
@system.storage
under snake.best. Mode is session-only; a newly created page defaults to Classic.
The movement interval starts at 300ms, decreases by 10ms per apple, and never goes below 120ms. Only one movement timer runs; none runs while hidden, paused, finished or destroyed. Old timer callbacks are invalidated.
Storage reads merge with the in-memory maximum; writes wait for the initial read and are serialized/coalesced so slow callbacks cannot overwrite a newer record. The coordinator survives page recreation within the module lifetime. Old 0.7 records through 253 remain valid and are never reduced to the new 86-point maximum. Invalid saved values are ignored. Errors/exceptions do not interrupt gameplay: failed reads/writes retry on later apples or page-show activity, without a retry loop. A failed/uncompleted write or immediate app termination may lose the unsaved record. Storage persistence still needs verification on the watch.
Lightweight rendering
Directional PNG tiles use only left/top positioning, no transforms. Existing
20px sprite art is nearest-neighbor enlarged to native 32px assets (crisp pixel
art, not new high-resolution detail). The board is a newly generated circular
PNG with transparent corners and a subtle legal-cell checker pattern. Wrapped
texture connections handle each varying row/column length. All rows/columns
have at least three cells, avoiding ambiguous one-/two-cell seams.
Food scans only 89 legal cells, including a nearly full board. HUD/footer
rectangles never overlap legal play tiles; text/overlay fit the watch chord.
tests/preview-0.8-static.png is a static composition of actual geometry/art,
with a legal-cell overlay—not a runtime screenshot.
Build and test
npm ci
npm test
npm run release
npm test runs the original core, piece and page tests, 14 upgrade
regressions, the numeric layout suite, and deterministic randomized property tests. Upgrade coverage includes rapid
swipes, lifecycle/timer races, storage failures and async ordering, mode changes,
all four Wrap edges, seam textures, full-board victory and bounded food spawning.
New behaviors were exercised through failing-then-passing test cycles.
Release output: dist/com.ilias.snake.release.0.8.rpk. The locked
aiot-toolkit 2.0.5 uses the existing sign/private.pem and sign/certificate.pem;
do not regenerate or commit those keys. Release uses plain JS (not JSC/protobuf),
matching the previously working toolchain. The dependency lock is unchanged;
npm ci currently reports 14 development-toolchain audit findings (3 low,
11 high). No forced toolkit upgrade was applied.
Files
src/pages/index/index.ux: round-screen UI, swipe queue, game/lifecycle state.src/common/snake.js: movement, collision, Wrap piece classification, food.src/common/best.js: asynchronous storage coordinator.src/common/tex/: native 32px sprite artwork and circular board.tests/{snake,pieces,page,upgrade,layout,properties,round,art,round-history}.cjs: Node regression suites, including history-based circular seam orientation checks.
Install the signed RPK through AstroBox. Source/releases live at https://gitea.oimcloud.myaddr.tools/codex-bot/vela-snake — publication is a separate step after review; a local build is not evidence of a published release.
Earlier versions
- 0.2/0.3: board played on watch; designWidth 480→466 fixed undersizing.
- 0.6: directional textured tiles and preserved user-supplied icon.
- 0.7: queued swipes, live/persisted records, capped acceleration, pause/resume, lifecycle safety, retry/win panels and selectable Classic/Wrap.