docs: add initial project documentation

This commit is contained in:
2026-09-02 23:44:01 +03:00
parent 4ff152ea32
commit 65fe630333
13 changed files with 5200 additions and 0 deletions
+280
View File
@@ -0,0 +1,280 @@
# 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 = 128`, `height = 64`, or 8,192 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.
- Rejected movement into a wall does not change position and is not a
successful move.
- 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.
## 11. 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.
- 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.
## 12. 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 `128 x 64` 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. 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.