In-game UX: board highlight + score badge, full-width rack, bag badge, zoom setting #240

Merged
developer merged 3 commits from feature/ingame-ux-board-highlight into development 2026-07-10 14:06:20 +00:00
Owner

Improves the in-game UX by removing the under-board status strip and moving its signals to
the board and the surrounding chrome. One PR, per the agreed plan.

What changed

  1. Bag count — a badge on the 🔄 Exchange/Pass control (hidden at zero, mirrors the hint
    badge) plus a non-scrolling "N in the bag" footer at the foot of the move table.
  2. Whose-turn / win-lose — moved out of the removed strip into a thin line above the score
    plaques
    (turn text during play; the viewer's result once the game ends). Medals stay
    hotseat-only, unchanged.
  3. Tentative-move feedback → the board. The old "invalid move" / "words: score" caption is
    gone. Staged tiles now tint light green when they form a word (a shade darker on the
    committed board tiles the word runs through) or a calm pink when they form none.
  4. Orange score badge on the main word — digit sized like a tile's point value (scales with
    zoom), anchored to a tile corner by the owner's edge rules and clamped to stay on-board.
  5. Full-width rack — a seven-column grid filling the tray in both portrait and landscape, so
    the tiles are square and as large as the row allows; the confirm control takes the fixed 7th
    slot while a play is staged.
  6. "Zoom the board" setting (touch-only, default on, device-local) gates the tile-placement
    auto-zoom. Additionally, taking a hint while zoomed in now zooms out so the highlighted
    hint word is never left off-screen.

Design note

The board highlight + badge geometry (which cells a formed word covers, where the badge
anchors) is a new pure client-side helper ui/src/lib/formed.ts, independent of the move
evaluator — so it works whether the preview came from the local dictionary or the network
fallback. Legality and score stay with the eval; geometry with the board.

New per-theme tokens in app.css: --tile-pending-legal / -illegal, --tile-formed,
--score-badge. Colours are starting values — please eyeball them on the contour.

Tests & docs

  • Unit: lib/formed.test.ts (15 cases — word geometry H/V/cross/lone-tile + badge corner at
    every edge and the 15-letter clamp).
  • e2e: new ingame-ux.spec.ts (turn strip, bag badge + table footer, staged-play green highlight +
    score badge, in the rack); updated game/quickmatch/smoke/zoom specs for the removed
    .status caption and the new hint-zooms-out behaviour.
  • Docs baked in: FUNCTIONAL.md (+_ru), UI_DESIGN.md, ARCHITECTURE.md.

Verified locally green: pnpm check, pnpm test:unit (583), pnpm build, pnpm test:e2e
(chromium + webkit), plus a portrait/landscape visual pass on the mock.

No schema or wire change — the contour does not need a wipe.

