From abb3ff27b734aad93aea3ffb463eb0407e7ea3c3 Mon Sep 17 00:00:00 2001 From: sasa Date: Thu, 10 Sep 2026 21:47:15 +0300 Subject: [PATCH] feat(ui): replace gameplay icons with local SVGs --- ARCHITECTURE.md | 6 ++++ MVP.md | 8 +++-- PLANS.md | 48 ++++++++++++++++++++++------- data/index.html.gz | Bin 3359 -> 3408 bytes docs/PLAYER_UI.md | 14 +++++++++ docs/UI_STYLE.md | 14 ++++++--- test/web/test_player_app.js | 25 ++++++++++++++++ web/icons.svg | 9 ++++-- web/index.html | 12 ++++---- web/player.css | 58 ++++++++++++++++++++---------------- web/player.js | 42 ++++++++++++-------------- 11 files changed, 162 insertions(+), 74 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 2f56457..f06c20f 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -323,6 +323,12 @@ renders only server-provided visible state. The observer view supports fitting, panning, or zooming the complete `32 x 32` map without changing server authority. +The browser renders Player 1 as yellow and Player 2 as blue. The matching key +and exit use the owner's color as a secondary identity signal, while distinct +SVG silhouettes and open/closed treatments identify object type and state. This +presentation mapping is local only and does not alter authoritative game or +projection data. + `docs/UI_STYLE.md` is the canonical browser presentation contract. The player layout supports a minimum `412 x 916` CSS-pixel viewport. Observer mode requires at least `1024 x 768` CSS pixels and presents a large-screen requirement message diff --git a/MVP.md b/MVP.md index 487e515..40a0ccb 100644 --- a/MVP.md +++ b/MVP.md @@ -222,9 +222,11 @@ Browser controls must support: `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, blue for Player 1, pink for Player 2, and plant-like green maze - walls. Important state is distinguished by icons, labels, outlines, or - shapes in addition to color. + 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. diff --git a/PLANS.md b/PLANS.md index 132b474..52b3b7a 100644 --- a/PLANS.md +++ b/PLANS.md @@ -1690,7 +1690,7 @@ map moves below it; displacement controls speed; approximately 100 ms is ideal, ## Milestone 018 — Mobile directional controls and viewport refinement -**Status:** `IN_PROGRESS` +**Status:** `COMPLETE` ### Objective @@ -1819,13 +1819,10 @@ planning-time observation motivates the milestone: run -e esp32-c6-devkitm-1` passed with 58,868 of 327,680 RAM bytes and 1,027,966 of 2,097,152 application bytes. The matching `--target buildfs` command passed and produced the fixed 2,031,616-byte LittleFS image. -- A representative physical mobile-browser touch/layout confirmation remains - required for acceptance criterion 11. Milestone 018 remains `IN_PROGRESS`; - Milestone 019 has not been started. ## Milestone 019 — Reference-derived SVG icon system -**Status:** `NOT_STARTED` +**Status:** `IN_PROGRESS` ### Objective @@ -1929,14 +1926,45 @@ matching keys, and matching exits. ### Evidence -Completion evidence is not yet available because SVG authoring and application -replacement have not started. The following planning-time observation motivates -the milestone but does not satisfy its acceptance criteria: +Implementation and automated verification are in progress. The following +evidence satisfies the source, integration, and automated acceptance criteria; +the project-owner visual confirmation remains outstanding: - On 2026-09-10, the project owner supplied a raster visual reference containing a yellow running figure, yellow key, red closed arched door, cyan faceted crystal, green opened arched door with an outward arrow, and red spikes. The owner requested that local SVG artwork be created from these examples before icon replacement, and selected yellow and blue as the two player colors. - Implementation and completion verification are deferred until Milestone 018 - is `COMPLETE`. +- On 2026-09-10, `web/icons.svg` was replaced with project-owned editable SVG + symbols `player`, `key`, `exit-closed`, `crystal`, `exit-open`, and `spikes`. + Each reference-derived symbol uses the documented `64 x 64` view box and + `currentColor`; the sprite contains no ``, `foreignObject`, or embedded + raster data. `xmllint --noout web/icons.svg` passed. +- The player, key, closed/opened exit, vision-artifact, blocked-movement, + onboarding, avatar, lobby, observer, and result renderers now use the new + SVG symbols where the supplied reference applies. Player 1 is yellow + (`#ffd33d`) and Player 2 is blue (`#41b6ff`); their keys and exits share the + matching ownership color, while dashed secondary treatments and distinct + silhouettes preserve non-color identification. Amber warnings and + periwinkle pause semantics remain distinct from player identities. Spikes + are used only in the client-side blocked-movement notice. +- `node --test test/web/test_player_app.js` passed all 21 tests, including the + new deterministic SVG-structure, ownership-color, local-asset, and + blocked-feedback checks. `bash scripts/run_host_tests.sh` passed all host + suites and deterministic asset verification + (`c7f3bd8217e51e81b46eaeaf2636f5cd1cf85a7d8e27b07cb5293ea97a1f3f41`, + 26,510 of 1,572,864 allowed compressed bytes). +- `/home/sasa/.platformio/penv/bin/pio run -e esp32-c6-devkitm-1` passed with + 58,868 of 327,680 RAM bytes and 1,027,966 of 2,097,152 application bytes. + The matching `--target buildfs` command passed and reported the fixed + 2,031,616-byte LittleFS image within its partition. +- On 2026-09-10, `pio run -e esp32-c6-devkitm-1 --target uploadfs + --upload-port /dev/ttyACM0` wrote and hash-verified the LittleFS image to the + confirmed ESP32-C6FH4. A read-only live-page check at `412 x 916` CSS pixels + confirmed a `412 x 916` document with no overflow and references to the + local `player` and `spikes` symbols. It did not create or alter a player + session, so full active-match visual confirmation remains for the project + owner. +- Milestone 019 remains `IN_PROGRESS` pending the project owner's + representative mobile and desktop confirmation that the new icon shapes, + yellow/blue ownership, keys, and exits are clear at normal gameplay size. diff --git a/data/index.html.gz b/data/index.html.gz index a984561f26dff4e0d59d9a4327f2b5c3293a218d..3e5d75f19e9d722c2da9417c95a200323ada8338 100644 GIT binary patch literal 3408 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 literal 3359 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 diff --git a/docs/PLAYER_UI.md b/docs/PLAYER_UI.md index e560d67..b8de562 100644 --- a/docs/PLAYER_UI.md +++ b/docs/PLAYER_UI.md @@ -12,6 +12,20 @@ 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. Spikes appear only +with local blocked-movement feedback and do 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. diff --git a/docs/UI_STYLE.md b/docs/UI_STYLE.md index 49bcfda..a6238c0 100644 --- a/docs/UI_STYLE.md +++ b/docs/UI_STYLE.md @@ -30,10 +30,11 @@ roles must remain stable: - black or near-black for the application and map background; - purple for panels and elevated surfaces; - turquoise for interactive accents; -- blue for Player 1 and pink for Player 2 across every screen, map object, and - message; -- green for success, yellow for warnings, red for errors, blue for pause, and - orange for disconnection; +- yellow for Player 1 and blue for Player 2 across every screen, map object, + and message; each player's matching key and exit use the same ownership + color; +- green for success, amber for warnings, red for errors, periwinkle for pause, + and orange for disconnection; - green vegetation, bushes, and plants for maze walls. When two semantic roles use related colors, icons, labels, outlines, or shapes @@ -41,6 +42,11 @@ must keep them unambiguous. Important player and object information must not be communicated by color alone. Key objects use an additional label, outline, or marker. +The gameplay icon family is locally authored SVG artwork derived from the +approved running-player, key, arched-exit, crystal, opened-exit, and spike +reference silhouettes. The spike icon communicates only blocked movement or a +wall collision; it never represents a trap or a new gameplay mechanic. + WCAG AA contrast certification and dedicated color-vision-deficiency palettes are not MVP requirements. diff --git a/test/web/test_player_app.js b/test/web/test_player_app.js index 0ba523f..ae82dbe 100644 --- a/test/web/test_player_app.js +++ b/test/web/test_player_app.js @@ -269,6 +269,31 @@ test("player assets are local, Russian, accessible, and responsive", () => { assert.match(icons, /id="maze"/); }); +test("reference-derived SVG gameplay symbols preserve local yellow and blue ownership", () => { + const icons = fs.readFileSync(path.join(project, "web/icons.svg"), "utf8"); + const script = fs.readFileSync(path.join(project, "web/player.js"), "utf8"); + const css = fs.readFileSync(path.join(project, "web/player.css"), "utf8"); + const html = fs.readFileSync(path.join(project, "web/index.html"), "utf8"); + const playerUi = fs.readFileSync(path.join(project, "docs/PLAYER_UI.md"), "utf8"); + for (const iconId of ["player", "key", "exit-closed", "crystal", "exit-open", "spikes"]) { + assert.match(icons, new RegExp(``)); + } + assert.doesNotMatch(icons, /<(?:image|foreignObject)\b/i); + assert.doesNotMatch(icons, /data:image\//i); + assert.match(script, /icon\(variant \? "exit-open" : "exit-closed", "object object-exit"\)/); + assert.match(script, /icon\("crystal", "object object-vision"\)/); + assert.match(script, /icon\("player", `pawn/); + assert.match(html, /\/icons\.svg#spikes/); + assert.match(css, /--p1: #ffd33d/); + assert.match(css, /--p2: #41b6ff/); + assert.match(css, /--warning: #ffad38/); + assert.match(css, /--pause: #9b8cff/); + assert.match(css, /\.pawn-owner-two \{ border-style: dashed; \}/); + assert.match(html, /Жёлтый/); + assert.match(html, /Синий/); + assert.match(playerUi, /`player`, `key`, `exit-closed`,\n`crystal`, `exit-open`, and `spikes`/); +}); + test("observer view fits large screens and bounds zoom", () => { assert.equal(player.observerFitScale(1024, 600, 32, 32), 2.25); assert.equal(player.clampObserverZoom(.01), .25); diff --git a/web/icons.svg b/web/icons.svg index 63be1aa..25d94b1 100644 --- a/web/icons.svg +++ b/web/icons.svg @@ -1,5 +1,11 @@ - + + + + + + + @@ -9,7 +15,6 @@ - diff --git a/web/index.html b/web/index.html index f49f2b3..a47ad64 100644 --- a/web/index.html +++ b/web/index.html @@ -34,8 +34,8 @@

Игроки

-
P1СвободноСлот грустит
-
P2СвободноСлот грустит
+
СвободноСлот грустит
+
СвободноСлот грустит

Зрительный зал

0 / 4 эксперта по чужим ошибкам.

Большая красная кнопка

Старт доступен Игроку 1, когда оба слота на месте.

@@ -44,7 +44,7 @@