Files
scrabble-game/ui/README.md
T
Ilia Denisov 8881214213 R6(a): de-stage code, docs, READMEs; split stage6_test
Mechanical, behaviour-preserving removal of Stage N / TODO-N / phase (RN)
references from comments, doc-comments, service READMEs, the current-state docs
(ARCHITECTURE, FUNCTIONAL+_ru, TESTING, UI_DESIGN), config-file comments, and the
.fbs/.proto schema comments. PLAN.md / PRERELEASE.md / CLAUDE.md keep the stage
history.

- Rename the only stage-named identifiers: registerStage8 -> registerSocialOps,
  registerStage11 -> registerLinkOps (gateway transcode).
- Split stage6_test.go: TestEmailLoginFlow -> email_test.go,
  TestGuestAutoMatchLeavesNoStats (+ provisionGuest) -> account_test.go.
- Regenerated proto bindings (push.pb.go, telegram_grpc.pb.go) from the de-staged
  .proto comments; FB Go/TS bindings unchanged (flatc strips schema comments).

go build/vet/gofmt clean across modules; integration typecheck and pnpm check green.
2026-06-10 16:56:03 +02:00

87 lines
4.6 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.
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. **Social** surfaces add 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 app ~97 KB gzip JS; per-chunk budget: scripts/bundle-size.mjs)
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`
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. `VITE_TELEGRAM_GAME_CHANNEL_NAME_EN` / `VITE_TELEGRAM_GAME_CHANNEL_NAME_RU`
are the per-language "Play in Telegram" links shown on the landing page.
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; its game events carry a state **delta**
that `lib/gamedelta.ts` applies to the per-game cache (`lib/gamecache.ts`), so a move renders without
a follow-up `game.state` (a gap falls back to a refetch). `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:** 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)
```