# Minesweep A modern, web-based Minesweeper game playable directly in the browser at https://minesweep.lol with no install. Features hardware-accelerated rendering, custom-shape minefields (rectangle, diamond, circle, plus, heart), seed-based reproducibility, and URL-shareable boards. ## Game rules Minesweep follows the canonical Minesweeper rules popularized by the Windows version: 1. The minefield is a grid of cells. Some cells contain hidden mines. 2. Click any cell to reveal it. The very first reveal in a game is always safe β€” the mines are placed AFTER your first click, and the 3Γ—3 region surrounding the first-clicked cell is guaranteed mine-free. 3. Revealing a non-mine cell shows a number 1–8 indicating how many mines touch it. Revealing a "0" cell (no adjacent mines) cascades to reveal all connected zero cells and their numbered neighbors. 4. Right-click (desktop) or long-press (touch) places a 🚩 flag on a cell you suspect contains a mine. Repeating the action cycles the marker through 🚩 β†’ ❓ (uncertain) β†’ blank. Question marks do not count as flags for chord arithmetic. 5. Double-tap or middle-click a revealed number to "chord" β€” auto-reveal all unflagged neighbors, but only if the count of adjacent flags matches the number. A wrong flag during a chord can trigger a mine. 6. You win by revealing every non-mine cell. You lose by revealing a mine. ## Differentiators Compared to other browser Minesweeper implementations: - **Custom shapes.** The minefield can be a non-rectangular shape (diamond, circle, plus sign, heart). Out-of-shape cells are inert: no mines, no clicks, no rendering. - **Deterministic seeds.** The mine layout is generated from a 32-bit seed via Mulberry32 PRNG. Same shape + same dimensions + same seed = same board, every time. Seeds can be numeric (used directly) or words (FNV-1a hashed). - **URL hash sharing.** The active game's parameters live in `location.hash`, e.g. `#d=custom&sh=heart&w=20&h=20&m=50&s=42`. Sharing a specific board is just sharing the URL. The hash is updated via `history.replaceState` on every new game. - **Hardware-accelerated pan/zoom.** The board is a single `` element. Pan and zoom apply `canvas.style.transform = translate3d(...) scale(...)` so the GPU composites β€” zero per-frame JS during gestures, 60 fps even on big boards. - **Custom dimensions up to 100Γ—100.** Mines are clamped to leave at least the 3Γ—3 safe region (or just the clicked cell on tiny dense boards). - **Question marks.** Optional XP-style cycle (some implementations omit this). - **OLED-optimized dark mode.** `--bg` and revealed cells are pure `#000` so OLED pixels are off; the hidden-tile gradient is high-contrast against the void. ## Difficulty presets - **Beginner** β€” 9Γ—9 grid, 10 mines (~12% mine density) - **Intermediate** β€” 16Γ—16 grid, 40 mines (~16%) - **Expert** β€” 30Γ—16 grid, 99 mines (~21%) - **Custom** β€” pick any width 5–100, height 5–100, mine count 1 to (widthΒ·heightβˆ’9), and one of the five shapes. ## Controls ### Mouse (desktop) - Left-click hidden cell: reveal (or, if Flag mode is on, place 🚩) - Right-click hidden cell: cycle marker 🚩 β†’ ❓ β†’ blank - Middle-click revealed number: chord - Left-click revealed number: chord (shortcut) - Mouse wheel: zoom (cursor-anchored) - Middle-button drag: pan - Click smiley face: new game - Difficulty dropdown: switch presets, including Custom ### Touch (mobile) - Tap hidden cell: reveal (or place 🚩 if Flag mode is on) - Long-press hidden cell: cycle marker - Double-tap revealed number: chord - Pinch: zoom 0.3×–6Γ— - One-finger drag (when zoomed in): pan - Two-finger drag: pan - "Flag mode" toggle in the floating bottom bar: switches taps from reveal to flag ### Keyboard - Arrow keys: move the focus cursor - Space / Enter: reveal or chord (depending on cell state) - F: cycle marker - C: chord - R: new game - M: toggle Flag mode ## Custom config form When "Custom" is selected from the difficulty dropdown, an inline form appears with: - Shape selector (rect / diamond / circle / plus / heart) - Width input (5–100) - Height input (5–100) - Mine count input (1 to in-shape-cells minus 9) - Seed input (text β€” empty for random; numeric for direct use; words are FNV-1a hashed to a seed) After clicking "Start", the game begins and the URL hash updates with all parameters. ## Sharing a specific game Every game's full configuration is encoded in the URL hash. Examples: - `https://minesweep.lol/#d=expert&s=12345` β€” Expert preset, seed 12345 - `https://minesweep.lol/#d=custom&sh=heart&w=20&h=20&m=50&s=hello` β€” Heart-shaped 20Γ—20 custom with 50 mines, seed derived from "hello" - `https://minesweep.lol/#d=beginner&s=99` β€” Beginner preset, seed 99 Anyone opening the URL plays the same board. Refreshing the page restores the same game. ## Persistence - **Difficulty preference** β€” last-selected preset, restored on reload. - **Best times** β€” fastest completion in seconds, per preset (Custom games don't compete since boards aren't comparable). - **Custom dimensions** β€” last-used custom width/height/mines/shape. - **Flag mode** β€” whether the bottom toggle is on. All of the above lives in `localStorage`. There is no server, no account, no cloud sync. ## Visual design - Two themes: light and dark, switched by `prefers-color-scheme`. - Dark theme is OLED-friendly (pure `#000` background and revealed cells). - Number colors follow the classic Minesweeper palette (1=blue, 2=green, 3=red, 4=navy, 5=maroon, 6=teal, 7=black, 8=gray) in light mode; dark mode uses lightened variants for readability against `#000`. - Cells use a subtle gradient bevel; revealed cells are flat with a thin grid line. - The smiley face button reflects game state: πŸ™‚ idle/playing, 😎 won, 😡 lost. ## Accessibility - `role="application"` on the board with an ARIA label. - Off-screen live region announces game start, win, and loss with the elapsed time. - Reset button is a real `