chore: move to @cozy-games/mnswpr
This commit is contained in:
parent
2d7f7d0ebb
commit
3418be3d7b
13 changed files with 31 additions and 31 deletions
|
|
@ -4,7 +4,7 @@ Guidance for AI coding agents working in this repository.
|
||||||
|
|
||||||
## What this is
|
## What this is
|
||||||
|
|
||||||
Classic Minesweeper as a vanilla web game — no framework, no TypeScript (JSDoc + `// @ts-check` only). Deployed at [mnswpr.com](https://mnswpr.com) (Netlify) and published to npm as `@ayo-run/mnswpr`. The game engine has **zero runtime dependencies**; only the website adds Firebase.
|
Classic Minesweeper as a vanilla web game — no framework, no TypeScript (JSDoc + `// @ts-check` only). Deployed at [mnswpr.com](https://mnswpr.com) (Netlify) and published to npm as `@cozy-games/mnswpr`. The game engine has **zero runtime dependencies**; only the website adds Firebase.
|
||||||
|
|
||||||
**`mnswpr` is the main test app.** It's the reference app for the monorepo and the default target for local runs — `.claude/launch.json` launches it (`dev` on :5173, `preview` on :4173), and it's what you should build/run/preview when verifying changes to the shared packages or tooling.
|
**`mnswpr` is the main test app.** It's the reference app for the monorepo and the default target for local runs — `.claude/launch.json` launches it (`dev` on :5173, `preview` on :4173), and it's what you should build/run/preview when verifying changes to the shared packages or tooling.
|
||||||
|
|
||||||
|
|
@ -79,8 +79,8 @@ Node version: `.nvmrc` pins `lts/*`.
|
||||||
|
|
||||||
This is the **Cozy Games** monorepo. Workspaces are declared in `pnpm-workspace.yaml` as `apps/*`, `packages/*`, and `sites/*`. `utils/` is now a real workspace package (`@cozy-games/utils`), imported by name — no more `../utils` relative paths.
|
This is the **Cozy Games** monorepo. Workspaces are declared in `pnpm-workspace.yaml` as `apps/*`, `packages/*`, and `sites/*`. `utils/` is now a real workspace package (`@cozy-games/utils`), imported by name — no more `../utils` relative paths.
|
||||||
|
|
||||||
- **`apps/mnswpr/`** — package `mnswpr`, `@ayo-run/mnswpr`'s host, the mnswpr.com website. Consumes the engine and leaderboard via `workspace:*` (`import mnswpr from '@ayo-run/mnswpr/mnswpr.js'`) and wires them together in `apps/mnswpr/main.js`. Owns its Firebase config (`firebase.json`, `firestore.rules`, `.firebaserc`) and app-specific scripts (`apps/mnswpr/scripts/`). A future app (e.g. sudoku) gets its own `apps/<name>/` and its `package.json` `name` is just the app name (`<name>`, unscoped) so it's addressable directly by name (`pnpm -F <name> run <script>`).
|
- **`apps/mnswpr/`** — package `mnswpr`, `@cozy-games/mnswpr`'s host, the mnswpr.com website. Consumes the engine and leaderboard via `workspace:*` (`import mnswpr from '@cozy-games/mnswpr/mnswpr.js'`) and wires them together in `apps/mnswpr/main.js`. Owns its Firebase config (`firebase.json`, `firestore.rules`, `.firebaserc`) and app-specific scripts (`apps/mnswpr/scripts/`). A future app (e.g. sudoku) gets its own `apps/<name>/` and its `package.json` `name` is just the app name (`<name>`, unscoped) so it's addressable directly by name (`pnpm -F <name> run <script>`).
|
||||||
- **`packages/mnswpr/`** — `@ayo-run/mnswpr`, the standalone, framework-free game engine published to npm. `packages/mnswpr/mnswpr.js` is the whole engine; `levels.js` defines the four difficulty presets. Depends only on `@cozy-games/utils`.
|
- **`packages/mnswpr/`** — `@cozy-games/mnswpr`, the standalone, framework-free game engine published to npm. `packages/mnswpr/mnswpr.js` is the whole engine; `levels.js` defines the four difficulty presets. Depends only on `@cozy-games/utils`.
|
||||||
- **`packages/leaderboard/`** — `@cozy-games/leaderboard`, a backend-agnostic, time-windowed leaderboard (adapter-injected storage).
|
- **`packages/leaderboard/`** — `@cozy-games/leaderboard`, a backend-agnostic, time-windowed leaderboard (adapter-injected storage).
|
||||||
- **`packages/utils/`** — `@cozy-games/utils`, shared services with no dependencies, re-exported from `index.js`: `StorageService`, `TimerService` (`pretty()` time formatting used by both engine and leaderboard), `LoggerService`, `LoadingService`, and date-bucket helpers.
|
- **`packages/utils/`** — `@cozy-games/utils`, shared services with no dependencies, re-exported from `index.js`: `StorageService`, `TimerService` (`pretty()` time formatting used by both engine and leaderboard), `LoggerService`, `LoadingService`, and date-bucket helpers.
|
||||||
- **`sites/`** — docs (Astro Starlight) and UI demos. Placeholders for now.
|
- **`sites/`** — docs (Astro Starlight) and UI demos. Placeholders for now.
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,14 @@ The goal is to reveal every safe cell without detonating a mine. Your **first cl
|
||||||
The web is a wonderful, free, and open platform to create and distribute value. You can use **mnswpr** in different ways:
|
The web is a wonderful, free, and open platform to create and distribute value. You can use **mnswpr** in different ways:
|
||||||
|
|
||||||
- as a deployed [web app](https://mnswpr.com)
|
- as a deployed [web app](https://mnswpr.com)
|
||||||
- as a [library](https://npmx.dev/package/@ayo-run/mnswpr) with `npm i @ayo-run/mnswpr`
|
- as a [library](https://npmx.dev/package/@cozy-games/mnswpr) with `npm i @cozy-games/mnswpr`
|
||||||
- as a `web component` (coming soon).
|
- as a `web component` (coming soon).
|
||||||
|
|
||||||
Using it as a library takes only a few lines — mount it onto any element by `id`:
|
Using it as a library takes only a few lines — mount it onto any element by `id`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import '@ayo-run/mnswpr/mnswpr.css'
|
import '@cozy-games/mnswpr/mnswpr.css'
|
||||||
import mnswpr from '@ayo-run/mnswpr'
|
import mnswpr from '@cozy-games/mnswpr'
|
||||||
|
|
||||||
const game = new mnswpr('app')
|
const game = new mnswpr('app')
|
||||||
game.initialize()
|
game.initialize()
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import mnswpr from '@ayo-run/mnswpr/mnswpr.js'
|
import mnswpr from '@cozy-games/mnswpr/mnswpr.js'
|
||||||
import '@ayo-run/mnswpr/mnswpr.css'
|
import '@cozy-games/mnswpr/mnswpr.css'
|
||||||
import '@cozy-games/utils/loading/loading.css'
|
import '@cozy-games/utils/loading/loading.css'
|
||||||
import * as pkg from '@ayo-run/mnswpr/package.json'
|
import * as pkg from '@cozy-games/mnswpr/package.json'
|
||||||
import { configureLeaderboard } from '@cozy-games/leaderboard/leaderboard-element.js'
|
import { configureLeaderboard } from '@cozy-games/leaderboard/leaderboard-element.js'
|
||||||
import { FirebaseAdapter } from '@cozy-games/leaderboard/adapters/firebase.js'
|
import { FirebaseAdapter } from '@cozy-games/leaderboard/adapters/firebase.js'
|
||||||
import { NicknameService } from './modules/nickname/nickname.js'
|
import { NicknameService } from './modules/nickname/nickname.js'
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
"db:stop": "pkill -f '[c]loud-firestore-emulator'; pkill -f '[f]irebase.* emulators:'; true"
|
"db:stop": "pkill -f '[c]loud-firestore-emulator'; pkill -f '[f]irebase.* emulators:'; true"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ayo-run/mnswpr": "workspace:*",
|
"@cozy-games/mnswpr": "workspace:*",
|
||||||
"@cozy-games/leaderboard": "workspace:*",
|
"@cozy-games/leaderboard": "workspace:*",
|
||||||
"@cozy-games/utils": "workspace:*",
|
"@cozy-games/utils": "workspace:*",
|
||||||
"firebase": "^12.11.0",
|
"firebase": "^12.11.0",
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import {
|
||||||
getFirestore, getDocs, collection, query, orderBy, limit
|
getFirestore, getDocs, collection, query, orderBy, limit
|
||||||
} from 'firebase/firestore/lite'
|
} from 'firebase/firestore/lite'
|
||||||
|
|
||||||
import { levels } from '@ayo-run/mnswpr/levels.js'
|
import { levels } from '@cozy-games/mnswpr/levels.js'
|
||||||
|
|
||||||
// Mirror of TimerService.pretty() (@cozy-games/utils timer) — inlined so this
|
// Mirror of TimerService.pretty() (@cozy-games/utils timer) — inlined so this
|
||||||
// generator has no cross-module import chain to resolve under raw Node.
|
// generator has no cross-module import chain to resolve under raw Node.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
**Status:** Accepted · **Repo:** cozy-games · **Date:** 2026-07
|
**Status:** Accepted · **Repo:** cozy-games · **Date:** 2026-07
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
cozy-games is a collection of reusable game modules (`@ayo-run/mnswpr`, the
|
cozy-games is a collection of reusable game modules (`@cozy-games/mnswpr`, the
|
||||||
leaderboard package, future extractions). Applications built on these packages
|
leaderboard package, future extractions). Applications built on these packages
|
||||||
differ in how they store data, authenticate users, and enforce rules.
|
differ in how they store data, authenticate users, and enforce rules.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
"build": "pnpm -r --filter \"./packages/*\" run build",
|
"build": "pnpm -r --filter \"./packages/*\" run build",
|
||||||
"build:lib": "vite build packages/mnswpr",
|
"build:lib": "vite build packages/mnswpr",
|
||||||
"publish:lib": "node scripts/publish-lib.js",
|
"publish:lib": "node scripts/publish-lib.js",
|
||||||
"release": "pnpm build:lib && pnpm -F @ayo-run/mnswpr run release && pnpm publish:lib",
|
"release": "pnpm build:lib && pnpm -F @cozy-games/mnswpr run release && pnpm publish:lib",
|
||||||
"postinstall": "node scripts/ensure-java.mjs",
|
"postinstall": "node scripts/ensure-java.mjs",
|
||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ npm i -D vite
|
||||||
Now that the JS project is initialized and we have a development environment with `vite`, we will install **mnswpr** as a dependency:
|
Now that the JS project is initialized and we have a development environment with `vite`, we will install **mnswpr** as a dependency:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm i @ayo-run/mnswpr
|
npm i @cozy-games/mnswpr
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, you can run the installed `vite` dev server by running the following:
|
Finally, you can run the installed `vite` dev server by running the following:
|
||||||
|
|
@ -141,8 +141,8 @@ Create a new file named `main.js` with the following content:
|
||||||
/**
|
/**
|
||||||
* main.js
|
* main.js
|
||||||
*/
|
*/
|
||||||
import '@ayo-run/mnswpr/mnswpr.css'
|
import '@cozy-games/mnswpr/mnswpr.css'
|
||||||
import mnswpr from '@ayo-run/mnswpr'
|
import mnswpr from '@cozy-games/mnswpr'
|
||||||
|
|
||||||
const game = new mnswpr('app')
|
const game = new mnswpr('app')
|
||||||
game.initialize()
|
game.initialize()
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `@ayo-run/mnswpr/core` — the headless, isomorphic Minesweeper core. No DOM, no
|
* `@cozy-games/mnswpr/core` — the headless, isomorphic Minesweeper core. No DOM, no
|
||||||
* wall clock. Runs identically in a browser (offline play) or on a server
|
* wall clock. Runs identically in a browser (offline play) or on a server
|
||||||
* (authoritative timing / replay verification). See
|
* (authoritative timing / replay verification). See
|
||||||
* docs/headless-core-and-client-design.md.
|
* docs/headless-core-and-client-design.md.
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ export function validateLayout(layout) {
|
||||||
/**
|
/**
|
||||||
* Pure, Node-runnable board generation: given a size, a mine count, and an
|
* Pure, Node-runnable board generation: given a size, a mine count, and an
|
||||||
* injected RNG, produce a plain layout object — no DOM, no I/O, no `Grid` class
|
* injected RNG, produce a plain layout object — no DOM, no I/O, no `Grid` class
|
||||||
* leaking out. This is the headless entry point behind `@ayo-run/mnswpr/core`;
|
* leaking out. This is the headless entry point behind `@cozy-games/mnswpr/core`;
|
||||||
* the DOM client reaches the same generator lazily through `MinesweeperRules`.
|
* the DOM client reaches the same generator lazily through `MinesweeperRules`.
|
||||||
*
|
*
|
||||||
* The injected `rng` is the determinism seam: the same rng sequence always
|
* The injected `rng` is the determinism seam: the same rng sequence always
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Headless core + client design — `@ayo-run/mnswpr/core` and the client that consumes it
|
# Headless core + client design — `@cozy-games/mnswpr/core` and the client that consumes it
|
||||||
|
|
||||||
Design for splitting the Minesweeper engine into a **headless, isomorphic core**
|
Design for splitting the Minesweeper engine into a **headless, isomorphic core**
|
||||||
(runs identically in a browser or on a server) and a **thin client** that renders
|
(runs identically in a browser or on a server) and a **thin client** that renders
|
||||||
|
|
@ -23,12 +23,12 @@ Goals, in priority order:
|
||||||
## 1. Package layout & the seam
|
## 1. Package layout & the seam
|
||||||
|
|
||||||
**Decision (settled): one published package, core exposed as a sub-path.** Open-
|
**Decision (settled): one published package, core exposed as a sub-path.** Open-
|
||||||
source consumers keep installing a single `@ayo-run/mnswpr` and get the headless
|
source consumers keep installing a single `@cozy-games/mnswpr` and get the headless
|
||||||
core for free at `@ayo-run/mnswpr/core` — no second package to publish, version,
|
core for free at `@cozy-games/mnswpr/core` — no second package to publish, version,
|
||||||
or document. The DOM client stays the default entry (`.`).
|
or document. The DOM client stays the default entry (`.`).
|
||||||
|
|
||||||
```
|
```
|
||||||
packages/mnswpr/ # @ayo-run/mnswpr — ONE published package
|
packages/mnswpr/ # @cozy-games/mnswpr — ONE published package
|
||||||
mnswpr.js # "." → DOM client (browser entry; today's default)
|
mnswpr.js # "." → DOM client (browser entry; today's default)
|
||||||
levels.js # shared by client + core (level presets)
|
levels.js # shared by client + core (level presets)
|
||||||
core/ # "./core" → headless, isomorphic, ZERO DOM, ZERO wall-clock
|
core/ # "./core" → headless, isomorphic, ZERO DOM, ZERO wall-clock
|
||||||
|
|
@ -66,8 +66,8 @@ packages/mnswpr/ # @ayo-run/mnswpr — ONE published package
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- `import mnswpr from '@ayo-run/mnswpr'` → DOM client, exactly as today.
|
- `import mnswpr from '@cozy-games/mnswpr'` → DOM client, exactly as today.
|
||||||
- `import { GameSession, MinesweeperRules } from '@ayo-run/mnswpr/core'` → headless.
|
- `import { GameSession, MinesweeperRules } from '@cozy-games/mnswpr/core'` → headless.
|
||||||
The core entry pulls in **zero DOM**, so a server (later) imports it without
|
The core entry pulls in **zero DOM**, so a server (later) imports it without
|
||||||
dragging in browser code, and the browser bundle for `.` never includes the
|
dragging in browser code, and the browser bundle for `.` never includes the
|
||||||
core's server-only helpers.
|
core's server-only helpers.
|
||||||
|
|
@ -85,7 +85,7 @@ layering are orthogonal. Rules of the seam:
|
||||||
|
|
||||||
When Sudoku lands, `core/grid/` and `core/session/` move out verbatim into
|
When Sudoku lands, `core/grid/` and `core/session/` move out verbatim into
|
||||||
`@cozy-games/grid` + `@cozy-games/game-session`; `core/minesweeper/` (and a new
|
`@cozy-games/grid` + `@cozy-games/game-session`; `core/minesweeper/` (and a new
|
||||||
`sudoku/`) depend on them, and `@ayo-run/mnswpr/core` re-exports from them so the
|
`sudoku/`) depend on them, and `@cozy-games/mnswpr/core` re-exports from them so the
|
||||||
consumer-facing sub-path is unchanged.
|
consumer-facing sub-path is unchanged.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -346,7 +346,7 @@ Minesweeper(appId, version, {
|
||||||
| Needs a host tier | no | yes (Function/Worker + session store) |
|
| Needs a host tier | no | yes (Function/Worker + session store) |
|
||||||
| Use | offline play, published npm engine | host-owned sessions |
|
| Use | offline play, published npm engine | host-owned sessions |
|
||||||
|
|
||||||
The published `@ayo-run/mnswpr` stays fully functional standalone (Local mode).
|
The published `@cozy-games/mnswpr` stays fully functional standalone (Local mode).
|
||||||
Running on a host opts into Remote. Same renderer, same input, same rules.
|
Running on a host opts into Remote. Same renderer, same input, same rules.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -425,7 +425,7 @@ appear in `core/` outside the injected `clock`/`rng` seams.
|
||||||
|
|
||||||
## 11. Open decisions
|
## 11. Open decisions
|
||||||
|
|
||||||
- **Package boundary:** ✅ *resolved* — one `@ayo-run/mnswpr` package, core at the
|
- **Package boundary:** ✅ *resolved* — one `@cozy-games/mnswpr` package, core at the
|
||||||
`./core` sub-path (§1). Extraction to `@cozy-games/grid` + `@cozy-games/game-session`
|
`./core` sub-path (§1). Extraction to `@cozy-games/grid` + `@cozy-games/game-session`
|
||||||
deferred to when Sudoku lands; the sub-path stays stable across that move.
|
deferred to when Sudoku lands; the sub-path stays stable across that move.
|
||||||
- **Host mode (replay-validation vs live authority):** *deferred.* Ship
|
- **Host mode (replay-validation vs live authority):** *deferred.* Ship
|
||||||
|
|
|
||||||
|
|
@ -50,12 +50,12 @@ importers:
|
||||||
|
|
||||||
apps/mnswpr:
|
apps/mnswpr:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@ayo-run/mnswpr':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../../packages/mnswpr
|
|
||||||
'@cozy-games/leaderboard':
|
'@cozy-games/leaderboard':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/leaderboard
|
version: link:../../packages/leaderboard
|
||||||
|
'@cozy-games/mnswpr':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../packages/mnswpr
|
||||||
'@cozy-games/utils':
|
'@cozy-games/utils':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/utils
|
version: link:../../packages/utils
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Publishes @ayo-run/mnswpr to npm using the mnswpr app README.md as the
|
// Publishes @cozy-games/mnswpr to npm using the mnswpr app README.md as the
|
||||||
// package's README (what npmjs.com displays).
|
// package's README (what npmjs.com displays).
|
||||||
//
|
//
|
||||||
// packages/mnswpr/README.md is a generated copy (gitignored) — the source of
|
// packages/mnswpr/README.md is a generated copy (gitignored) — the source of
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue