Files
maze32/docs/PLAYER_UI.md
T

136 lines
7.2 KiB
Markdown

# 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 responsive avatar focal point. On a
portrait phone this is horizontally centered at 30% of the map height; compact
landscape uses a stable left-biased unobstructed point away from the directional
pad. This also keeps the avatar off a wall when the visible projection reaches
a maze boundary, and is recalculated on resize and rotation.
## Feedback and message rail
## Compact settings
The persistent gear button beside the connection indicator opens one compact
popover. It shows live connection details and Wi-Fi settings on every screen.
During an active player match it additionally provides sound, reduced-motion,
and optional-help controls with visible Russian on/off labels. Opening or
closing this presentation-only menu never sends a command or changes server
state. Escape and outside activation dismiss it; player actions also close it
before opening their existing destination.
The header response indicator takes at most one heartbeat sample every five
seconds, holds one in-flight request, and uses a five-sample median. Good is
at most 150 ms, delayed is 151--500 ms, and slow is above 500 ms. Hysteresis
holds good until above 175 ms and slow until at most 450 ms; a sample is stale
after 15 seconds. Hidden documents and closed sockets do not probe.
The browser stores the direction for each outstanding move request. A matching
server `blocked` rejection may include only that player's approved breakthrough
stage, which bends the already rendered bush wall for at most 340 ms without
blocked-move text. A received opened-passage projection paired with an adjacent
authoritative player move may show one 480 ms hedge-parting dash and four
bounded decorative accents before settling at the server-approved destination.
Opened-passage bits render a permanent trampled bush gap with a 60% clear
centre. Effects have restartable timers and clear on a newer projection, pause,
result, reset, disconnect, screen change, and control reset. Reduced motion is
static and settles directly at the received destination.
The map draws only a bounded canonical hedge-edge layer generated from current
received cells. It hashes each visible edge deterministically to choose the
approved local SVG variant, so the browser neither retains unseen geometry nor
decides topology. The layer is decorative and cannot receive input.
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:
```json
{"v":1,"type":"move","seq":7,"requestId":"move-7","payload":{"direction":"west"}}
```
```json
{"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`.