# CLAUDE Wrdler v0.2.12 # Wrdler - Project Context ## Project Overview Wrdler is a simplified vocabulary puzzle game based on BattleWords: - **Python project** (Streamlit, Python 3.12.8) - **8x6 grid** (8 columns × 6 rows, one word per row, horizontal only) - **No scope/radar visualization** - **2 free letter guesses at game start** (all instances revealed) - **Word composition:** 2 four-letter, 2 five-letter, 2 six-letter words per puzzle **Current Version:** 0.2.12 **Last Updated:** 2025-12-21 **Repository:** https://github.com/Oncorporation/Wrdler.git **Branch:** main ## Recent Changes (v0.2.12) - Layout changes for improved usability - Fixed static spinner graphic and favicon - Background enable/disable toggles improved - Sidebar disabled for streamlined UI - Minor grid layout tightening - Added a couple words to classic.txt - HF server fix - Documentation updates ## Current Features (v0.2.12) ### Core Gameplay - 8x6 grid with 6 hidden words (one per row, horizontal only) - Players choose 2 free letters at start; all instances are revealed - Click cells to reveal letters or empty spaces - Guess words for points (word length + bonus for unrevealed letters) - Game ends when all words guessed or all word letters are revealed - Incorrect guess history display (toggleable, default enabled) - 10 incorrect guess limit per game - **All leaderboard and challenge submissions use the latest st.session_state, including challenge overrides.** ### Game Modes 1. **Classic Mode:** Allows consecutive guessing after correct answers 2. **Too Easy Mode:** Single guess per reveal ### Scoring Tiers - **Legendary:** 45+ points - **Fantastic:** 42-44 points - **Great:** 39-41 points - **Good:** 35-38 points - **Keep practicing:** < 35 points ### Settings Page & Management - All game settings moved from sidebar to a dedicated Settings page (`?page=settings`) - Accessible via footer navigation (`⚙️ Settings` link) - Local JSON-based settings persistence in `wrdler/settings/` - Latest settings auto-loaded on startup - Enhanced settings management: create, update, rename, and delete settings files - Split "Save Settings" into "Create Settings" and "Update Settings" actions - Improved settings loading and user feedback - Default sound effects enabled in settings - New default configuration: `classic-classic-full_sound_free_letters.json` - Deprecated configuration removed: `classic-classic-2.json` ### Word List Management - Sort and filter word lists (filter using `assets/filter.txt` blocklist) - Dialog display of removed words after filtering ### Challenge Mode & Remote Storage - Short URL-based challenge sharing via `?game_id=` - Each player gets different random words from same wordlist - Multi-user challenge leaderboards (top 5 display) - Remote storage via HuggingFace datasets - Word list difficulty calculation - "Show Challenge Share Links" toggle (default OFF) - **Integration:** - Automatic submission after game completion (opt-in via game over popup) - Challenge scores also contribute to daily/weekly leaderboards - Source tracking via `source_challenge_id` field - Unified JSON format with `entry_type` field (daily/weekly/challenge) - **Challenge settings override defaults on load, and all submissions use the current session state.** **Access:** 'Leaderboard' link in the footer navigation at the bottom of the page ### Daily & Weekly Leaderboards - **Settings-Based Separation:** Each unique settings combo creates separate leaderboard - Settings: `game_mode`, `wordlist_source`, `show_incorrect_guesses`, `enable_free_letters`, `puzzle_options` (spacer, may_overlap) - **Auto Score Submission:** Checks qualification for top 25 after game completion - **Storage:** Folder-based discovery at `games/leaderboards/{daily|weekly}/{period}/{file_id}/settings.json` - **File ID Format:** `{wordlist_source}-{game_mode}-{sequence}` (e.g., `classic-classic-0`) - **Leaderboard Page:** Four tabs (Today, Daily, Weekly, History) accessible via `?page=today|daily|weekly|history` using query parameter routing and custom navigation links (not Streamlit native tabs) - Leaderboard files use UTC for all period boundaries. - When displaying daily leaderboards, show the UTC period as a PST date range. - Example: For UTC file date 2025-12-08, display: 2025-12-08 00:00:00 UTC to 2025-12-08 23:59:59 UTC and 2025-12-07 16:00:00 PST to 2025-12-08 15:59:59 PST The leaderboard expander label should show: `Mon, Dec 08, 2025 4:00 PM PST – Tue, Dec 09, 2025 3:59:59 PM PST [settings badge]` ### Game Over Dialog & Leaderboard Integration - Game over dialog now integrates leaderboard submission and displays qualification results (rankings) - After submitting your score, the dialog will show if you qualified for the daily or weekly leaderboard and your rank ### AI Word Generation - Topic-based word list generation via HuggingFace Spaces or local transformers - Automatic word saving (max 1000 words per file) - Retry mechanism (up to 3 attempts) for insufficient word counts - Fallback to dictionary words if AI unavailable ### Audio & Visuals - Ocean-themed gradient background with wave animations - Toggleable background music with volume control (configured via Settings page, played globally) - Sound effects (hit/miss/correct/incorrect) with volume control (configured via Settings page, enabled by default) ### PWA Support - Installable as Progressive Web App on desktop and mobile - Service worker for offline caching of static assets - Works offline for basic functionality ### Footer Navigation - Navigation links to Leaderboard, Play, and Settings pages are in the footer (not the sidebar) - Footer navigation prevents reloading active pages ## Technical Architecture ### Technology Stack - **Framework:** Streamlit 1.52.1 - **Language:** Python 3.12.8 (requires >=3.12, <3.13) - **Remote Storage:** huggingface_hub (>=0.20.0) - **AI Generation:** transformers, gradio_client - **Testing:** Pytest - **Package Manager:** UV or pip ### Project Structure ``` wrdler/ ├── app.py # Streamlit entry point ├── wrdler/ # Main package │ ├── __init__.py # Version: 0.2.10 │ ├── models.py # Data models (Coord, Word, Puzzle, GameState) │ ├── generator.py # Puzzle generation with deterministic seeding │ ├── logic.py # Game mechanics (reveal, guess, scoring) │ ├── ui.py # Streamlit UI with query param routing │ ├── oauth.py # HuggingFace OAuth utilities │ ├── settings_page.py # Settings page UI (enhanced) │ ├── leaderboard.py # Leaderboard system (daily/weekly) │ ├── leaderboard_page.py # Leaderboard UI page │ ├── word_loader.py # Word list management │ ├── word_loader_ai.py # AI word generation │ ├── game_storage.py # HF game storage wrapper │ ├── version_info.py # Version display │ ├── modules/ # Shared utility modules │ │ ├── __init__.py # Module exports │ │ ├── storage.py # HuggingFace storage & URL shortener │ │ ├── storage.md # Storage module documentation │ │ ├── constants.py # Storage-related constants │ │ └── file_utils.py # File utility functions │ └── words/ # Word list files │ ├── classic.txt # Default word list │ ├── fourth_grade.txt # Elementary word list ├── tests/ # Unit tests ├── specs/ # Documentation ├── static/ # PWA assets (manifest.json, service-worker.js) ├── .env # Environment variables (HF credentials) ├── pyproject.toml # Project metadata ├── requirements.txt # Dependencies ├── uv.lock # UV lock file ├── Dockerfile # Container deployment ├── README.md # User-facing documentation ├── CLAUDE.md # This file - project context for Claude ├── GAMEPLAY_GUIDE.md # User guide with tips and strategies ``` ### Page Navigation System Uses **query parameter-based routing** (NOT Streamlit multi-page): - `?page=today|daily|weekly|history` → Leaderboard pages - `?page=settings` → Settings page - `?game_id=` → Challenge mode - No query params → Main game page ## Data Models ### Core Classes ```python @dataclass class Coord: x: int # row, 0-based y: int # col, 0-based @dataclass class Word: text: str start: Coord direction: Direction # "H" or "V" cells: List[Coord] @dataclass class Puzzle: words: List[Word] may_overlap: bool spacer: int uid: str # Unique identifier @dataclass class GameState: grid_rows: int # 6 for Wrdler grid_cols: int # 8 for Wrdler puzzle: Puzzle revealed: Set[Coord] guessed: Set[str] score: int last_action: str can_guess: bool game_mode: str points_by_word: Dict[str, int] start_time: Optional[datetime] end_time: Optional[datetime] ``` ## Environment Variables Create a `.env` file in the project root: ```bash # Challenge Mode & Leaderboards (Remote Storage) HF_API_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxx # HuggingFace API token with write access HF_REPO_ID=YourUsername/YourRepo # Dataset repo for challenge storage # AI Word Generation USE_HF_WORDS=false # Enable HF Space API for word generation HF_WORD_LIST_REPO_ID=YourUsername/WordRepo # Dataset repo for AI word lists # OAuth Admin Access ADMIN_USERS=username1,username2 # Comma-separated list of admin usernames MAX_DISPLAY_ENTRIES=25 # Max leaderboard entries to display (default: 25) ``` ### HF_REPO_ID Structure ``` HF_REPO_ID/ ├── shortener.json # URL shortener mappings ├── games/{uid}/settings.json # Challenge data (entry_type: "challenge") └── games/leaderboards/ ├── daily/{YYYY-MM-DD}/{file_id}/settings.json # Daily leaderboards └── weekly/{YYYY-Www}/{file_id}/settings.json # Weekly leaderboards ``` ## Development Workflow ### Running Locally ```bash # Install dependencies uv pip install -r requirements.txt --link-mode=copy # Run app streamlit run app.py ``` ### Testing ```bash pytest tests/ ``` ## OAuth-Protected Settings Page - Settings page at `?page=settings`, protected by HuggingFace OAuth (admin-only access) - Uses query parameter routing and checks admin access via `ADMIN_USERS` env var ## Technical Notes - **8×6 grid:** `grid_rows=6`, `grid_cols=8` - **Horizontal-only placement:** One word per row - **Query param routing:** All pages use `?page=` system - **Session state management:** Heavy use of `st.session_state` - **All leaderboard and challenge submissions use the latest st.session_state, including challenge overrides.** ## Deployment Platforms 1. **HuggingFace Spaces** (Primary) - Dockerfile deployment with OAuth support 2. **Local Development** - Streamlit run 3. **Docker** - Containerized deployment ## Git Configuration - **Current Branch:** AI (working branch) - **Main Branch:** main - **Remotes:** - origin: https://github.com/Oncorporation/Wrdler.git - Hugging: https://huggingface.co/spaces/Surn/Wrdler