From fc40263b235567b74c84df323a4c5cccc9299c4a Mon Sep 17 00:00:00 2001 From: d1rshan Date: Fri, 29 May 2026 19:56:58 +0530 Subject: [PATCH 1/9] consistency --- .../{use-falling-words-game.ts => engine.ts} | 127 +++++++----------- .../src/features/games/falling-words/types.ts | 12 -- .../src/features/games/falling-words/view.tsx | 71 ++++------ 3 files changed, 76 insertions(+), 134 deletions(-) rename apps/frontend/src/features/games/falling-words/{use-falling-words-game.ts => engine.ts} (81%) diff --git a/apps/frontend/src/features/games/falling-words/use-falling-words-game.ts b/apps/frontend/src/features/games/falling-words/engine.ts similarity index 81% rename from apps/frontend/src/features/games/falling-words/use-falling-words-game.ts rename to apps/frontend/src/features/games/falling-words/engine.ts index 79e56d1..c330c20 100644 --- a/apps/frontend/src/features/games/falling-words/use-falling-words-game.ts +++ b/apps/frontend/src/features/games/falling-words/engine.ts @@ -10,11 +10,7 @@ import { getWordBank } from "@/features/content/word-banks/manager"; import type { WordBankId } from "@/features/content/word-banks/types"; import type { DifficultyKey, GamePhase } from "../core/types"; -import type { - DifficultyConfig, - FallingWord, - UseFallingWordsGameOptions, -} from "./types"; +import type { DifficultyConfig, FallingWord } from "./types"; const difficultyConfigs: Record = { easy: { spawnIntervalMs: 1800, baseSpeed: 68, speedJitter: 20, gravity: 6 }, @@ -24,6 +20,14 @@ const difficultyConfigs: Record = { const rand = (min: number, max: number) => Math.random() * (max - min) + min; +export type UseGameOptions = { + onComplete?: (result: { + gameId: "falling-words"; + score: number; + difficulty: DifficultyKey; + }) => void | Promise; +}; + function createFallingWord( id: number, width: number, @@ -59,9 +63,9 @@ function findExactMatch(words: FallingWord[], value: string) { .sort((left, right) => right.y - left.y)[0]; } -export function useFallingWordsGame( +export function useEngine( wordBankId: WordBankId, - options: UseFallingWordsGameOptions = {}, + options: UseGameOptions = {}, ) { const wordBank = getWordBank(wordBankId); @@ -82,18 +86,15 @@ export function useFallingWordsGame( const [currentInput, setCurrentInput] = createSignal(""); const [elapsedMs, setElapsedMs] = createSignal(0); - const selectedDifficulty = createMemo(() => difficultyConfigs[difficulty()]); + const config = createMemo(() => difficultyConfigs[difficulty()]); const score = createMemo(() => formatScore(elapsedMs())); const focusedWordId = createMemo((prevFocusedWordId?: number | null) => { const input = currentInput(); const words = activeWords(); - if (input.length === 0) { - return null; - } + if (input.length === 0) return null; - // Keep focus sticky if the previously focused word is still a valid exact prefix match if (prevFocusedWordId != null) { const prevWord = words.find((w) => w.id === prevFocusedWordId); if (prevWord && prevWord.text.startsWith(input)) { @@ -101,7 +102,6 @@ export function useFallingWordsGame( } } - // Try exact prefix match first const exactPrefixCandidates = words .filter((word) => word.text.startsWith(input)) .sort((left, right) => right.y - left.y); @@ -110,8 +110,6 @@ export function useFallingWordsGame( return exactPrefixCandidates[0]?.id ?? null; } - // If no exact prefix match, find the word that HAS the longest prefix match with currentInput - // This allows for mistakes at the end of the input while keeping focus let bestWordId = null; let longestPrefix = 0; let lowestY = -1; @@ -126,14 +124,11 @@ export function useFallingWordsGame( prefixLen++; } - if (prefixLen > 0) { - if (prefixLen > longestPrefix) { + if (prefixLen > 0 && prefixLen >= longestPrefix) { + if (prefixLen > longestPrefix || word.y > lowestY) { longestPrefix = prefixLen; bestWordId = word.id; lowestY = word.y; - } else if (prefixLen === longestPrefix && word.y > lowestY) { - bestWordId = word.id; - lowestY = word.y; } } } @@ -145,7 +140,6 @@ export function useFallingWordsGame( if (phase() === "running" && runStartTime > 0) { return elapsedBeforeRun + (performance.now() - runStartTime); } - return elapsedBeforeRun; }; @@ -164,20 +158,16 @@ export function useFallingWordsGame( } }; - const focusInput = () => { - inputRef?.focus(); - }; + const focusInput = () => inputRef?.focus(); const spawnWord = () => { - if (!wordBank || wordBank.words.length === 0) { - return; - } + if (!wordBank || wordBank.words.length === 0) return; const nextWord = createFallingWord( nextWordId, fieldWidth(), wordBank.words, - selectedDifficulty(), + config(), ); nextWordId += 1; setActiveWords((current) => [...current, nextWord]); @@ -189,9 +179,7 @@ export function useFallingWordsGame( setPhase("idle"); setActiveWords([]); setCurrentInput(""); - if (inputRef) { - inputRef.value = ""; - } + if (inputRef) inputRef.value = ""; focusInput(); setElapsedMs(0); lastFrameTime = 0; @@ -226,21 +214,14 @@ export function useFallingWordsGame( const submitExactMatch = (value: string, requireFocusMatch = false) => { const targetWord = findExactMatch(activeWords(), value); - if (!targetWord) { - return false; - } - - if (requireFocusMatch && targetWord.id !== focusedWordId()) { - return false; - } + if (!targetWord) return false; + if (requireFocusMatch && targetWord.id !== focusedWordId()) return false; setActiveWords((current) => current.filter((word) => word.id !== targetWord.id), ); setCurrentInput(""); - if (inputRef) { - inputRef.value = ""; - } + if (inputRef) inputRef.value = ""; return true; }; @@ -249,7 +230,6 @@ export function useFallingWordsGame( resetGame(nextDifficulty); return; } - setDifficulty(nextDifficulty); }; @@ -285,23 +265,16 @@ export function useFallingWordsGame( if (event.key === "Enter") { event.preventDefault(); - - if (phase() === "idle" || phase() === "game-over") { - startGame(); - } + if (phase() === "idle" || phase() === "game-over") startGame(); } }; const handleVisibilityChange = () => { - if (document.hidden && phase() === "running") { - endGame(); - } + if (document.hidden && phase() === "running") endGame(); }; const handleWindowBlur = () => { - if (phase() === "running") { - endGame(); - } + if (phase() === "running") endGame(); }; createEffect(() => { @@ -315,7 +288,7 @@ export function useFallingWordsGame( lastFrameTime = timestamp; setElapsedMs(elapsedBeforeRun + (timestamp - runStartTime)); - const difficultyConfig = selectedDifficulty(); + const difficultyConfig = config(); if (timestamp - lastSpawnTime >= difficultyConfig.spawnIntervalMs) { spawnWord(); @@ -337,9 +310,8 @@ export function useFallingWordsGame( const nextRotation = word.rotation + word.angularVelocity * deltaSeconds; - if (fieldHeight() > 0 && nextY >= fieldHeight() - 40) { + if (fieldHeight() > 0 && nextY >= fieldHeight() - 40) hitBottom = true; - } return { ...word, @@ -373,13 +345,8 @@ export function useFallingWordsGame( setTimeout(updateFieldSize, 100); focusInput(); - const observer = new ResizeObserver(() => { - updateFieldSize(); - }); - - if (fieldRef) { - observer.observe(fieldRef); - } + const observer = new ResizeObserver(() => updateFieldSize()); + if (fieldRef) observer.observe(fieldRef); window.addEventListener("blur", handleWindowBlur); document.addEventListener("visibilitychange", handleVisibilityChange); @@ -391,27 +358,29 @@ export function useFallingWordsGame( }); }); - onCleanup(() => { - stopLoop(); - }); + onCleanup(stopLoop); return { - activeWords, - currentInput, - difficulty, - focusedWordId, - handleDifficultyChange, - handleInput, - handleKeyDown, - phase, - score, - setInputRef: (element: HTMLInputElement) => { - inputRef = element; + game: { + phase, + difficulty, + activeWords, + currentInput, + focusedWordId, + score, }, - setFieldRef: (element: HTMLDivElement) => { - fieldRef = element; + actions: { + handleDifficultyChange, + handleInput, + handleKeyDown, + setInputRef: (element: HTMLInputElement) => { + inputRef = element; + }, + setFieldRef: (element: HTMLDivElement) => { + fieldRef = element; + }, + focusInput, }, - focusInput, wordBank, }; } diff --git a/apps/frontend/src/features/games/falling-words/types.ts b/apps/frontend/src/features/games/falling-words/types.ts index 3a6cf30..1d99b23 100644 --- a/apps/frontend/src/features/games/falling-words/types.ts +++ b/apps/frontend/src/features/games/falling-words/types.ts @@ -1,5 +1,3 @@ -import type { DifficultyKey } from "../core/types"; - export type DifficultyConfig = { spawnIntervalMs: number; baseSpeed: number; @@ -17,13 +15,3 @@ export type FallingWord = { rotation: number; angularVelocity: number; }; - -type CompletedGameResult = { - gameId: "falling-words"; - score: number; - difficulty: DifficultyKey; -}; - -export type UseFallingWordsGameOptions = { - onComplete?: (result: CompletedGameResult) => void | Promise; -}; diff --git a/apps/frontend/src/features/games/falling-words/view.tsx b/apps/frontend/src/features/games/falling-words/view.tsx index ed88ccd..0cd23fe 100644 --- a/apps/frontend/src/features/games/falling-words/view.tsx +++ b/apps/frontend/src/features/games/falling-words/view.tsx @@ -1,41 +1,23 @@ import { Show } from "solid-js"; -import { useAuthSession } from "@/features/auth/hooks"; -import { useCreateResultMutation } from "@/features/users/results/api"; -import { toast } from "@/lib/toast"; - import type { GameViewProps } from "../core/types"; +import { useSubmitGameResult } from "../core/hooks"; import { DifficultySelector } from "../core/components/difficulty-selector"; import { GameMeta } from "../core/components/game-meta"; import FallingWordsField from "./components/falling-words-field"; import { FallingWordsHud as Hud } from "./components/falling-words-hud"; -import { useFallingWordsGame } from "./use-falling-words-game"; +import { useEngine } from "./engine"; import { meta } from "./meta"; function FallingWordsView(props: GameViewProps) { - const auth = useAuthSession(); - const createResultMutation = useCreateResultMutation(); - const game = useFallingWordsGame(props.wordBankId ?? meta.defaultWordBankId, { - onComplete: (result) => { - if (!auth.isAuthenticated()) { - return; - } - - const minimumScore = meta.minScores[result.difficulty]; - - if (result.score < minimumScore) { - toast.info( - `Result not saved. Test too short. Minimum score for ${result.difficulty} is ${minimumScore}.`, - ); - return; - } + const saveResult = useSubmitGameResult(meta.minScores); - createResultMutation.mutate({ - gameId: result.gameId, - score: result.score, - difficulty: result.difficulty, - }); - }, + const { + game: gameState, + actions, + wordBank, + } = useEngine(props.wordBankId ?? meta.defaultWordBankId, { + onComplete: saveResult, }); return ( @@ -43,40 +25,43 @@ function FallingWordsView(props: GameViewProps) {
- +
- - + +
From 11279ecb728b11faf7124bbd617fde710b320c95 Mon Sep 17 00:00:00 2001 From: d1rshan Date: Fri, 29 May 2026 19:58:10 +0530 Subject: [PATCH 2/9] rename hud --- .../components/{falling-words-hud.tsx => hud.tsx} | 4 ++-- apps/frontend/src/features/games/falling-words/view.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename apps/frontend/src/features/games/falling-words/components/{falling-words-hud.tsx => hud.tsx} (76%) diff --git a/apps/frontend/src/features/games/falling-words/components/falling-words-hud.tsx b/apps/frontend/src/features/games/falling-words/components/hud.tsx similarity index 76% rename from apps/frontend/src/features/games/falling-words/components/falling-words-hud.tsx rename to apps/frontend/src/features/games/falling-words/components/hud.tsx index 8052da2..7e12820 100644 --- a/apps/frontend/src/features/games/falling-words/components/falling-words-hud.tsx +++ b/apps/frontend/src/features/games/falling-words/components/hud.tsx @@ -1,11 +1,11 @@ import { GameStat } from "../../core/components/game-stat"; -export type FallingWordsHudProps = { +export type HudProps = { score: number; typedValue: string; }; -export function FallingWordsHud(props: FallingWordsHudProps) { +export function Hud(props: HudProps) { return (
diff --git a/apps/frontend/src/features/games/falling-words/view.tsx b/apps/frontend/src/features/games/falling-words/view.tsx index 0cd23fe..61b5e19 100644 --- a/apps/frontend/src/features/games/falling-words/view.tsx +++ b/apps/frontend/src/features/games/falling-words/view.tsx @@ -5,7 +5,7 @@ import { useSubmitGameResult } from "../core/hooks"; import { DifficultySelector } from "../core/components/difficulty-selector"; import { GameMeta } from "../core/components/game-meta"; import FallingWordsField from "./components/falling-words-field"; -import { FallingWordsHud as Hud } from "./components/falling-words-hud"; +import { Hud } from "./components/hud"; import { useEngine } from "./engine"; import { meta } from "./meta"; From 21345d0c76e379c81465b9876c3e4342e8452553 Mon Sep 17 00:00:00 2001 From: d1rshan Date: Fri, 29 May 2026 19:59:29 +0530 Subject: [PATCH 3/9] rename field --- .../components/{falling-words-field.tsx => field.tsx} | 6 +++--- apps/frontend/src/features/games/falling-words/view.tsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename apps/frontend/src/features/games/falling-words/components/{falling-words-field.tsx => field.tsx} (97%) diff --git a/apps/frontend/src/features/games/falling-words/components/falling-words-field.tsx b/apps/frontend/src/features/games/falling-words/components/field.tsx similarity index 97% rename from apps/frontend/src/features/games/falling-words/components/falling-words-field.tsx rename to apps/frontend/src/features/games/falling-words/components/field.tsx index 5ea9b6c..606f9c5 100644 --- a/apps/frontend/src/features/games/falling-words/components/falling-words-field.tsx +++ b/apps/frontend/src/features/games/falling-words/components/field.tsx @@ -5,7 +5,7 @@ import { Kbd } from "@/components/ui/kbd"; import type { GamePhase } from "../../core/types"; import type { FallingWord } from "../types"; -type FallingWordsFieldProps = { +type FieldProps = { ref?: (el: HTMLDivElement) => void; words: FallingWord[]; currentInput: string; @@ -15,7 +15,7 @@ type FallingWordsFieldProps = { onFieldClick: () => void; }; -function FallingWordsField(props: FallingWordsFieldProps) { +function Field(props: FieldProps) { return (
- Date: Sun, 31 May 2026 10:28:52 +0530 Subject: [PATCH 4/9] view --- apps/frontend/src/features/games/falling-words/meta.ts | 4 ++-- apps/frontend/src/features/games/falling-words/view.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/frontend/src/features/games/falling-words/meta.ts b/apps/frontend/src/features/games/falling-words/meta.ts index 462f9c9..1b90f5c 100644 --- a/apps/frontend/src/features/games/falling-words/meta.ts +++ b/apps/frontend/src/features/games/falling-words/meta.ts @@ -1,5 +1,5 @@ import type { GameModule } from "../core/types"; -import FallingWordsView from "./view"; +import View from "./view"; export const meta: GameModule = { id: "falling-words", @@ -8,5 +8,5 @@ export const meta: GameModule = { defaultWordBankId: "english/core-1k", difficultyKeys: ["easy", "medium", "hard"] as const, minScores: { easy: 20, medium: 15, hard: 10 }, - View: FallingWordsView, + View, }; diff --git a/apps/frontend/src/features/games/falling-words/view.tsx b/apps/frontend/src/features/games/falling-words/view.tsx index 4988c93..f34df99 100644 --- a/apps/frontend/src/features/games/falling-words/view.tsx +++ b/apps/frontend/src/features/games/falling-words/view.tsx @@ -9,7 +9,7 @@ import { Hud } from "./components/hud"; import { useEngine } from "./engine"; import { meta } from "./meta"; -function FallingWordsView(props: GameViewProps) { +function View(props: GameViewProps) { const saveResult = useSubmitGameResult(meta.minScores); const { @@ -68,4 +68,4 @@ function FallingWordsView(props: GameViewProps) { ); } -export default FallingWordsView; +export default View; From 1ca40cb74e759c3c22a7fe272bfe896846272b21 Mon Sep 17 00:00:00 2001 From: d1rshan Date: Sun, 31 May 2026 10:32:23 +0530 Subject: [PATCH 5/9] more stuff --- .../src/features/games/falling-words/components/field.tsx | 4 +--- .../src/features/games/falling-words/components/hud.tsx | 2 +- apps/frontend/src/features/games/falling-words/view.tsx | 2 +- .../games/survival/components/{survival-hud.tsx => hud.tsx} | 4 ++-- apps/frontend/src/features/games/survival/view.tsx | 2 +- 5 files changed, 6 insertions(+), 8 deletions(-) rename apps/frontend/src/features/games/survival/components/{survival-hud.tsx => hud.tsx} (93%) diff --git a/apps/frontend/src/features/games/falling-words/components/field.tsx b/apps/frontend/src/features/games/falling-words/components/field.tsx index 606f9c5..9cf1857 100644 --- a/apps/frontend/src/features/games/falling-words/components/field.tsx +++ b/apps/frontend/src/features/games/falling-words/components/field.tsx @@ -15,7 +15,7 @@ type FieldProps = { onFieldClick: () => void; }; -function Field(props: FieldProps) { +export function Field(props: FieldProps) { return (
); } - -export default Field; diff --git a/apps/frontend/src/features/games/falling-words/components/hud.tsx b/apps/frontend/src/features/games/falling-words/components/hud.tsx index 7e12820..538f728 100644 --- a/apps/frontend/src/features/games/falling-words/components/hud.tsx +++ b/apps/frontend/src/features/games/falling-words/components/hud.tsx @@ -1,6 +1,6 @@ import { GameStat } from "../../core/components/game-stat"; -export type HudProps = { +type HudProps = { score: number; typedValue: string; }; diff --git a/apps/frontend/src/features/games/falling-words/view.tsx b/apps/frontend/src/features/games/falling-words/view.tsx index f34df99..0819ee4 100644 --- a/apps/frontend/src/features/games/falling-words/view.tsx +++ b/apps/frontend/src/features/games/falling-words/view.tsx @@ -4,7 +4,7 @@ import type { GameViewProps } from "../core/types"; import { useSubmitGameResult } from "../core/hooks"; import { DifficultySelector } from "../core/components/difficulty-selector"; import { GameMeta } from "../core/components/game-meta"; -import Field from "./components/field"; +import { Field } from "./components/field"; import { Hud } from "./components/hud"; import { useEngine } from "./engine"; import { meta } from "./meta"; diff --git a/apps/frontend/src/features/games/survival/components/survival-hud.tsx b/apps/frontend/src/features/games/survival/components/hud.tsx similarity index 93% rename from apps/frontend/src/features/games/survival/components/survival-hud.tsx rename to apps/frontend/src/features/games/survival/components/hud.tsx index 15ceba3..f9565de 100644 --- a/apps/frontend/src/features/games/survival/components/survival-hud.tsx +++ b/apps/frontend/src/features/games/survival/components/hud.tsx @@ -2,7 +2,7 @@ import { Index } from "solid-js"; import { Heart } from "./heart"; import { GameStat } from "../../core/components/game-stat"; -export type SurvivalHudProps = { +type HudProps = { health: number; score: number; wpm: number; @@ -10,7 +10,7 @@ export type SurvivalHudProps = { isTakingDamage?: boolean; }; -export function SurvivalHud(props: SurvivalHudProps) { +export function Hud(props: HudProps) { return (
diff --git a/apps/frontend/src/features/games/survival/view.tsx b/apps/frontend/src/features/games/survival/view.tsx index b3cea16..fc44fb6 100644 --- a/apps/frontend/src/features/games/survival/view.tsx +++ b/apps/frontend/src/features/games/survival/view.tsx @@ -8,7 +8,7 @@ import { GameInput } from "../core/components/game-input"; import { GameMeta } from "../core/components/game-meta"; import { meta } from "./meta"; import { useEngine } from "./engine"; -import { SurvivalHud as Hud } from "./components/survival-hud"; +import { Hud } from "./components/hud"; import { Words } from "./components/words"; import "./animations.css"; From 97ae30a36f37ed1384e0597a00adfe0a982459df Mon Sep 17 00:00:00 2001 From: d1rshan Date: Sun, 31 May 2026 10:34:09 +0530 Subject: [PATCH 6/9] game id --- apps/frontend/src/features/games/falling-words/engine.ts | 4 ++-- apps/frontend/src/features/games/survival/engine.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/frontend/src/features/games/falling-words/engine.ts b/apps/frontend/src/features/games/falling-words/engine.ts index c330c20..7d8239d 100644 --- a/apps/frontend/src/features/games/falling-words/engine.ts +++ b/apps/frontend/src/features/games/falling-words/engine.ts @@ -9,7 +9,7 @@ import { import { getWordBank } from "@/features/content/word-banks/manager"; import type { WordBankId } from "@/features/content/word-banks/types"; -import type { DifficultyKey, GamePhase } from "../core/types"; +import type { DifficultyKey, GameId, GamePhase } from "../core/types"; import type { DifficultyConfig, FallingWord } from "./types"; const difficultyConfigs: Record = { @@ -22,7 +22,7 @@ const rand = (min: number, max: number) => Math.random() * (max - min) + min; export type UseGameOptions = { onComplete?: (result: { - gameId: "falling-words"; + gameId: GameId; score: number; difficulty: DifficultyKey; }) => void | Promise; diff --git a/apps/frontend/src/features/games/survival/engine.ts b/apps/frontend/src/features/games/survival/engine.ts index 36c1c07..ca8b956 100644 --- a/apps/frontend/src/features/games/survival/engine.ts +++ b/apps/frontend/src/features/games/survival/engine.ts @@ -4,7 +4,7 @@ import { createStore } from "solid-js/store"; import { getWordBank } from "@/features/content/word-banks/manager"; import type { WordBankId } from "@/features/content/word-banks/types"; -import type { DifficultyKey, GamePhase } from "../core/types"; +import type { DifficultyKey, GameId, GamePhase } from "../core/types"; import { getMetrics } from "../core/metrics"; import { randomWord } from "../core/utils"; @@ -21,7 +21,7 @@ const DAMAGE: Record = { export type UseGameOptions = { onComplete?: (result: { - gameId: string; + gameId: GameId; score: number; difficulty: DifficultyKey; }) => void; From 62aec6e1931e34f90b795d8acaa68bec36245970 Mon Sep 17 00:00:00 2001 From: d1rshan Date: Sun, 31 May 2026 10:35:55 +0530 Subject: [PATCH 7/9] game overlay --- .../games/falling-words/components/field.tsx | 15 --------------- .../src/features/games/falling-words/view.tsx | 6 +++++- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/apps/frontend/src/features/games/falling-words/components/field.tsx b/apps/frontend/src/features/games/falling-words/components/field.tsx index 9cf1857..4fc8cd5 100644 --- a/apps/frontend/src/features/games/falling-words/components/field.tsx +++ b/apps/frontend/src/features/games/falling-words/components/field.tsx @@ -11,7 +11,6 @@ type FieldProps = { currentInput: string; focusedWordId: number | null; phase: GamePhase; - score: number; onFieldClick: () => void; }; @@ -31,20 +30,6 @@ export function Field(props: FieldProps) {
)} - {props.phase === "game-over" && ( -
-
-

- {props.score} -

-
- enter -

to restart

-
-
-
- )} - {props.words.map((word) => { const isFocused = word.id === props.focusedWordId; const isPrefixMatch = diff --git a/apps/frontend/src/features/games/falling-words/view.tsx b/apps/frontend/src/features/games/falling-words/view.tsx index 0819ee4..faa0b4c 100644 --- a/apps/frontend/src/features/games/falling-words/view.tsx +++ b/apps/frontend/src/features/games/falling-words/view.tsx @@ -4,6 +4,7 @@ import type { GameViewProps } from "../core/types"; import { useSubmitGameResult } from "../core/hooks"; import { DifficultySelector } from "../core/components/difficulty-selector"; import { GameMeta } from "../core/components/game-meta"; +import { GameOver } from "../core/components/game-over"; import { Field } from "./components/field"; import { Hud } from "./components/hud"; import { useEngine } from "./engine"; @@ -33,13 +34,16 @@ function View(props: GameViewProps) {
+ + + + From a81e29eeaae8a0635fcfdc5bb0e9d19d89b28ade Mon Sep 17 00:00:00 2001 From: d1rshan Date: Sun, 31 May 2026 10:43:06 +0530 Subject: [PATCH 8/9] fix --- apps/frontend/src/features/content/word-banks/manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/features/content/word-banks/manager.ts b/apps/frontend/src/features/content/word-banks/manager.ts index 5a9a084..693354e 100644 --- a/apps/frontend/src/features/content/word-banks/manager.ts +++ b/apps/frontend/src/features/content/word-banks/manager.ts @@ -2,5 +2,5 @@ import { wordBanks } from "@/features/content/word-banks/registry"; import type { WordBankId } from "@/features/content/word-banks/types"; export function getWordBank(wordBankId: WordBankId) { - return wordBanks[wordBankId] ?? null; + return wordBanks[wordBankId]; } From a7e25188d9db8ab80ca9a572e339271445aeb9b2 Mon Sep 17 00:00:00 2001 From: d1rshan Date: Sun, 31 May 2026 10:45:12 +0530 Subject: [PATCH 9/9] void --- apps/frontend/src/features/games/falling-words/engine.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/features/games/falling-words/engine.ts b/apps/frontend/src/features/games/falling-words/engine.ts index 7d8239d..6b3110d 100644 --- a/apps/frontend/src/features/games/falling-words/engine.ts +++ b/apps/frontend/src/features/games/falling-words/engine.ts @@ -25,7 +25,7 @@ export type UseGameOptions = { gameId: GameId; score: number; difficulty: DifficultyKey; - }) => void | Promise; + }) => void; }; function createFallingWord( @@ -205,7 +205,7 @@ export function useEngine( setPhase("game-over"); stopLoop(); setElapsedMs(finalElapsedMs); - void options.onComplete?.({ + options.onComplete?.({ gameId: "falling-words", score: finalScore, difficulty: difficulty(),