Files
scrabble-game/ui/README.md
T
Ilia Denisov e16076c89e
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 11s
CI / ui (pull_request) Successful in 31s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 55s
Stage 17 round 6 (#16-20): landing page, /app/ move, cache + stream fixes
Close out Stage 17 round 6:

- Landing page at / — one Vite build with two entries (index.html = game
  SPA, landing.html = a lightweight landing reusing the theme/i18n/
  aboutContent leaf modules, not the app store).
- Move the web game SPA to /app/; the Telegram Mini App stays at /telegram/
  (gateway webui.Handler(stripPrefix, indexName): landing at /, SPA at /app/
  + /telegram/). Per-language "Play in Telegram" link via new
  VITE_TELEGRAM_LINK_EN/_RU build vars (button hides when unset).
- Cache headers: hash-named /assets/* immutable, HTML shells no-cache (the
  go:embed zero modtime emitted no validators, so the client re-downloaded
  the whole bundle every launch).
- Live-stream 15s abort fix: an immediate heartbeat on open + a 10s default
  interval (the first tick at 15s raced the edge idle timeout -> reconnect
  storm).

PLAN/ARCHITECTURE(§13)/FUNCTIONAL(+ru)/gateway+ui+deploy READMEs updated;
round 6 closed. Tests: gateway webui/connectsrv units, ui landing unit + e2e,
full e2e (60) green.
2026-06-08 13:33:05 +02:00

85 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# scrabble-ui
Pure-HTML5 game client — **plain Svelte 5 (runes) + TypeScript + Vite**, no
SvelteKit. Talks to the `gateway` over **Connect-RPC + FlatBuffers**; embeddable in
platform webviews and packageable to native via Capacitor.
Stage 7 ships the **playable slice**: sign in (guest / email), the "my games" lobby,
auto-match, the board (place tiles by drag or tap, pass, exchange, resign), hint,
word-check + complaint, per-game chat and nudge, the live in-app stream, i18n (en/ru),
theme, and the profile. **Stage 8** adds friends/blocks (with one-time friend codes),
friend-game invitations, profile editing + email binding, the statistics screen, the
lobby notification badge, and the in-game history + GCG export (share or download,
finished games only).
## Scripts
```sh
pnpm install
pnpm start # mock mode (VITE_MOCK): lobby -> game with no backend, :5173
pnpm dev # against a running gateway (Vite proxies /scrabble.edge.v1.Gateway -> :8081)
pnpm check # svelte-check / tsc
pnpm test:unit # Vitest (pure logic + FlatBuffers codec)
pnpm test:e2e # Playwright smoke against the mock
pnpm build # static bundle into dist/ (prod ~67 KB gzip JS)
pnpm codegen # regenerate src/gen from edge.proto + scrabble.fbs (dev-time)
```
`GATEWAY_URL` overrides the dev proxy target; `VITE_GATEWAY_URL` sets the runtime
gateway origin for a packaged (non-proxied) build. `VITE_TELEGRAM_BOT_ID` (Stage 11)
enables the "Link Telegram" web sign-in (the Login Widget) — inert until the site
domain is registered with BotFather (`/setdomain`); `VITE_TELEGRAM_LINK` is the
share-to-Telegram deep-link base (Stage 9). `VITE_TELEGRAM_LINK_EN` / `VITE_TELEGRAM_LINK_RU`
are the per-language "Play in Telegram" links shown on the landing page (Stage 17).
The build has **two entries**: the game SPA (`index.html`, served at `/app/` and
`/telegram/`) and a lightweight landing page (`landing.html`, served at `/`).
## How it talks to the gateway
A single Connect `Execute(message_type, payload)` carries every unary op; the request
and response bodies are **FlatBuffers** tables (`pkg/fbs/scrabble.fbs`) in `payload`.
The session token rides in `Authorization: Bearer`; a domain failure comes back in
`result_code`. `Subscribe` is the live event stream. `lib/transport.ts` is the real
client; `lib/mock/` is an in-memory fake selected by `MODE === 'mock'` (and tree-shaken
out of production). Both speak the plain `lib/model.ts` types via `lib/codec.ts`.
**No board on the wire:** `StateView` is a summary + rack only, so the client
reconstructs the 15×15 board by replaying the decoded move journal (`game.history`).
**The play loop is alphabet-agnostic (Stage 13):** the rack and the play / exchange /
word-check requests carry **alphabet indices**, and the client caches each variant's
`(index, letter, value)` table — sent once behind `StateRequest.include_alphabet` — in
`lib/alphabet.ts`, rendering the rack and blank chooser from it. **Premium squares**
(`lib/premiums.ts`) stay a client-side geometry map **ported from
`scrabble-solver/rules/rules.go`** (pinned by a Vitest parity test); **tile values and the
alphabet now come from the server table** (their parity lives in the Go `engine.AlphabetTable`
test). Board, tiles and effects are pure CSS + Unicode — no image/font/SVG assets.
## Codegen
`src/gen/` is **committed**; CI builds it, it is not regenerated there (the same model
as the Go committed jet/fbs output). `pnpm codegen` runs `flatc --ts` on
`../pkg/fbs/scrabble.fbs` and `buf generate` (`protoc-gen-es`) on the edge proto. Needs
`flatc` 23.5.26 and `buf` on PATH.
## Theming
Design tokens are CSS custom properties (`src/app.css`); light/dark follows
`prefers-color-scheme` or an explicit choice in Settings. The token system is
**Telegram-themeParams-ready** (`lib/theme.ts`) — a Mini App can override the tokens at
runtime; the Telegram SDK itself is wired in the Telegram stage.
## Layout
```
src/
lib/ model, client facade, transport (+ mock), codec, board replay,
placement state machine, premiums (geometry), alphabet cache, stats, share,
i18n, theme, session, router, app store
components/ Header, Menu (+ badge), Modal, Toast, TabBar, Screen
screens/ Login, Lobby, NewGame, Profile, Settings, About, Friends, Stats
game/ Game, Board, Rack, Controls, MakeMove, Chat
gen/ committed edge codegen (FlatBuffers + Connect)
e2e/ Playwright smoke + social specs (mock)
```