338 lines
16 KiB
Markdown
338 lines
16 KiB
Markdown
# maze32 MVP
|
|
|
|
## 1. Product goal
|
|
|
|
maze32 is a local browser-based multiplayer maze race hosted by one ESP32-C6.
|
|
Two players explore the same maze in real time, search for their own keys and
|
|
exits, and try to leave first. Up to four observers may watch the complete
|
|
match.
|
|
|
|
The MVP must produce a fair, playable match whose normal target duration is
|
|
approximately five minutes. There is no match time limit.
|
|
|
|
## 2. Runtime model
|
|
|
|
- One ESP32-C6 runs the HTTP server, WebSocket server, maze generator, and the
|
|
authoritative game simulation.
|
|
- Both players and all observers use ordinary web browsers.
|
|
- Clients send intentions such as move or drop-key; they never determine the
|
|
result of an action locally.
|
|
- The server validates action order, movement cooldowns, collisions, item
|
|
ownership, visibility, victory, and draws.
|
|
- The server must never send hidden game state to a player client. Fog of war
|
|
is enforced when constructing the server response, not merely by hiding
|
|
elements in the browser.
|
|
|
|
## 3. Roles and lobby
|
|
|
|
### Players
|
|
|
|
- Exactly two player slots exist: Player 1 and Player 2.
|
|
- A player joins with a unique display name and receives a temporary session
|
|
token.
|
|
- The UI may suggest humorous available names.
|
|
- The first player becomes the lobby owner and is the only player who may
|
|
start the match.
|
|
- The second player is a participant without start authority.
|
|
- The match can start only when both player slots are occupied.
|
|
- Refreshing the browser restores the same player, slot, position, inventory,
|
|
and match state through the session token.
|
|
|
|
### Observers
|
|
|
|
- Up to four observers may connect without a password.
|
|
- Observers do not consume player slots.
|
|
- Observers are read-only: they cannot start, pause, or control a match.
|
|
- An observer sees the entire maze without fog of war, both current player
|
|
positions, keys and their holders, exits, compasses, vision artifacts, match
|
|
status, connection state, and final result.
|
|
- An observer disconnect does not pause the match.
|
|
|
|
### Start sequence
|
|
|
|
- When the lobby owner starts a ready match, both players receive the same
|
|
`3-2-1` countdown.
|
|
- Movement is rejected until the countdown completes.
|
|
- Both players become active at the same authoritative server instant.
|
|
|
|
## 4. Maze
|
|
|
|
### Dimensions and representation
|
|
|
|
- The initial configuration is `width = 32`, `height = 32`, or 1,024 cells.
|
|
- Width and height are runtime configuration values and must not be hard-coded
|
|
into game logic.
|
|
- Movement is orthogonal between cells; diagonal movement does not exist.
|
|
- Every playable cell and required object must be reachable.
|
|
|
|
### Symmetry and topology
|
|
|
|
- Geometry uses central symmetry under a 180-degree rotation:
|
|
`(x, y) -> (width - 1 - x, height - 1 - y)`.
|
|
- Player 2's start, key, exit, and other fairness-relevant placements are the
|
|
rotated counterparts of Player 1's placements.
|
|
- The maze contains cycles, alternative routes, dead ends, and many passages
|
|
between its conceptual halves.
|
|
- Players can enter either half through multiple routes, but the UI must not
|
|
identify a cell as belonging to either player.
|
|
- The maze is not a perfect maze with only one route between points.
|
|
|
|
### Starts, keys, and exits
|
|
|
|
- Players start at opposite, rotationally symmetric entrance cells.
|
|
- An entrance is only the starting point; it is not the player's exit.
|
|
- Each player has one unique key and one unique exit.
|
|
- A key opens only its matching exit, and only the owner of that key and exit
|
|
can win through them.
|
|
- Key and exit pairs are placed rotationally symmetrically and at equal route
|
|
distances for both players.
|
|
- Each key begins outside its owner's initial field of view.
|
|
- Each exit may be at any distant valid symmetric location.
|
|
- Map generation must make finding the key at least as challenging as the
|
|
subsequent search for the correct exit. Exact balance thresholds are
|
|
tunable and must be validated through generation metrics and playtesting.
|
|
|
|
### Landmarks and generated objects
|
|
|
|
- The maze contains visually distinctive landmarks to support human spatial
|
|
memory even though explored territory is not retained.
|
|
- Fairness-relevant landmarks and vision artifacts are generated in
|
|
rotationally symmetric pairs.
|
|
- The exact number and density of landmarks and artifact pairs are tunable
|
|
balance parameters. The MVP must place more than one vision artifact.
|
|
|
|
## 5. Movement and player interaction
|
|
|
|
- One accepted input moves a player by exactly one traversable cell in one of
|
|
four directions: up, down, left, or right.
|
|
- Players act independently; the server does not wait for alternating or
|
|
simultaneous turns.
|
|
- A small server-enforced minimum interval exists between accepted moves. Its
|
|
value is configurable for playtesting.
|
|
- A server-accepted impact against the same closed interior wall from the same
|
|
cell and direction is tracked per player. The first four impacts do not move
|
|
the player; the fifth within three seconds of each previous impact opens the
|
|
passage in both cells and completes that move. Perimeter walls never open.
|
|
- Players do not block each other and may occupy the same cell.
|
|
- A meeting occurs when both players occupy the same cell.
|
|
- There are no attacks, health, damage, or other combat mechanics in MVP.
|
|
|
|
Browser controls must support:
|
|
|
|
- keyboard movement on computers;
|
|
- directional swipes on touchscreens;
|
|
- an accessible drop-key action for both control modes.
|
|
|
|
## 6. Keys and inventory
|
|
|
|
- A player may carry at most one key.
|
|
- A player may pick up either key if the inventory slot is empty.
|
|
- The carried key disappears from its map cell and becomes server-owned
|
|
inventory state.
|
|
- A player always sees which key they carry.
|
|
- A player may voluntarily drop either their own or the opponent's key. It is
|
|
placed on the player's current cell.
|
|
- Entering a cell containing a key while already carrying one does not pick up
|
|
the second key.
|
|
- A player may carry the opponent's key elsewhere and drop it as sabotage.
|
|
- When players meet, every carried key is automatically transferred to its
|
|
correct owner. If both carry each other's keys, the keys swap owners in the
|
|
same authoritative event.
|
|
- Outside the current field of view, a player receives no information that the
|
|
opponent found, dropped, or carries a key.
|
|
- When the opponent is visible, their carried key identity is visible too.
|
|
- A player cannot open or use the opponent's exit, even while carrying the
|
|
matching opponent key.
|
|
|
|
## 7. Fog of war
|
|
|
|
- Normal vision radius is three cells around the player.
|
|
- Walls do not block vision.
|
|
- For the MVP, radius uses a square/Chebyshev neighborhood: a radius of three
|
|
exposes at most a `7 x 7` cell area, clipped by map boundaries.
|
|
- Once a cell leaves the current vision area it becomes completely unknown
|
|
again; there is no explored-map memory.
|
|
- Hidden cells reveal neither maze geometry nor stale objects or player
|
|
positions.
|
|
- The opponent is visible only while inside the current vision area and
|
|
disappears immediately after leaving it.
|
|
- Observers are exempt from fog of war.
|
|
|
|
## 8. Vision artifacts and compasses
|
|
|
|
### Vision artifacts
|
|
|
|
- The map contains multiple one-use vision artifacts.
|
|
- Entering an artifact cell activates it immediately and removes it from the
|
|
map; it cannot be stored or reused.
|
|
- The effect increases vision radius from three to six cells.
|
|
- The effect lasts for the next ten successful moves by that player.
|
|
- Failed move attempts do not consume an effect move.
|
|
- Additional artifact types are outside the MVP.
|
|
|
|
### Compasses
|
|
|
|
- The maze contains two stationary compasses, one associated with each
|
|
player's exit and placed fairly as a symmetric pair.
|
|
- A compass cannot be picked up.
|
|
- A player must enter the appropriate compass cell to activate its hint.
|
|
- On activation, the UI displays an arrow pointing toward that player's own
|
|
exit.
|
|
- A compass does not reveal a route or the exit coordinates.
|
|
|
|
## 9. Exit, victory, and draw
|
|
|
|
- A player can open only their own exit and only with their own key.
|
|
- Opening the exit is not itself a victory.
|
|
- After opening it, the player must perform one additional valid outward move
|
|
beyond the maze boundary through that exit.
|
|
- The server records the authoritative exit time.
|
|
- The first player to complete the outward move wins.
|
|
- If both authoritative exit times fall within a 200 ms window, the result is
|
|
a draw.
|
|
- The normal target match duration is approximately five minutes, but a
|
|
connected match continues indefinitely until victory or another defined draw
|
|
condition.
|
|
|
|
## 10. Connectivity and recovery
|
|
|
|
### Wi-Fi provisioning
|
|
|
|
- In normal operation the ESP connects to a previously configured Wi-Fi
|
|
network in station mode.
|
|
- Network credentials are stored in NVS and reused after reboot.
|
|
- When the configured network is unavailable or credentials have not been
|
|
saved, the ESP starts a fallback access point.
|
|
- The fallback web interface allows the user to configure and save an existing
|
|
Wi-Fi network.
|
|
|
|
### Player disconnection
|
|
|
|
- Loss of either player's WebSocket connection pauses the authoritative match.
|
|
- No player movement or turn-based effect duration advances while paused.
|
|
- The disconnected player has 60 seconds to reconnect with the existing
|
|
session token.
|
|
- A successful reconnect restores the same slot and resumes the same match
|
|
state.
|
|
- If the player does not reconnect within 60 seconds, the match ends in a draw.
|
|
- Reloading a page is treated as a reconnect, not as leaving the match.
|
|
- A confirmed explicit player exit during any non-waiting phase, including a
|
|
finished result, revokes only that session and authoritatively returns all
|
|
remaining participants to a fresh waiting lobby. Observer exits and player
|
|
exits from an already waiting lobby affect only the departing session.
|
|
|
|
### Player trails
|
|
|
|
- Every successful in-maze player move is recorded authoritatively as a
|
|
persistent passage trail for the current match. Players receive only trail
|
|
segments inside their current fog-of-war projection; observers receive both
|
|
complete trails. Trails clear with the match and never come from browser
|
|
history.
|
|
|
|
## 11. Browser presentation
|
|
|
|
- The browser UI uses one dark, humorous retro arcade visual language across
|
|
provisioning, lobby, player, and observer modes, as defined in
|
|
`docs/UI_STYLE.md`.
|
|
- All player-facing UI copy, game messages, and browser errors are in Russian.
|
|
- The UI uses a near-black background, purple panels, turquoise interactive
|
|
accents, yellow for Player 1, blue for Player 2, and plant-like green maze
|
|
walls. Each player's matching key and exit use the same ownership color.
|
|
Important state is distinguished by icons, labels, outlines, or shapes in
|
|
addition to color; amber warnings and blue pause states use distinct
|
|
treatments so they cannot be confused with player identity.
|
|
- The player map consumes all space not required by fixed status and control
|
|
panels. The player view supports a minimum `412 x 916` CSS-pixel viewport
|
|
without page scrolling.
|
|
- On portrait phones, the authoritative player focal point is horizontally
|
|
centered at approximately 30% of the usable map height, above the operating
|
|
hand zone. Compact landscape uses a stable left-biased focal point in the
|
|
largest unobstructed map area.
|
|
- Textual system notices use one Russian live message rail above the top bar.
|
|
A connection-loss notice remains there until recovery; movement blocked by a
|
|
wall and rate limiting use maze-only visual feedback and never show text.
|
|
- Computers and tablets support keyboard, swipes, and on-screen arcade
|
|
controls. Phones show an always-visible four-button directional pad as the
|
|
primary touch control while retaining avatar drag and directional swipes as
|
|
optional alternatives. The pad sends only existing orthogonal movement
|
|
intentions through the authoritative server path.
|
|
- An always-visible `OK` control with a key icon drops the carried key without
|
|
confirmation and exposes the Russian accessible label `Сбросить ключ`.
|
|
- Observer mode requires at least a `1024 x 768` CSS-pixel viewport, initially
|
|
fits the complete map, and supports zoom and pan. Smaller viewports show a
|
|
Russian large-screen requirement message.
|
|
- Sound and vibration are enabled by default after the first user interaction
|
|
when the browser and device support them.
|
|
- The application has no runtime internet dependency. It uses local assets,
|
|
locally authored SVG icons, plain CSS, and a system monospace font styled to
|
|
resemble a pixel font.
|
|
|
|
## 12. Technical constraints
|
|
|
|
- Target: ESP32-C6FH4, 4 MB Flash, no required PSRAM.
|
|
- Build: PlatformIO, `espressif32@7.0.1`, ESP-IDF, compatible
|
|
`esp32-c6-devkitm-1` profile.
|
|
- Flash layout: 2 MiB factory application and 1,984 KiB LittleFS; no OTA in
|
|
MVP.
|
|
- Static browser assets reside in LittleFS and should be compressed for the
|
|
production image.
|
|
- The complete compressed web payload must not exceed 1.5 MiB and must fit the
|
|
unchanged 1,984 KiB LittleFS partition.
|
|
- HTTP serves the application and provisioning pages; WebSocket carries live
|
|
lobby, control, and match messages.
|
|
- The initial LwIP socket limit is 16.
|
|
- The implementation must be tested with two player connections and four
|
|
simultaneous observer connections on the physical device.
|
|
- Active lobby and match state may live in RAM and need not survive an ESP
|
|
reboot. Wi-Fi settings must survive reboot.
|
|
|
|
## 13. MVP acceptance criteria
|
|
|
|
The MVP is accepted when all of the following are demonstrated on the target
|
|
board:
|
|
|
|
1. The firmware builds with the locked PlatformIO configuration and fits the
|
|
application and LittleFS partitions.
|
|
2. Wi-Fi station setup persists in NVS, and failed station connection exposes
|
|
the fallback access-point configuration flow.
|
|
3. Two browsers can claim unique player names, restore their slots after page
|
|
refresh, enter the lobby, and start through the owner-controlled countdown.
|
|
4. Four additional browsers can observe the complete match simultaneously
|
|
without receiving control authority.
|
|
5. Repeatedly generated `32 x 32` maps are connected, centrally symmetric,
|
|
contain cycles and multiple cross-half passages, and preserve equal
|
|
player-relative placement metrics.
|
|
6. Player clients never receive cells or dynamic objects outside their current
|
|
allowed view; observer clients receive the complete state.
|
|
7. Keyboard and touch controls produce server-validated single-cell movement
|
|
with an enforced configurable cooldown.
|
|
8. Key pickup, one-slot inventory, dropping, sabotage, automatic owner return,
|
|
door restrictions, and visible-carried-key rules behave as specified.
|
|
9. Vision artifacts expand the view for exactly ten successful moves, and
|
|
compass cells display the correct direction to the activating player's own
|
|
exit.
|
|
10. An outward move through an opened own exit determines victory, and exits
|
|
within 200 ms produce a draw.
|
|
11. A player disconnect pauses the match, reconnection restores it, and a
|
|
60-second reconnect timeout ends it as a draw.
|
|
12. A representative match normally completes in approximately five minutes
|
|
after balance tuning, without imposing a hard match timer.
|
|
13. The Russian retro arcade UI follows `docs/UI_STYLE.md`, works at the
|
|
required player and observer viewport sizes in the current stable Chrome,
|
|
Safari, Firefox, and Edge releases, requires no runtime internet access,
|
|
and stays within the 1.5 MiB compressed web-asset budget.
|
|
|
|
## 14. Explicitly outside MVP
|
|
|
|
- More than two active players or more than one concurrent match.
|
|
- More than four observers.
|
|
- Persistent accounts, passwords, cloud services, matchmaking, or internet
|
|
play.
|
|
- Spectator control or moderation tools.
|
|
- Physical display or gameplay buttons.
|
|
- ESP-NOW, BLE multiplayer, or multiple-device game simulation.
|
|
- Additional artifact types, combat, health, traps, or player elimination.
|
|
- Persistent match recovery after ESP reboot.
|
|
- OTA firmware partitions and OTA update flow.
|
|
- Dependence on PSRAM, an unverified LED, or an assumed board pinout.
|