diff --git a/README.md b/README.md index de46099..f56057a 100644 --- a/README.md +++ b/README.md @@ -1,185 +1,99 @@ # Fertig Classic Games -A Phaser 3.90 collection of classic tabletop games (Backgammon, Parchisi, ...) -and casino games (Blackjack, Texas Hold 'Em, ...). Games are single-player -against AI opponents. +A single-page collection of **77 classic games** — board games, card games, +casino games, word games, and logic puzzles — all playable in the browser +against local AI opponents. Built on [Phaser 3.90](https://phaser.io/). -**This is a fully static site — no server, no database, no accounts, no npm -needed to run it.** The frontend uses native browser ES modules (no bundler, -no build step) and loads Phaser from a CDN. All per-player data (a single local -profile, chips, match history, puzzle progress) lives in the browser's -`localStorage`. Word-game dictionaries and AI run client-side from the ported -engines in `src/words/`. - -## Running / deployment - -The repository root **is** the site. Serve it as static files from any web -server, at the domain root **or any subdirectory** (e.g. `example.com/games/`). -All asset paths are relative and anchored by ``, so no -configuration is needed. The only runtime files are `index.html`, `styles.css`, -and the `assets/`, `data/`, and `src/` directories. - -To deploy into a parent site, copy those into the desired subdirectory: - -``` -cp -r index.html styles.css *.png favicon.ico assets data src /var/www/parent-site/games/ -``` - -For local testing: - -``` -npm run serve # python3 -m http.server on http://localhost:8000 -``` - -The `tools/` directory holds offline dev tooling — puzzle generators and -`verify*` self-play scripts — run with plain `node` from the repo root -(e.g. `node tools/verifyBookwork.js`). It is not part of the deployed site. +**This is a fully static site.** There is no server, no database, no accounts, +no build step, and no `npm install` required to run it. The frontend uses native +browser ES modules and loads Phaser from a CDN. Everything that used to be a +backend round-trip — the single local player profile, casino chip balance, match +history, puzzle progress, and word-game dictionaries/AI — now runs entirely in +the browser against `localStorage` and the ported engines in `src/words/`. --- ## Table of contents -- [Features](#features) -- [Prerequisites](#prerequisites) - [Quick start](#quick-start) -- [Configuration (`.env`)](#configuration-env) -- [Running the server](#running-the-server) +- [Deployment / hosting](#deployment--hosting) +- [The game catalog](#the-game-catalog) - [Project layout](#project-layout) -- [Database schema](#database-schema) -- [REST API](#rest-api) -- [Frontend architecture](#frontend-architecture) +- [Architecture](#architecture) + - [Scene flow](#scene-flow) + - [The local "backend"](#the-local-backend) + - [Word games](#word-games) + - [Assets](#assets) - [Adding a new game](#adding-a-new-game) -- [Email verification](#email-verification) -- [Profile pictures](#profile-pictures) -- [Troubleshooting](#troubleshooting) -- [Roadmap](#roadmap) - ---- - -## Features - -- Account creation with email + username + password (bcrypt hashed) -- Email verification with configurable SMTP — falls back to logging dev links - to the console when SMTP is not set up -- Session cookies backed by SQLite (httpOnly, SameSite=Lax) -- Profile management: display name, bio, avatar upload (PNG / JPEG / WebP) -- Match history (wins / losses / draws) recorded for single-player games -- Pluggable game registry — register tabletop or casino games server-side -- Single-player games against configurable AI opponents -- 1920×1080 canvas that scales to any viewport via `Phaser.Scale.FIT` -- Vector-only placeholder graphics — drop sprites in later without - refactoring scenes -- Mouse + keyboard controls - ---- - -## Prerequisites - -- **Node.js 20 or newer** (uses `node --watch`, native fetch, ES modules) -- **npm 9 or newer** -- A C/C++ toolchain for `better-sqlite3` and `bcrypt` to build native bindings: - - **Linux**: `build-essential`, `python3` - - **macOS**: Xcode command line tools (`xcode-select --install`) - - **Windows**: install **Visual Studio Build Tools 2022** with the - "Desktop development with C++" workload and **Python 3.x** (add to PATH). - Do **not** use the deprecated `windows-build-tools` npm package — it is - broken on modern Node.js. See [Troubleshooting](#troubleshooting) for - step-by-step instructions. - -No bundler, no Docker, no external database required to get started. +- [Developer tooling (`tools/`)](#developer-tooling-tools) +- [Data files (`data/`)](#data-files-data) --- ## Quick start +No dependencies to install. You just need a static file server, because ES +modules can't be loaded over `file://`. + ```bash git clone cd fertig-classic-games -cp example.env .env -# Edit .env — at minimum, set SESSION_SECRET to a long random string. -# Generate one with: -# node -e "console.log(require('crypto').randomBytes(48).toString('hex'))" - -npm install -npm run migrate -npm run dev +# Any static server works. A couple of one-liners: +npm run serve # python3 -m http.server 8000 → http://localhost:8000 +./start_web.sh # python3 -m http.server 3000 → http://localhost:3000 +npx serve . # if you prefer Node ``` -Open http://localhost:3000 in your browser. Register an account; if SMTP is -not configured (the default), the verification link is printed to the server -console — click it to verify. +Then open the printed URL in a modern browser. That's it — pick a game and play. + +> **Requirements:** a current browser with ES-module + importmap support +> (Chrome/Edge/Firefox/Safari, ~2023+). Python 3 (or any static server) for local +> hosting. Node.js 20+ is only needed for the optional dev tooling in `tools/`. --- -## Configuration (`.env`) +## Deployment / hosting -All configuration lives in `.env` at the project root. Use `example.env` as -the template. Fields: +**The repository root _is_ the site.** Serve it as static files from any web +host, CDN, or object store (GitHub Pages, Netlify, Cloudflare Pages, S3, nginx, +Apache, …). No configuration, environment variables, or runtime are needed. -### Server - -| Variable | Default | Description | -|-------------|--------------------------|------------------------------------------| -| `NODE_ENV` | `development` | `development` or `production`. | -| `HOST` | `0.0.0.0` | Bind address. | -| `PORT` | `3000` | HTTP port. | -| `BASE_URL` | `http://localhost:3000` | Public URL used in verification emails. | -| `LOG_LEVEL` | `info` | `error`, `warn`, `info`, `debug`. | - -### Database - -| Variable | Default | Description | -|-----------|-------------------------|-----------------------------------| -| `DB_PATH` | `./data/fertig.sqlite` | SQLite file path. Auto-created. | - -### Auth - -| Variable | Default | Description | -|------------------------|---------------|--------------------------------------------------------------------------------------------------------------| -| `SESSION_SECRET` | *(required)* | Long random string. **Required in production.** A dev fallback is used if empty in development with a warning. | -| `SESSION_COOKIE_NAME` | `fcg_sid` | Cookie name. | -| `SESSION_TTL_DAYS` | `30` | Session lifetime in days. | -| `BCRYPT_ROUNDS` | `12` | bcrypt cost factor. | - -### Uploads (profile pictures) - -| Variable | Default | Description | -|------------------------|--------------------------------------|--------------------------------------| -| `UPLOAD_DIR` | `./public/uploads` | Directory for avatar files. | -| `MAX_UPLOAD_SIZE_MB` | `5` | Max image size in MB. | -| `ALLOWED_UPLOAD_MIME` | `image/png,image/jpeg,image/webp` | Comma-separated MIME allowlist. | - -### Email - -| Variable | Default | Description | -|---------------------------------|---------|------------------------------------------------------------------------| -| `SMTP_HOST` | *(empty)* | If empty, verification links log to the console instead of sending. | -| `SMTP_PORT` | `587` | SMTP port. | -| `SMTP_SECURE` | `false` | `true` for SMTPS (usually port 465). | -| `SMTP_USER` | *(empty)* | SMTP username, if your provider requires auth. | -| `SMTP_PASS` | *(empty)* | SMTP password. | -| `SMTP_FROM` | *(see example.env)* | `From:` header for outgoing mail. | -| `VERIFICATION_TOKEN_TTL_HOURS` | `24` | How long verification links remain valid. | - ---- - -## Running the server +Because every asset path is relative and `index.html` sets ``, +the site works unchanged from a domain root **or any subdirectory** +(e.g. `example.com/games/`). To drop it into an existing site: ```bash -npm run dev # node --watch, auto-restart on file changes -npm start # plain node, production-style -npm run migrate # apply any pending DB migrations +cp -r index.html styles.css *.png favicon.ico assets data src \ + /var/www/parent-site/games/ ``` -The server serves both the API (`/api/*`) and the static frontend (`/`, -`/src/...`, `/uploads/...`) on the same port. +The only files the deployed site needs are `index.html`, `styles.css`, the +favicons/PWA icons in the root, and the `assets/`, `data/`, and `src/` +directories. The `tools/` directory is dev-only and never shipped. -After it starts you should see: +Player state (profile, chips, history, puzzle progress) lives in each visitor's +own browser `localStorage` under the `fcg:` prefix — nothing is stored or synced +server-side, so hosting is entirely stateless. -``` -[server] listening on http://0.0.0.0:3000 -``` +--- + +## The game catalog + +77 games are registered in `src/data/gamesRegistry.js` and grouped into five +menu categories: + +| Category | Count | Examples | +|----------|-------|----------| +| **Tabletop** | 21 | Backgammon, Chess, Checkers, Go, Othello, Settlers of Catan, Ticket to Ride, Risk, Monopoly, Blokus, Labyrinth, Mahjong, Stratego, Battleship, Mastermind, Connect 4, Forbidden Island, Azul, Chinese Checkers, Mexican Train, Parchisi | +| **Cards** | 18 | Cribbage, Gin Rummy, Rummikub, Canasta, Hearts, Uno, Phase 10, Skip-Bo, Go Fish, Old Maid, Nerts, Dominion, Splendor, Freecell, Solitaire Tour, Spire Climb, Zahtzee, Farkle | +| **Casino** | 9 | Blackjack, Texas Hold 'Em, Baccarat, Pai Gow Poker, Video Poker, Craps, Roulette, Bingo, Slot Machines | +| **Word** | 15 | Wordle Race, Scrabble, Boggle, Ghost, Word Ladder, Word Search, Hangman, Spelling Bee, Sudoku, Mini Crossword, Tectonic, Bookwork, Kiitos, Tri-Ominoes, Jumble | +| **Logic & Puzzle** | 14 | 2048, Rush Hour, Hexsweeper, Jell-o Monsters, Shift, Mahjong Match, Jewel Quest, Zuma, Bejeweled Blitz, Mini Motorways, Dot Link, Katamino, Genius Square, Block Fighter | + +Each game is a self-contained `Phaser.Scene` (plus its own logic/AI/data helper +modules) under `src/games//`. Games are single-player against 0–7 +configurable AI opponents depending on the title; several ship a video tutorial. --- @@ -187,291 +101,189 @@ After it starts you should see: ``` fertig-classic-games/ -├── example.env Configuration template (commit this) -├── .env Your local configuration (gitignored) -├── package.json -├── README.md +├── index.html Entry point: importmap for Phaser + +├── styles.css Page chrome (canvas container + DOM overlay layer) +├── package.json "serve" script; no runtime deps +├── start_web.sh Convenience local server (python http.server) +├── favicon*/apple-touch/… Favicons and PWA icons │ -├── server/ Backend (Node.js, ES modules) -│ ├── index.js Express bootstrap -│ ├── config.js Loads & validates .env -│ ├── db/ -│ │ ├── index.js better-sqlite3 connection singleton -│ │ ├── migrate.js SQL migration runner -│ │ └── migrations/ -│ │ └── 001_init.sql Initial schema -│ ├── auth/ -│ │ ├── routes.js /api/auth/* endpoints -│ │ ├── service.js bcrypt, sessions, verification tokens -│ │ └── middleware.js loadUser, requireAuth -│ ├── profile/ -│ │ ├── routes.js /api/profile/*, multer upload -│ │ └── service.js -│ ├── history/ -│ │ └── routes.js /api/history -│ ├── email/ -│ │ └── mailer.js Nodemailer wrapper with console fallback -│ └── games/ -│ └── registry.js Game definitions +├── src/ The entire application (native ES modules) +│ ├── main.js Phaser.Game config; registers every scene; DOM-overlay sync +│ ├── config.js Canvas dimensions (1920×1080) and the UI color palette +│ ├── data/ +│ │ └── gamesRegistry.js The catalog: registerGame() for all 77 games +│ ├── scenes/ Shell scenes (menu, profile, opponent select, room) +│ ├── services/ api.js → localApi.js → localStore.js (the local backend) +│ ├── ui/ Reusable widgets: Button, Modal, TextInput, Portrait, +│ │ music/speech/tutorial/fullscreen helpers +│ ├── words/ Client-side word-game engines + wordRouter dispatcher +│ └── games// One folder per game (Scene + Logic + AI + Data + tutorial.md) │ -├── public/ Frontend, served as static files -│ ├── index.html Loads Phaser via importmap -│ ├── styles.css -│ ├── uploads/ Avatars (gitignored) -│ └── src/ -│ ├── main.js Phaser.Game + scale config -│ ├── config.js UI colors, dimensions, API base -│ ├── services/ -│ │ ├── api.js fetch wrapper -│ │ └── auth.js Client-side auth store -│ ├── ui/ -│ │ ├── Button.js -│ │ ├── TextInput.js DOM-overlay input that follows canvas scale -│ │ └── Modal.js -│ ├── scenes/ -│ │ ├── BootScene.js -│ │ ├── PreloadScene.js -│ │ ├── LandingScene.js -│ │ ├── LoginScene.js -│ │ ├── RegisterScene.js -│ │ ├── VerifyScene.js -│ │ ├── ProfileScene.js -│ │ ├── GameMenuScene.js -│ │ ├── OpponentSelectScene.js -│ │ └── GameRoomScene.js -│ └── games/ One subdirectory per game (uno/, blackjack/, ...) +├── data/ Static JSON game data + word lists (fetched at runtime) +│ ├── *.json Per-game level banks, artwork maps, opponents, music, etc. +│ ├── crosswords/ Mini-crossword puzzle bank +│ └── wordlists/ enable1.txt (dictionary) + common.txt │ -└── data/ SQLite database (gitignored) - └── fertig.sqlite +├── assets/ Runtime media +│ ├── images/ Spritesheets, backgrounds, board art (81 files) +│ ├── fonts/ Bitmap/web fonts +│ ├── fx/ Sound effects (71 files) +│ ├── music/ Background music tracks (21 files) +│ ├── speech/ AI opponent voice clips (393 files) +│ ├── videos/ In-game portrait/animation clips (90 files) +│ └── tutorial-videos/ How-to-play videos (17 files) +│ +└── tools/ Offline dev scripts (run with node; NOT deployed) + ├── gen*.js Puzzle/level-bank generators + └── verify*.js Headless self-play verification harnesses ``` --- -## Database schema +## Architecture -Created by `server/db/migrations/001_init.sql`. Run `npm run migrate` to apply -any pending migrations. +The frontend is deliberately buildless: `index.html` declares an +`