fix(ui): hold each splash word for the pause before the readiness check
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 57s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m18s

The dismiss check fired at the instant a word finished laying, so a word
was never held: ЭРУДИТ fell straight into the lobby (too fast) and
ЗАГРУЗКА got no readable pause. The pause was a *leading* gap before the
next word, not a hold after the current one.

Move the hold to after each word and run the check after it: every word
(ЭРУДИТ included) now stays up for PAUSE_MS before the splash either
dismisses or lays the next word. prefixMs = WORD_MS + PAUSE_MS,
cycleMs = 2*(WORD_MS + PAUSE_MS).
This commit is contained in:
Ilia Denisov
2026-06-21 10:42:31 +02:00
parent ba6ee90278
commit 9642cafc1f
3 changed files with 39 additions and 32 deletions
+20 -18
View File
@@ -76,7 +76,8 @@ export const SPLASH_TILES: SplashTile[] = [...ERUDIT_TILES, ...ZAGRUZKA_TILES, .
/** ERUDIT_KEYS is the set of ЭРУДИТ tile keys — the tiles kept on screen across a clear. */
export const ERUDIT_KEYS: ReadonlySet<string> = new Set(ERUDIT_TILES.map((t) => t.key));
/** WORD_MS is the time to lay one whole word; PAUSE_MS the gap between words. */
/** WORD_MS is the time to lay one whole word; PAUSE_MS the hold after each word — so the word
* stays readable before the next word starts or the splash dismisses into the lobby. */
export const WORD_MS = 1000;
export const PAUSE_MS = 250;
@@ -106,33 +107,34 @@ function revealSteps(tiles: SplashTile[], base: number, perTile: number): Splash
/**
* splashSchedule builds the reveal plan. Each word is laid over wordMs (so its per-tile
* stagger is wordMs divided by the word's tile count), a readiness check lands at every word
* boundary, and pauseMs separates the words; after ОЖИДАНИЕ the cycle clears the two vertical
* words and restarts (ЭРУДИТ persists). wordMs and pauseMs are overridable for tuning/tests.
* stagger is wordMs divided by the word's tile count), then **held for pauseMs** so it stays
* readable; only after that hold does a readiness check land — so the splash never dismisses
* (nor starts the next word) the instant a word finishes. The next word begins right at the
* check. After ОЖИДАНИЕ the cycle clears the two vertical words and restarts (ЭРУДИТ persists).
* wordMs and pauseMs are overridable for tuning/tests.
*/
export function splashSchedule(opts: { wordMs?: number; pauseMs?: number } = {}): SplashSchedule {
const wordMs = opts.wordMs ?? WORD_MS;
const pauseMs = opts.pauseMs ?? PAUSE_MS;
const sV = wordMs / ZAGRUZKA_TILES.length;
const hold = wordMs + pauseMs; // lay the word, then hold it readable before the check
// Prefix: ЭРУДИТ left → right, the word completing at wordMs, then a readiness check.
// Prefix: ЭРУДИТ left → right, held, then a readiness check.
const prefix: SplashStep[] = [
...revealSteps(ERUDIT_TILES, 0, wordMs / ERUDIT_TILES.length),
{ atMs: wordMs, kind: 'check' },
{ atMs: hold, kind: 'check' },
];
// Cycle: pause, ЗАГРУЗКА, check, pause, ОЖИДАНИЕ, check, pause, clear. The leading pause is
// the gap after ЭРУДИТ (and, on repeat, after the previous cycle's clear).
const sV = wordMs / ZAGRUZKA_TILES.length;
const zBase = pauseMs;
const oBase = pauseMs + wordMs + pauseMs;
const clearAt = oBase + wordMs + pauseMs;
// Cycle: ЗАГРУЗКА, hold, check, ОЖИДАНИЕ, hold, check, clear. Each word starts at the previous
// word's check (no leading gap); the hold lives at the end of every word.
const endAt = 2 * hold;
const cycle: SplashStep[] = [
...revealSteps(ZAGRUZKA_TILES, zBase, sV),
{ atMs: zBase + wordMs, kind: 'check' },
...revealSteps(OZHIDANIE_TILES, oBase, sV),
{ atMs: oBase + wordMs, kind: 'check' },
{ atMs: clearAt, kind: 'clear' },
...revealSteps(ZAGRUZKA_TILES, 0, sV),
{ atMs: hold, kind: 'check' },
...revealSteps(OZHIDANIE_TILES, hold, sV),
{ atMs: endAt, kind: 'check' },
{ atMs: endAt, kind: 'clear' },
];
return { prefix, cycle, prefixMs: wordMs, cycleMs: clearAt };
return { prefix, cycle, prefixMs: hold, cycleMs: endAt };
}