---
title: "Mines — ADI Store"
description: "A classic Minesweeper, as one dashboard — three standard difficulties, a guaranteed-safe first click, chording, flags, and a best time per difficulty kept in localStorage."
url: https://withadi.dev/store/game-mines/
---

[All apps](https://withadi.dev/store/)

![](data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'><rect width='48' height='48' rx='10' fill='%23101010'/><rect x='6' y='6' width='16' height='16' rx='3' fill='%231B1B1B'/><rect x='26' y='6' width='16' height='16' rx='3' fill='%23232323'/><rect x='6' y='26' width='16' height='16' rx='3' fill='%23232323'/><rect x='26' y='26' width='16' height='16' rx='3' fill='%23E25C5C'/><rect x='12.5' y='10' width='3' height='12' rx='1' fill='%234A7FD6'/><path d='M31 10v10' stroke='%23E8532A' stroke-width='2' stroke-linecap='round'/><path d='M31 10 L39 13 L31 16 Z' fill='%23E8532A'/><circle cx='34' cy='34' r='5' fill='%232A2A2A'/><line x1='34' y1='25' x2='34' y2='43' stroke='%232A2A2A' stroke-width='2'/><line x1='25' y1='34' x2='43' y2='34' stroke='%232A2A2A' stroke-width='2'/></svg>)

# Mines

`1.0.0`

A classic Minesweeper, as one dashboard — three standard difficulties, a guaranteed-safe first click, chording, flags, and a best time per difficulty kept in localStorage.

game minesweeper mines puzzle

[Install](http://app.adi/marketplace/store/game-mines?install=1)[Download ADI](https://withadi.dev/#download)Opens in your panel, which asks where it goes Free — then this installs in one click

Already have ADI? [Install it from your panel](http://app.adi/marketplace/store/game-mines?install=1).

## What's included

As published. What actually installs is read off the pinned commit's own tree.

- **Dashboards**

  - game-mines — The game itself.

## About

## Mines

A classic Minesweeper, as one dashboard — three standard difficulties, a guaranteed-safe first click, chording, flags, a timer with a best time per difficulty kept in localStorage, and nothing on the backend: every rule lives in the browser.

This bundle carries one element:

| kind | name | what it is |
| --- | --- | --- |
| dashboard | `game-mines` | the game itself — frontend only, a one-route backend stub for the dashboard contract |

Install it:

```
adi-mono marketplace install <marketplace>/game-mines
```

It arrives archived, same as every dashboard — start it from the Dashboards page, or:

```
adi-mono marketplace start <marketplace>/game-mines/dashboards/game-mines
```

Then open it by its hostname. No secret, no project, nothing else to configure.

### Why no backend logic

Mines' entire rulebook — mine placement, flood fill, chording, win/lose detection — runs client-side; there is nothing for a server to compute or to keep private. The backend half of this dashboard exists only because the dashboard contract (`guides/dashboards.md`) needs one: it is the template's own unmodified `backend/index.ts`, answering `/api/health` so the page's status dot has something to poll, and nothing more. No route file was added.

### How it's built

`frontend/modules/game.ts` is the panel; `frontend/modules/.logic.ts` is the whole rulebook — pure functions over a plain grid of booleans and counts, no DOM, no randomness that isn't passed in as an argument. The dot in its name keeps it off the shell's auto-mounted panel list (`guides/dashboards.md`'s module discovery lists every `modules/*.ts` that doesn't start with `.`); the panel reaches it at runtime as a same-origin `./.logic.js` import, which the frontend server resolves straight back to this file.

The rules:

- **first click is always safe**: mines aren't placed until the very first reveal, seeded off

that click — the clicked cell and its whole eight-neighbour ring are excluded from mine placement, so the opening move always clears real space instead of risking a 1x1 island.

- **flood fill**: revealing a cell with zero mine-neighbours cascades outward through every

connected zero cell, stopping at (but still revealing) the first ring of numbered cells around each pocket. A mine is never pushed onto the flood — only an explicit reveal of its own cell can uncover one.

- **chording**: clicking an already-revealed number whose flagged-neighbour count matches its own

value reveals every other neighbour at once — the standard "I trust my flags" shortcut. A mismatched count is a no-op; a wrongly-flagged neighbour that turns out to be a mine still loses, exactly as an ordinary click on it would.

- **win**: every safe cell revealed, independent of whether every mine got flagged. **Lose**:

any mine revealed — the board then reveals every mine and marks any wrongly-placed flag.

Three difficulties, same as the original: Beginner (9×9, 10 mines), Intermediate (16×16, 40 mines), Expert (30×16, 99 mines) — escalating both board size and mine density for a real difficulty curve.

`frontend/modules/game.ts` renders this onto a DOM grid sized off one `--cell-size` CSS variable, recomputed on resize so Expert's 30 columns fit (and scroll, inside `.mines__viewport`) on a 375px phone exactly as they do on a desktop. The same flat palette (the template's own ADI tokens) covers light and dark.

Input: left-click/tap a hidden cell to reveal it, a revealed number to chord it; right-click or a ~450ms long-press (cancelled by a 10px finger move, so a scroll never flags) to flag a hidden cell. Arrow keys move a visible keyboard cursor, Space/Enter reveals or chords it, `F` flags it. Pause blurs the board and stops the clock without resetting it. Best time is `localStorage["adi.gamemines.best.<difficulty>"]`, scoped to the browser, not the backend — there is nothing server-side to lose it with.

### Checking it works

```
bun test test/mines-logic.test.ts
```

14 checks against `frontend/modules/.logic.ts` directly — no DOM, no server: the safe-first-click guarantee (`placeMines`, `reveal`), flood fill cascading and stopping at flags (`reveal`/`floodReveal`), chording on a matched, mismatched, and wrongly-flagged neighbour set (`chord`), and win/lose detection either cell-by-cell or in one cascading click.

A second, optional check covers what the logic tests structurally can't: whether the win/lose overlay is actually invisible when it should be. `.mines__overlay` sets `display: flex` (to centre its card), and an author stylesheet rule always outranks the UA's own `[hidden] { display: none }` at equal specificity — so a missing `.mines__overlay[hidden]` override renders the overlay (and its "New game" button) permanently, over the board, regardless of the `hidden` attribute. Neither `bun:test`'s DOM nor happy-dom compute CSS cascade, so this needs a real browser:

```
bun add -d playwright && bunx playwright install chromium # one-time, not needed to play the game
bun test test/overlay-visibility.test.ts
```

It skips (with a warning, not a failure) if Playwright isn't installed — the dashboard itself has no dependency on it.

### Licence

MIT.

## Where it comes from

Installing clones this repository at this commit. A publisher who pushes something else afterwards changes nothing about what you already read.

- **Repository** — [github.com/adi-family/mp-game-mines](https://github.com/adi-family/mp-game-mines.git)
- **Commit** — `4bdae6ebe51e1aed695450536f5b4d3fdc46c53f`
- **Branch** — `main`
- **Address** — `store/game-mines`
- **Contains** — dashboard
- **Manifest** — [raw.githubusercontent.com/adi-family/marketplace/main/apps/marketplace.json](https://raw.githubusercontent.com/adi-family/marketplace/main/apps/marketplace.json)

---
[ADI](https://withadi.dev/)

- [Download](https://withadi.dev/#download)
- [Store](https://withadi.dev/store/)
- [Docs](https://docs.withadi.dev/)
- [Source](https://github.com/adi-family/mono)
- [Licence](https://github.com/adi-family/mono/blob/main/LICENSE)
- [Changelog](https://github.com/adi-family/mono/blob/main/CHANGELOG.md)
- [Security](https://withadi.dev/security)
- [Privacy](https://withadi.dev/privacy)
- [Red team](https://withadi.dev/red-team-engagements)
- [Terms](https://withadi.dev/terms)
- [Support](https://withadi.dev/support)
- [Startups](https://withadi.dev/startups)
- [Partners](https://withadi.dev/#partners)
- [Partner portal](https://partners.withadi.dev/)
- [info@withadi.dev](mailto:info@withadi.dev)
- [Contact](mailto:info@withadi.dev)
