Files
scrabble-game/docs/UI_DESIGN.md
T
Ilia Denisov 92a4de3bf4
Tests · Go / test (pull_request) Successful in 7s
Tests · Integration / integration (pull_request) Successful in 10s
Tests · UI / test (pull_request) Successful in 12s
Stage 7 polish: docs + mark Stage 7 done (Part H)
- new docs/UI_DESIGN.md (design system: shell, nav, tab-bar, tiles, board zoom/labels, HoldConfirm, banner rotator, result iconography)
- ARCHITECTURE: app-shell + announcement channel (mock->server) + hint place-on-board / no_hint_available contract + board-style setting
- FUNCTIONAL(+ru): hint-on-board, word-check constraints/throttle, board style
- PLAN: Stage 7 -> done + polish refinement note; CLAUDE sources list
2026-06-03 13:38:17 +02:00

4.4 KiB
Raw Blame History

Scrabble Game — UI design system

Visual and interaction conventions for the ui client. Behaviour lives in FUNCTIONAL.md; cross-service architecture (including the global points this doc references) lives in ARCHITECTURE.md. The client is pure HTML5/CSS + Unicode — no image/font/SVG assets; icons are CSS shapes or emoji glyphs. Tokens are CSS custom properties (ui/src/app.css), light/dark via prefers-color-scheme or an explicit Settings choice, and Telegram-themeParams-ready (the tokens can be overridden at runtime).

Layout shell (components/Screen.svelte)

A mobile-app feel: the screen is a full-height flex column where the nav bar grows to absorb spare vertical space (its buttons stay top-aligned) and everything else — the announcement strip, the content, and the optional bottom tab bar — pins to the bottom, the strip directly above the content. Tall content scrolls within the content region. Every screen except Login uses Screen.

Navigation

  • Back: a thin, compact < drawn from two rotated CSS borders (Header.svelte .chev) — lighter than a glyph.
  • Hamburger: a CSS three-bar (Menu.svelte), deliberately larger; opens a dropdown of items (lobby: Profile/Settings/About; game: History/Chat/Check word/Drop game).
  • Tab bar (TabBar.svelte): square, borderless, evenly distributed buttons — a large emoji icon over a tiny truncated label. A press highlights a rounded square behind the icon (slightly larger than it) until release; spacing keeps adjacent labels from touching. No text selection on nav / tab-bar / buttons (user-select: none).

Tiles & board

  • Tiles: the letter sits in the top-left corner (offset a touch more than the value), the point value bottom-right; blanks show no value.
  • Board zoom (Board.svelte): a two-state zoom (full 15×15 ↔ ~9 cells) via transform: scale() on an inner layer inside a fixed-size viewport (the page never reflows; the viewport scrolls when zoomed), with a smooth transition. Cell/tile text lives in a counter-scaled layer (scale(1/z)) sized in cqw, so labels stay a constant size (relatively smaller at higher zoom). On touch, attempting to place a tile auto-zooms in centred on the target; double-tap and pinch toggle.
  • Bonus-square labels — a Settings choice (boardlabels.ts): beginner shows a split 3× / word (localized слово/буква), classic a single 3W / 3С, none nothing. Default beginner.
  • Grid lines: the inter-cell gap shows a contrasting --cell-line (darker in light, lighter in dark) to avoid a wavy-line optical illusion.

Controls

  • HoldConfirm (components/HoldConfirm.svelte): the shared press-and-hold control. A short tap opens a small popover above the button; a ~0.7 s hold runs the primary action immediately. Reused by:
    • MakeMove (appears when ≥1 tile is pending; the rack collapses its used slots and shifts left to free room): a 🏁 button whose popover offers Make move / Reset .
    • Game tab bar: 🔄 Draw (disabled when the bag is empty), 🥺 Skip, 🛟 Hint (with a remaining-count badge) — each confirmed by an Ok popover; 🔀 Shuffle has no label and no confirm. The under-board slot shows the Scores: N preview.

Announcement banner (components/AdBanner.svelte, lib/banner.ts)

A one-line inset strip under the nav bar. Content is minimal markdown (text + links, escaped + linkified). A parameterised rotator drives messages: a fitting message holds holdMs (default 60 s) then cross-fades to the next; a message wider than the strip pauses (edgePauseMs), scrolls to its right edge at scrollPxPerSec, pauses, and repeats until the cycle exceeds holdMs. Today a mock provider rotates a long and a short message; the source becomes a server-driven channel later (see ARCHITECTURE).

Result / status iconography (lib/result.ts)

Lobby rows show two lines (opponents, then result + score) with a large place-based emoji on the right: Victory 🏆 / Defeat 🥈 / Draw 🏅, and for 34-player games II 🥈 / III 🥉 / IV 🏅; active games show Your move 🟢 / Opponent's move ; invitations use 💌.

Caveat

Emoji are rendered by the platform's system emoji font, so their exact look varies across OSes — acceptable for the MVP, and consistent with the no-asset rule (no glyphs are downloaded).