Added Read Me file
This commit is contained in:
parent
23b43a6f2a
commit
004fc8d033
|
|
@ -0,0 +1,188 @@
|
||||||
|
# iPuzzle
|
||||||
|
|
||||||
|
A browser-based multiplayer jigsaw puzzle game built with [Phaser 3](https://phaser.io/) and vanilla ES6 JavaScript. Pick an image, choose a difficulty, and solve the puzzle solo or with friends in real time — no account required.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **55+ puzzle images** — a curated library of illustrated and photographic artwork, from fantasy landscapes to wildlife
|
||||||
|
- **7 difficulty levels** — 20, 40, 60, 100, 140, 180, or 250 pieces
|
||||||
|
- **Procedurally generated pieces** — interlocking tab/blank connectors generated from a grid so every edge fits its neighbor
|
||||||
|
- **Real-time multiplayer** — create a room and share the 4-character code (or a direct URL) for others to join instantly
|
||||||
|
- **Player color labels** — each player's held piece shows their name tag in a unique color
|
||||||
|
- **Snap detection with glow** — matching edges glow as you bring a piece close; release to lock
|
||||||
|
- **Group movement** — snapped pieces move as a unit
|
||||||
|
- **Pan and zoom** — middle-click drag or right-click drag to pan; scroll wheel to zoom
|
||||||
|
- **Box selection** — click-drag on empty space to grab multiple pieces at once
|
||||||
|
- **Background themes** — Dark Wood or Green Felt table surface
|
||||||
|
- **Puzzle timer** — tracks time from first interaction to completion
|
||||||
|
- **Completion stats** — snap rate chart, corner/edge/quadrant milestones, per-player snap counts
|
||||||
|
- **Background music** — 8 in-game tracks + main menu music with mute toggle
|
||||||
|
- **Session persistence** — progress is saved to `localStorage`; resume an unfinished puzzle from the main menu
|
||||||
|
- **Fullscreen support**
|
||||||
|
- **Responsive canvas** — scales to fit any window size via `Phaser.Scale.FIT`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running the Game
|
||||||
|
|
||||||
|
Because Phaser loads assets over XHR, the game must be served over HTTP (not opened as a `file://` URL).
|
||||||
|
|
||||||
|
### Option A — Node.js server (multiplayer)
|
||||||
|
|
||||||
|
The Node server handles both static file serving and WebSocket multiplayer.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd server
|
||||||
|
npm install
|
||||||
|
node server.js
|
||||||
|
# open http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
Set a custom port with the `PORT` environment variable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PORT=3000 node server.js
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option B — Simple HTTP server (single-player only)
|
||||||
|
|
||||||
|
Any static file server works if you only need single-player:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Python
|
||||||
|
python3 -m http.server 8080
|
||||||
|
|
||||||
|
# Node (npx)
|
||||||
|
npx serve .
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open `http://localhost:8080`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Multiplayer
|
||||||
|
|
||||||
|
1. One player starts a **New Puzzle** — a 4-character room code is generated (e.g. `X4KR`).
|
||||||
|
2. Share the code or the full URL (e.g. `http://your-host:8080/?room=X4KR`).
|
||||||
|
3. Other players click **Join Puzzle** and enter the room code, or open the share URL directly.
|
||||||
|
4. All players see each other's pieces in real time. Piece claiming prevents two players from grabbing the same piece simultaneously.
|
||||||
|
|
||||||
|
Rooms persist on the server for 5 minutes after the last player disconnects, allowing brief reconnections.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
| Action | Input |
|
||||||
|
|---|---|
|
||||||
|
| Pick up / release piece | Left-click |
|
||||||
|
| Pan the board | Middle-click drag or right-click drag |
|
||||||
|
| Zoom | Scroll wheel |
|
||||||
|
| Box-select multiple pieces | Left-click drag on empty space |
|
||||||
|
| Fullscreen | Button on main menu |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
iPuzzle/
|
||||||
|
├── index.html # Entry point; loads all scripts via <script> tags
|
||||||
|
├── server/
|
||||||
|
│ ├── server.js # Node HTTP + WebSocket server
|
||||||
|
│ └── package.json
|
||||||
|
├── js/
|
||||||
|
│ ├── main.js # Phaser game config; registers all scenes
|
||||||
|
│ ├── scenes/
|
||||||
|
│ │ ├── MainMenuScene.js # Animated main menu, join/create room UI
|
||||||
|
│ │ ├── NewPuzzleScene.js # Image picker, difficulty selector
|
||||||
|
│ │ └── PuzzleScene.js # Core gameplay loop
|
||||||
|
│ ├── puzzle/
|
||||||
|
│ │ ├── ConnectorGeometry.js # Tab/blank connector math
|
||||||
|
│ │ ├── PuzzleGenerator.js # Divides image into piece grid
|
||||||
|
│ │ ├── PieceRenderer.js # Draws each piece to a canvas texture
|
||||||
|
│ │ ├── PieceObject.js # Phaser Image wrapper for a piece
|
||||||
|
│ │ ├── GroupManager.js # Tracks which pieces are locked together
|
||||||
|
│ │ ├── SnapDetector.js # Proximity checks and glow segment generation
|
||||||
|
│ │ └── RoomCode.js # 4-character room code generator
|
||||||
|
│ ├── state/
|
||||||
|
│ │ ├── PuzzleState.js # In-memory canonical puzzle state
|
||||||
|
│ │ └── StorageManager.js # localStorage persistence helpers
|
||||||
|
│ └── net/
|
||||||
|
│ └── NetworkManager.js # WebSocket client singleton
|
||||||
|
└── assets/
|
||||||
|
├── puzzles.json # Manifest of available puzzle images
|
||||||
|
├── thumbnails.json # Manifest of thumbnail paths
|
||||||
|
├── images/
|
||||||
|
│ ├── puzzles/ # Full-resolution puzzle images + thumbnails
|
||||||
|
│ └── ui/ # Backgrounds, logo, sub-logo
|
||||||
|
└── audio/
|
||||||
|
├── music/ # main_menu.mp3, track_01–08.mp3, tracks.json
|
||||||
|
└── fx/ # click.mp3, grab.mp3, stats.mp3
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Scenes
|
||||||
|
|
||||||
|
| Scene | Responsibility |
|
||||||
|
|---|---|
|
||||||
|
| `MainMenuScene` | Animated intro, Continue / New Puzzle / Join Puzzle / Fullscreen buttons, join dialog |
|
||||||
|
| `NewPuzzleScene` | Scrollable image gallery with thumbnails, difficulty picker, background picker |
|
||||||
|
| `PuzzleScene` | Piece rendering, interaction, snap/glow, pan/zoom, multiplayer relay, completion stats |
|
||||||
|
|
||||||
|
### Puzzle piece generation
|
||||||
|
|
||||||
|
1. `PuzzleGenerator` divides the chosen image into a `cols × rows` grid.
|
||||||
|
2. `ConnectorGeometry` assigns tab or blank connectors to each shared edge, ensuring that piece A's tab aligns with piece B's blank.
|
||||||
|
3. `PieceRenderer` draws each piece — with its connectors — to an off-screen canvas, then registers it as a Phaser texture.
|
||||||
|
4. `PieceObject` wraps a Phaser `Image` and tracks grid position, group membership, and world coordinates.
|
||||||
|
|
||||||
|
### Snap detection
|
||||||
|
|
||||||
|
Each frame while a piece is held, `SnapDetector.check()` compares every piece in the held group to its grid neighbors. If any neighbor is within `snapRadius` (35% of piece width), the pieces lock together via `GroupManager`. A larger `glowRadius` (140% of piece width) drives the edge-glow preview.
|
||||||
|
|
||||||
|
### Multiplayer protocol (WebSocket)
|
||||||
|
|
||||||
|
| Message | Direction | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `create_room` | client → server | Host sends initial puzzle state |
|
||||||
|
| `room_created` | server → client | Confirms room code and player ID |
|
||||||
|
| `join_room` | client → server | Joiner requests to enter a room |
|
||||||
|
| `room_joined` | server → client | Returns full puzzle state, player list, and existing claims |
|
||||||
|
| `player_joined` / `player_left` | server → all | Presence events |
|
||||||
|
| `claim` | client → server | Request exclusive hold on a piece group |
|
||||||
|
| `claim_ok` / `claim_denied` | server → client | Claim result |
|
||||||
|
| `move` | client → server | Throttled (50 ms) position delta while dragging |
|
||||||
|
| `release` | client → server | Drop with updated positions and merged groups |
|
||||||
|
| `completed` | server → all | Broadcast when all pieces form one group |
|
||||||
|
|
||||||
|
### State persistence
|
||||||
|
|
||||||
|
`StorageManager` serialises the current `PuzzleState` to `localStorage` on every significant event (snap, release). On "Continue Puzzle" the state is restored from storage. All state is keyed by room code to support future multi-room play.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adding New Puzzles
|
||||||
|
|
||||||
|
1. Add a 16:9 PNG or JPG to `assets/images/puzzles/`.
|
||||||
|
2. Create a thumbnail (any size, same basename prefixed with `thumb_`) in the same folder.
|
||||||
|
3. Add an entry to `assets/puzzles.json` and `assets/thumbnails.json`.
|
||||||
|
|
||||||
|
A helper script for bulk thumbnail generation is provided at `assets/images/puzzles/make_thumbnails.sh`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tech Stack
|
||||||
|
|
||||||
|
| Concern | Technology |
|
||||||
|
|---|---|
|
||||||
|
| Game engine | [Phaser 3.90](https://phaser.io/) (CDN) |
|
||||||
|
| Language | Vanilla ES6 (no build step, no npm on the client) |
|
||||||
|
| Multiplayer | WebSocket via the [`ws`](https://github.com/websockets/ws) library |
|
||||||
|
| Server | Node.js (built-in `http` + `ws`) |
|
||||||
|
| Persistence | Browser `localStorage` |
|
||||||
Loading…
Reference in New Issue