Stage 17 round 5 — board interaction & UI polish
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 11s
CI / ui (pull_request) Successful in 29s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m17s

- Even zoom: interpolate the board scroll toward a pre-clamped target as the real width
  grows/shrinks, so it magnifies A->B in one motion instead of lurching and snapping back
  near the edges/centre. Recentre only on a zoom toggle, never on a focus change — so a
  2nd+ placed tile and a hovered dragged tile no longer jump the board.
- Drag: highlight the aimed-at empty cell as a drop target; hover-hold auto-zoom now
  fires only for the first (zoom-in) hold.
- Pinch zoom: two-finger spread/close toggles zoom toward the pinch midpoint (preventDefault
  only for two touches, so one-finger scroll stays native); a second finger aborts a drag.
- Shuffle hop capped at 0.3s and disabled under reduce-motion.
- Make-move is a borderless icon button, disabled while the pending word is known illegal.
- Variant display names: english & russian_scrabble -> Scrabble/Скрэббл, erudit ->
  Erudite/Эрудит; the in-game title shows the variant name (was always 'Scrabble').
This commit is contained in:
Ilia Denisov
2026-06-07 09:34:07 +02:00
parent 3899ffda0f
commit 29d1193a0a
6 changed files with 171 additions and 39 deletions
+3 -3
View File
@@ -40,9 +40,9 @@ export const en = {
'new.title': 'New game',
'new.subtitle': 'Auto-match with another player',
'new.english': 'English',
'new.russian': 'Russian',
'new.erudit': 'Эрудит',
'new.english': 'Scrabble',
'new.russian': 'Scrabble',
'new.erudit': 'Erudite',
'new.find': 'Find a game',
'new.searching': 'Looking for an opponent…',
+2 -2
View File
@@ -41,8 +41,8 @@ export const ru: Record<MessageKey, string> = {
'new.title': 'Новая игра',
'new.subtitle': 'Автоподбор соперника',
'new.english': 'Английский',
'new.russian': 'Русский',
'new.english': 'Скрэббл',
'new.russian': 'Скрэббл',
'new.erudit': 'Эрудит',
'new.find': 'Найти игру',
'new.searching': 'Ищем соперника…',
+10 -1
View File
@@ -11,13 +11,22 @@ export interface VariantOption {
label: MessageKey;
}
// ALL_VARIANTS lists every variant in display order.
// ALL_VARIANTS lists every variant in display order. The labels are display names, not
// language names: both Scrabble variants render as "Scrabble"/"Скрэббл" and Erudit as
// "Erudite"/"Эрудит" (Stage 17) — the offered list is language-gated, so within one
// language the names stay distinct.
export const ALL_VARIANTS: VariantOption[] = [
{ id: 'english', label: 'new.english' },
{ id: 'russian_scrabble', label: 'new.russian' },
{ id: 'erudit', label: 'new.erudit' },
];
// variantNameKey returns the i18n key for a variant's display name (used by the in-game
// title and the lobby cards).
export function variantNameKey(v: Variant): MessageKey {
return ALL_VARIANTS.find((o) => o.id === v)?.label ?? 'new.english';
}
// VARIANT_LANGUAGE maps each variant to its game language. en -> English;
// ru -> Russian + Эрудит.
export const VARIANT_LANGUAGE: Record<Variant, 'en' | 'ru'> = { english: 'en', russian_scrabble: 'ru', erudit: 'ru' };