/game-debug [profile|game|stats|all]
Inspect and explain CrossQuest game state data structures.
Arguments
- •
profile— Explain UserProfile structure and localStorage key - •
game— Explain SavedGameState structure and auto-save mechanics - •
stats— Explain UserStats, scoring formula, and level calculation - •
all(default) — Show all of the above
Instructions
For profile:
Explain the UserProfile interface from /types.ts:
code
localStorage key: "umnyaut_profile"
UserProfile {
username: string — Display name
selectedCategories: string[] — Chosen crossword categories
stats: UserStats — Points, level, streak, etc.
history: GameHistoryEntry[] — Completed games log
solvedCrosswordIds: string[] — IDs of completed crosswords (dedup)
themeProgress: ThemeProgress — Per-category word progress
avatar?: string — Avatar identifier
defaultDifficulty?: string — "easy" | "medium" | "hard"
soundEnabled?: boolean — Sound effects toggle
createdAt?: string — ISO date of profile creation
}
Note the migration logic in AppContext.tsx:
- •
solvedCrosswordIdsdefaults to[]if missing - •
themeProgressdefaults to{}if missing - •
categoriesrenamed toselectedCategories - •
soundEnableddefaults totrue - •
defaultDifficultydefaults to"medium" - •
createdAtset to current date if missing
For game:
Explain the SavedGameState interface:
code
localStorage key: "umnyaut_current_game_state" (SAVED_GAME_KEY)
SavedGameState {
crosswordData: CrosswordData — Full crossword (grid, words, clues)
userGrid: string[][] — Player's current letter input
timer: number — Elapsed seconds
wordPenalties: [number, {hint: boolean, letters: boolean}][]
— Serialized Map of hint usage per word index
savedAt: string — ISO timestamp of last save
}
Key points:
- •
wordPenaltiesis aMap<number, {...}>at runtime, serialized as array of tuples - •
userGridmirrorscrosswordData.griddimensions, empty cells are"" - •Auto-save triggers on state changes during gameplay
- •Cleared from localStorage on game completion
For stats:
Explain UserStats and scoring:
code
UserStats {
points: number — Total accumulated points
level: number — Calculated level (see formula)
streak: number — Consecutive days played
lastPlayed: string — ISO date of last game
totalSolved: number — Total crosswords completed
averageTime?: number — Average completion time in seconds
perfectGames?: number — Games completed without any hints
maxStreak?: number — Highest streak ever achieved
streakMilestones?: number[] — Celebrated milestone values
}
Scoring formula:
code
finalScore = baseScore × (1 - penaltyPercent) × speedBonus × accuracyBonus Minimum: 50 points
Level formula:
code
baseLevel = floor(points / 500) speedFactor = min(1.2, max(1, 300/averageTime)) accuracyFactor = 1 + (perfectGames/totalSolved × 0.3) level = max(1, floor(baseLevel × speedFactor × accuracyFactor))
Streak milestones: 7, 30, 100, 365 days
Common Issues to Watch For
- •Corrupted profile — JSON parse fails in AppContext, profile becomes null
- •Missing migration fields — Old profiles missing
solvedCrosswordIds,themeProgress, etc. - •wordPenalties deserialization — Must convert
[key, value][]back toMap - •Stale saved game —
savedAttoo old, crossword data may not match current API - •NaN in stats — Division by zero in level calc when
totalSolvedis 0