Improves the in-game UX by removing the under-board status strip and moving its signals to the board and the surrounding chrome. One PR, per the agreed plan. ## What changed 1. **Bag count** — a badge on the 🔄 Exchange/Pass control (hidden at zero, mirrors the hint badge) plus a non-scrolling "N in the bag" footer at the foot of the move table. 2. **Whose-turn / win-lose** — moved out of the removed strip into a **thin line above the score plaques** (turn text during play; the viewer's result once the game ends). Medals stay hotseat-only, unchanged. 3. **Tentative-move feedback → the board.** The old "invalid move" / "words: score" caption is gone. Staged tiles now tint **light green** when they form a word (a shade **darker** on the committed board tiles the word runs through) or a **calm pink** when they form none. 4. **Orange score badge** on the main word — digit sized like a tile's point value (scales with zoom), anchored to a tile corner by the owner's edge rules and clamped to stay on-board. 5. **Full-width rack** — a seven-column grid filling the tray in both portrait and landscape, so the tiles are square and as large as the row allows; the ✅ confirm control takes the fixed 7th slot while a play is staged. 6. **"Zoom the board" setting** (touch-only, default on, device-local) gates the tile-placement auto-zoom. Additionally, taking a **hint while zoomed in now zooms out** so the highlighted hint word is never left off-screen. ## Design note The board highlight + badge **geometry** (which cells a formed word covers, where the badge anchors) is a new **pure client-side helper** `ui/src/lib/formed.ts`, independent of the move evaluator — so it works whether the preview came from the local dictionary or the network fallback. Legality and score stay with the eval; geometry with the board. New per-theme tokens in `app.css`: `--tile-pending-legal` / `-illegal`, `--tile-formed`, `--score-badge`. **Colours are starting values — please eyeball them on the contour.** ## Tests & docs - Unit: `lib/formed.test.ts` (15 cases — word geometry H/V/cross/lone-tile + badge corner at every edge and the 15-letter clamp). - e2e: new `ingame-ux.spec.ts` (turn strip, bag badge + table footer, staged-play green highlight + score badge, ✅ in the rack); updated `game`/`quickmatch`/`smoke`/`zoom` specs for the removed `.status` caption and the new hint-zooms-out behaviour. - Docs baked in: `FUNCTIONAL.md` (+`_ru`), `UI_DESIGN.md`, `ARCHITECTURE.md`. Verified locally green: `pnpm check`, `pnpm test:unit` (583), `pnpm build`, `pnpm test:e2e` (chromium + webkit), plus a portrait/landscape visual pass on the mock. No schema or wire change — the contour does not need a wipe.
developer added 1 commit 2026-07-10 12:59:16 +00:00
feat(ui): move in-game status to the board — highlight, score badge, full-width rack
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Failing after 13s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Failing after 0s
CI / deploy (pull_request) Has been skipped
77a690fcf6
Remove the under-board status strip and relocate its signals:
- bag count -> a badge on the exchange/pass control + the foot of the move table
- whose-turn / win-lose -> a thin strip above the score plaques
- the tentative-move caption -> the board itself: staged tiles tint green (legal) or
  pink (illegal), the board tiles a formed word runs through go a shade darker, and an
  orange score badge sits on the main word (digit sized like a tile value, clamped on-board)

The word geometry (covered cells + badge anchor) is a new pure client-side helper
(ui/src/lib/formed.ts), independent of the move evaluator, so it works on the local or
network preview path alike; the badge's number still comes from the preview score.

Rack: a seven-column grid filling the tray width in both layouts — square, full-width
tiles — with the confirm control in the fixed 7th slot.

Settings: a touch-only "Zoom the board" toggle (default on, device-local) gates the
tile-placement auto-zoom; taking a hint while zoomed in now zooms out so the highlighted
hint word is never left off-screen.

Docs (FUNCTIONAL +_ru, UI_DESIGN, ARCHITECTURE) and e2e/unit tests updated.
developer added 1 commit 2026-07-10 13:03:31 +00:00
chore(ui): raise the app bundle budget to 126 KB for the in-game board UX
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 1m10s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m59s
1e1117c28e
developer added 1 commit 2026-07-10 13:58:08 +00:00
fix(ui): one-word games must not highlight phantom cross words; review polish
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 21s
CI / ui (pull_request) Successful in 1m25s
CI / conformance (pull_request) Successful in 11s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 2m2s
bf46b9492d
Board-highlight bug (reported on the contour): formedGeometry walked cross words
unconditionally, so in a single-word (one-word-per-turn) game a staged tile sitting
next to a committed tile lit up a green "cross word" the engine ignores — and which
need not even be a real word (the reported "БО lights up green in a one-word ПОПА
play"). Gate the cross-word walk on the game's multipleWordsPerTurn flag. The score
(8) was already correct — a premium square under the main word.

Also, from review:
- the turn strip reads the staged play's "WORD+WORD = N" while composing a legal move,
  reverting to the turn / result text otherwise;
- the Exchange/Pass dialog shows the bag count ("In the bag: N" / "Bag is empty")
  right-aligned in the title row, via a new optional Modal `titleAside`;
- cosmetics: half the turn strip's bottom padding (the plaques below carry their own
  top pad); a top gap above the landscape rack (it sat flush under the docked history);
  more horizontal padding on tab count badges so a 2-3 digit bag count clears the pill
  ends;
- admin console: the game Summary now shows the single-word / multiple-words rule.

Tests: formed single-word case added; full unit (584) + e2e (chromium + webkit, 113
each) green; backend build + adminconsole templates parse. Docs (FUNCTIONAL +_ru,
UI_DESIGN) updated.
owner approved these changes 2026-07-10 14:05:08 +00:00
developer merged commit 7b4d2421e2 into development 2026-07-10 14:06:20 +00:00
developer deleted branch feature/ingame-ux-board-highlight 2026-07-10 14:06:20 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: developer/scrabble-game#240