Files
maze32/docs/PLAYER_UI.md
T

5.6 KiB

Player browser application

Milestone 008 provides the responsive player-facing browser application. The browser remains a renderer and input device: it sends movement and key-drop intentions, and it never calculates a legal move, inventory change, timer, visibility region, compass result, or match result.

Local assets

The application consists of index.html, player.css, player.js, and the locally authored icons.svg sprite. The deterministic asset build compresses each file with gzip for LittleFS. There are no remote fonts, frameworks, analytics, icon services, or runtime network dependencies beyond the local ESP.

Gameplay icon mapping

icons.svg contains editable, local SVG symbols with a shared 64 x 64 view box for the reference-derived gameplay set: player, key, exit-closed, crystal, exit-open, and spikes. Player 1 is yellow and Player 2 is blue; their matching keys and exits use the same owner color. The player, key, and exit silhouettes remain distinct, and Player 2 uses a dashed secondary treatment so ownership does not depend on color alone.

The closed and opened arched exits show the existing locked and opened exit states. The crystal represents the existing vision artifact. The spike symbol is kept as a local catalog asset but is not shown for blocked movement; it does not add a trap, damage, protocol, or server-state feature.

Input contract

Arrow keys and WASD map to north, east, south, and west move intentions. Touch swipes use the same four strings after a 28 CSS-pixel threshold. Phone layouts hide the direction pad and retain swipes; tablet and desktop layouts show the direction pad and also accept swipes. The persistent OK control sends drop_key and exposes the accessible label Сбросить ключ.

On phones, an always-visible four-button directional pad is the primary touch control. Its inactive centre prevents diagonal input; each button sends one of the same four authoritative movement intentions and a held button repeats no faster than every 170 ms. The centered player avatar is also an optional touch movement handle. Its transparent target is 96 by 96 CSS pixels while the visible avatar can deflect at most 28 CSS pixels. A 12-pixel dead zone and diagonal hysteresis resolve only cardinal intentions. Drag displacement selects a monotonically bounded local cadence from 360 ms to 170 ms, which remains slower than the authoritative 150 ms cooldown. The browser keeps one sent move in flight and coalesces all later drag changes into one latest intention; release discards that unsent intention. The deflection is local input feedback only. The maze redraws only after a server-authoritative projection and the browser never predicts a cell change. For every projection, the browser translates only the received cells so the authoritative self cell stays under the centered avatar; this also keeps the avatar off a wall when the visible projection reaches a maze boundary.

Feedback and message rail

The browser stores the direction for each outstanding move request. Only after a matching server blocked rejection does it shake the already rendered maze in the attempted direction for at most 340 ms; it shows no blocked-move text or spike notice. A matching rate_limited rejection darkens and blurs only the maze for at most 520 ms. Each effect has one restartable timer and is cleared on pause, result, reset, disconnect, and control reset. Reduced-motion mode uses a static maze border cue for blocked movement instead of a shake.

All remaining Russian system messages use one role=status live message rail above the application top bar. One connection-loss message has highest priority and remains until a successful recovery; other messages deduplicate, replace lower-priority content, and dismiss after 2.6 seconds.

Commands use the version-one protocol envelope and contain intention data only:

{"v":1,"type":"move","seq":7,"requestId":"move-7","payload":{"direction":"west"}}
{"v":1,"type":"drop_key","seq":8,"requestId":"drop_key-8","payload":{}}

Projection handling

View chunks are grouped by authoritative view sequence and rendered only after all chunks arrive. Each completed view replaces the previous maze DOM in full. The client does not merge a new view with previously visible cells, infer missing passages, or retain an explored map. Maze dimensions, cells, objects, player position, opponent visibility, inventory, vision duration, compass hint, phase, and result all come from the server projection.

The session token is the only game-related value saved in browser storage. On reload, the client sends that token in a restore intention and waits for a fresh role-appropriate server projection. Position, inventory, effects, hints, maze cells, and results are never restored from browser storage.

Presentation states

Name selection, lobby, countdown, active play, pause, and match result use the shared dark retro-arcade visual system. The fixed player status identifies the player and labels inventory, remaining boosted-vision moves, compass direction, and match phase. Modal overlays distinguish countdown, pause, and results. Rejected movement produces a local wall-bump animation without revealing any additional maze state. All player-facing copy and browser-generated errors are Russian; protocol identifiers remain English.

Sound and supported vibration are enabled after the first pointer or keyboard interaction. Both are progressive enhancements: unsupported devices continue without an error.

Observer presentation and its read-only interaction boundary are documented in OBSERVER_UI.md.