fuzzyworld

explodorama / commit

Deploy to apps.fuzzyworld.net with fuzzyworld-tools

2f667e952ea037961710678bd0585335b868a24d · Pavel Safronov · 2026-10-26 18:21:08 -0700 · parents 6c3fcc3172c6

Deploy to apps.fuzzyworld.net with fuzzyworld-tools

Adds the fuzzyworld package.json section, a deploy script (fw deploy) and the fuzzyworld-tools dependency, and points gitlab.io / gitlab.com links at apps.fuzzyworld.net and code.fuzzyworld.net.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
 CONTRIBUTING.md             | 17 ++++++++++-------
 PLAN.md                     |  4 ++--
 README.md                   |  4 ++--
 package-lock.json           | 13 +++++++++++++
 package.json                | 13 ++++++++++---
 src/main.ts                 |  8 ++++----
 static/manifest.webmanifest |  1 +
 vite.config.ts              |  3 ++-
 8 files changed, 44 insertions(+), 19 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f8df061..335f4a3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,11 +1,14 @@
 # Contributing to Explodorama
 
-Thank you for wanting to help! Bug reports, playtest notes and merge requests are all welcome
-on [GitLab](https://gitlab.com/PavelSafronov/explodorama).
+Thank you for wanting to help! The project moved from GitLab to
+[code.fuzzyworld.net](https://code.fuzzyworld.net/explodorama/), which has no issue tracker or
+merge requests yet. Bug reports and playtest notes are welcome through the game's **report**
+link, which opens a prefilled email. Code contributions are paused until merge requests are
+supported again; the sections below still describe what one needs.
 
 ## Reporting a bug
 
-Open an issue and include:
+Send a report and include:
 
 - what you did, what you expected, and what happened instead;
 - the **seed** (shown in the menu, and on the game-over and victory banners) and the level —
@@ -14,7 +17,7 @@ Open an issue and include:
 
 ## Getting set up
 
-You need Node.js 22 (the version CI uses).
+You need Node.js 22.
 
 ```sh
 npm install
@@ -34,10 +37,10 @@ the game carries on instead of freezing.
 The URL parameters listed in the README (`?seed`, `?level`, `?charges`, `?dev`,
 `?immortal`, `?demo`) are the quickest way to reach the situation you are working on.
 
-## Before you open a merge request
+## Before you send a change (once contributions reopen)
 
-1. **`npm test` and `npm run build` both pass.** CI runs exactly these two, and Pages only
-   deploys when they pass.
+1. **`npm test` and `npm run build` both pass.** `npm run deploy` runs exactly these two,
+   and only publishes when they pass.
 2. **Rule changes come with tests.** Game rules live in `src/sim/` and are tested in `test/`.
 3. **The docs are up to date.** A change a player can notice belongs in the README and in
    [CHANGELOG.md](CHANGELOG.md) under *Unreleased*. A change to the design or to a recorded
diff --git a/PLAN.md b/PLAN.md
index 748005e..8c3e9ae 100644
--- a/PLAN.md
+++ b/PLAN.md
@@ -531,7 +531,7 @@ A **Developer** run earns them all, but each shows a **red border** (user reques
 "like the red quarters some bars used in jukeboxes"); its victory banner is framed in red already.
 
 Shows: **seed, date, turns, deaths, sim version**, and a
-**QR code** linking to `https://pavelsafronov.gitlab.io/explodorama/#cert=…`.
+**QR code** linking to `https://apps.fuzzyworld.net/explodorama/#cert=…`.
 
 Being honest about what this can prove: the game is fully client-side and open source, so any
 code-only "signature" can be forged by someone determined. What *can* be verified is the run
@@ -996,7 +996,7 @@ tools/                 compose-icons.sh (composed sprites and the app icons), sc
   of everything loaded (so the game starts offline) and registers only in the build.
 - `.gitlab-ci.yml`: copy nordic-skating's (test stage, then `pages` with `mv dist public` and the
   "fail loudly" checks; add a check that the sprites were built). Project at
-  `gitlab.com/PavelSafronov/explodorama`, served at `https://pavelsafronov.gitlab.io/explodorama/`.
+  `code.fuzzyworld.net/explodorama`, served at `https://apps.fuzzyworld.net/explodorama/`.
 - Docs to create and keep current: `README.md` (how to play; every action, pickup, curse, enemy;
   Attribution), this `PLAN.md`, `decisions.md` (each decision + why — seed it
   from §0), `design.md` (balance tables: enemy schedule, prices, drop rates, payout formula).
diff --git a/README.md b/README.md
index 1aabddb..f2da529 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # EXPLODORAMA!
 
-**[▶ Play now!](https://pavelsafronov.gitlab.io/explodorama/)** — in the browser, on a phone or a computer.
+**[▶ Play now!](https://apps.fuzzyworld.net/explodorama/)** — in the browser, on a phone or a computer.
 
 A turn-based, mobile-first, roguelike take on the 1985 NES bomb-laying classic. Every bomb
 counts down with *your* moves, so nothing happens until you act — and you can see exactly
@@ -13,7 +13,7 @@ see [PLAN.md](PLAN.md).
 
 Version: **39**, shown at the bottom of the menu with the commit the game was built from (a link
 to it on GitLab, plus "plus local changes" in a build with uncommitted changes) and a link to the
-[source code](https://gitlab.com/PavelSafronov/explodorama). The version is the rules version
+[source code](https://code.fuzzyworld.net/explodorama/). The version is the rules version
 (`SIM_VERSION` in [src/sim/record.ts](src/sim/record.ts)): it goes up by one whenever a rule
 change would make an old run replay differently. A run saved under another version is not
 resumed, and a seed gives the same dungeon only within one version.
diff --git a/package-lock.json b/package-lock.json
index 82259f0..e9174c6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
       },
       "devDependencies": {
         "@types/node": "^26.6.5",
+        "fuzzyworld-tools": "git+https://code.fuzzyworld.net/fuzzyworld-tools.git#semver:^1.0.0",
         "playwright": "^1.63.0",
         "typescript": "^7.0.2",
         "vite": "^8.3.4",
@@ -823,6 +824,18 @@
         "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
       }
     },
+    "node_modules/fuzzyworld-tools": {
+      "version": "1.0.1",
+      "resolved": "git+https://code.fuzzyworld.net/fuzzyworld-tools.git#45b1fe3805ad7ec86b864e4604b7ad89a0e25a78",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "fw": "bin/fw"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/lightningcss": {
       "version": "1.33.0",
       "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz",
diff --git a/package.json b/package.json
index a03d5ae..d57b521 100644
--- a/package.json
+++ b/package.json
@@ -11,23 +11,30 @@
     "test": "vitest run",
     "test:watch": "vitest",
     "screenshots": "npm run build && node tools/screenshots.mjs",
-    "balance": "node tools/balance/run.mjs"
+    "balance": "node tools/balance/run.mjs",
+    "deploy": "fw deploy"
   },
   "repository": {
     "type": "git",
-    "url": "https://gitlab.com/PavelSafronov/explodorama.git"
+    "url": "https://code.fuzzyworld.net/explodorama.git"
   },
-  "homepage": "https://pavelsafronov.gitlab.io/explodorama/",
+  "homepage": "https://apps.fuzzyworld.net/explodorama/",
   "license": "MIT",
   "dependencies": {
     "littlejsengine": "1.28.0"
   },
   "devDependencies": {
     "@types/node": "^26.6.5",
+    "fuzzyworld-tools": "git+https://code.fuzzyworld.net/fuzzyworld-tools.git#semver:^1.0.0",
     "playwright": "^1.63.0",
     "typescript": "^7.0.2",
     "vite": "^8.3.4",
     "vite-plugin-qrcode": "^0.4.1",
     "vitest": "^5.0.5"
+  },
+  "fuzzyworld": {
+    "app": "explodorama",
+    "title": "EXPLODORAMA!",
+    "description": "A turn-based, mobile-first, roguelike bomb-laying game. Every bomb counts down with your moves."
   }
 }
diff --git a/src/main.ts b/src/main.ts
index 57fb09e..21616ff 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -392,7 +392,7 @@ function showInfo(info: Info, extra: DialogButton[] = []): void {
   if (clip) startClip(document.querySelector<HTMLCanvasElement>('#dialog-body canvas.clip')!, clip)
 }
 
-const REPO_URL = 'https://gitlab.com/PavelSafronov/explodorama'
+const REPO_URL = 'https://code.fuzzyworld.net/explodorama'
 /**
  * The project's GitLab Service Desk address (user, 2026-10-24): an email to it becomes a
  * confidential issue, so players need no GitLab account. Public by design: it is in the game's
@@ -435,11 +435,11 @@ function reportBug(): void {
   location.href = mailto(bugDetails(false) + '\nRun record: too long for an email link. The full details are on your clipboard: please paste them here.')
 }
 
-/** ", commit 0580e85" linked to it on GitLab, with a note if built with uncommitted changes. */
+/** ", commit 0580e85" linked to its page on code.fuzzyworld.net, with a note if built with uncommitted changes. */
 function commitLine(): string {
   const commit = import.meta.env.VITE_COMMIT
   if (!commit) return ''
-  const link = `<a href="${REPO_URL}/-/commit/${commit}" target="_blank" rel="noopener">${commit}</a>`
+  const link = `<a href="${REPO_URL}/commit/${commit}.html" target="_blank" rel="noopener">${commit}</a>`
   return `, commit ${link}${import.meta.env.VITE_COMMIT_DIRTY ? ' plus local changes' : ''}`
 }
 
@@ -463,7 +463,7 @@ function showMenu(): void {
       `New Platformer Pack, UI Pack, UI Pack: RPG Expansion, Game Icons, Board Game Icons and Splat Pack (CC0). Thank you!</p>` +
       // The version is the rules version: it changes exactly when old saves stop resuming.
       `<p class="credit">Version ${SIM_VERSION}${commitLine()}. ` +
-      `<a href="${REPO_URL}" target="_blank" rel="noopener">Source code</a></p>`,
+      `<a href="${REPO_URL}/" target="_blank" rel="noopener">Source code</a></p>`,
     buttons: [
       { label: 'Resume', kind: 'primary', icon: playIcon },
       { label: 'New', kind: 'danger', icon: newRunIcon, onClick: newRunDialog },
diff --git a/static/manifest.webmanifest b/static/manifest.webmanifest
index 41cc9a6..4d84a87 100644
--- a/static/manifest.webmanifest
+++ b/static/manifest.webmanifest
@@ -1,4 +1,5 @@
 {
+  "id": "./",
   "name": "EXPLODORAMA!",
   "short_name": "EXPLODORAMA!",
   "description": "A turn-based, mobile-first, roguelike bomb-laying game. Every bomb counts down with your moves.",
diff --git a/vite.config.ts b/vite.config.ts
index eea955f..caf9203 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,6 +1,7 @@
 import { defineConfig } from 'vite'
 import { qrcode } from 'vite-plugin-qrcode'
 import { execSync } from 'node:child_process'
+import fuzzyworld from 'fuzzyworld-tools/vite'
 
 /**
  * Relative asset paths by default, so the same build works wherever Pages puts it:
@@ -27,7 +28,7 @@ export default defineConfig({
   base,
   // `npm run dev` and `npm run preview` bind to every interface (--host) so a phone on the same
   // Wi-Fi can open the game; this prints a scannable QR of that network URL alongside it.
-  plugins: [qrcode()],
+  plugins: [fuzzyworld(), qrcode()],
   // In `npm run dev`, the game's console output and uncaught errors, from any device (a phone on
   // the Wi-Fi too), are printed in this terminal (user request, 2026-10-23: a crash on the phone
   // showed nothing anywhere). Caught errors are logged with their stack by src/devlog.ts.