# 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). ## 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`). Premium squares and tile values (`lib/premiums.ts`) are a client-side map **ported from `scrabble-solver/rules/rules.go`** (pinned by a Vitest parity 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, 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) ```