SOURCE / PINNED RELEASE
Made of little things.
Shiftfield
- Release
- 5a170c505f6b…
- Author-recorded commit
- a2e23e0171aa…
- License
- LICENSE
- Author’s source reference
- nostr://npub16nzc4ql748r2kv9202rgzrt0fmtk4n3tzsjl86yf6ty9agqe9u0qjcc7hc/wss%3A%2F%2Fgit.napplet.soy%2F/n-e4fb6341ccd
Archive hash verified: 66de7623efd91da1…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
# Browser Testing — Automated + Manual
The game must always be playable **in an actual browser** on the built
artifact (`dist/index.html`), not just in headless unit tests. Two tiers:
## Tier 1 — Automated (CI-verifiable, runs in `pnpm verify`)
`pnpm test:browser` boots the BUILT `dist/` in real headless Chromium
(Playwright, pinned to the same browser build the conformance CLI uses) and
asserts the full loop: boot error-free, click→Flow/turn tick, right-click
flag, radar cost+cooldown, Sector-clear overlay → Continue → depth+1,
death overlay → New Run → reset, ice/fire/telegraph render at depth 11,
board square with no overflow at 200×160 / 320×560 / 900×600.
Prereqs (already satisfied in this repo):
- `playwright@1.61.0` devDependency (keep in lockstep with
`@napplet/conformance-cli`'s bundled playwright).
- browser binary: `node node_modules/playwright/cli.js install
chromium-headless-shell` if `~/.cache/ms-playwright/` lacks it.
The smoke test drives the live engine through the DOM via the QA hook
`window.minesweeperDx` (exposed in `src/main.ts`). Keep the hook: if you
rename/remove it, `tests/browser.test.mjs` fails, which is intended.
## Tier 2 — Manual (human-required; do this before ANY release/demo)
Automated Chromium cannot feel touch, real shell framing, or visual polish.
The user must run through this checklist in the real shell (`soyli dev` →
printed URL) and report results back to the agent session.
1. **Serve it:** `soyli dev` (follow its printed URL) or `pnpm preview`
(http://127.0.0.1:4173). Stop the server afterwards.
2. **Desktop mouse:** reveal several safe tiles (Flow rises, turn ticks).
Right-click → flag ⚑. Right-click the same tile again → flag is REMOVED
(classic toggle). Right-click on a revealed tile → nothing happens (flags
only go on hidden ground). Right-click a *fire* tile if visible → fire
locks.
Reveal every mine-free tile → **Sector clear** overlay → Continue →
depth increments and a fresh board renders.
3. **Death:** reveal any tile FIRST (the opening can never detonate — classic
first-click safety: even clicking a mine on the board's very first reveal
opens the tile and moves that mine elsewhere). THEN click a mine → boom
status + **Run over** overlay, all 15 mines flash red. New Run → everything
resets to depth 0 / turn 0, and the new board's first reveal is protected
again.
4. **Abilities:** spend 5 Flow on Radar → the button highlights and the status
says "Radar armed"; **nothing fires yet**. The NEXT tile you click takes the
3×3 reveal (not the last-focused tile, and the clicked tile is not
additionally revealed as a normal click). Right-click/long-press or pressing
Radar again (or Escape) cancels the arm. Buttons disable when Flow is short
or on cooldown (⏳ badge counts down per turn).
5. **Chaos at depth ≥ 6:** shift telegraph appears in HUD (arrow + turn
countdown). When it fires, mines visibly slide one tile in the arrow
direction with toroidal wrap. Stabilizer freezes the countdown.
6. **Hazards at depth ≥ 11:** board opens with one ❄ ice and one ▲ fire
tile. Ice blocks clicks 3 turns (status stays, tile thaws). Fire pulses
and spreads every 2 turns; reveal extinguishes, flag locks, and letting
fire touch a mine detonates the run.
7. **Touch (phone/tablet):** tap = reveal, long-press ≈0.5s = flag toggle
(press again on a flagged tile to remove it; no ghost reveal afterwards).
CRITICAL (double-toggle fix 2026-10-29): during a long press the flag
appears MID-HOLD and MUST STILL BE THERE when you lift the finger on the
same tile — exactly ONE flag, exactly ONE turn tick, no slide-off trick
needed.
Desktop also verify: a SLOW right-click (hold the right button >0.5s
before releasing) still PLACES a flag — and the next left-click reveals
normally.
Pinch/rotate should not break layout.
8. **Frame sizes inside the real napplet shell:** drag-resize through
200×160, 320×560, 900×600, fullscreen. Board stays square, no scrollbars,
ability bar reachable.
9. **Keyboard:** arrows move focus ring, Enter reveals, Space flags
(same toggle: Space on a flagged tile removes the flag).
10. **Leaderboard & runner name (first-run gate ruling 2026-10-29):** on a
FRESH identity (or a save that has never been asked), the FIRST
`Enter The Depths` click must be interrupted by the **Choose your runner
name** modal — type a name, press Enter (or click the button), the run
starts. It must NEVER appear again (not on later starts, not after
reload). Clear a board → Bank: the summary note invites a name — press
**Enter** in the field to post immediately, or leave the summary any other
way to post on exit. Open Leaderboard: your row carries the typed name,
never `unnamed-runner`. Blank name at the gate = runs as `unnamed-runner`
by player choice. On a host WITHOUT cvm (e.g. `pnpm preview`) the gate
must never appear and all board entry points stay hidden.
If any Tier-2 item fails, file the symptom + repro in the session; fix it
and, where automatable, extend `tests/browser.test.mjs`.
