Deploy to monsterrobot.games/games/policesquadquest/ + page shell

Live: https://monsterrobot.games/games/policesquadquest/

web/index.html is our arcade page shell, matching the house style set by
morpquest (boot splash, gold README tab, controls and the shelf explained).
tools/webbuild.sh copies it over the engine's default after baking, so the
cases/ shelf directory stays nothing but games.

Hosting, established by reading the boxes rather than the docs: the deploy-map
note pointing at /opt/dealgod/images/engine/ on the dealgod VPS is stale for
this domain — that path now falls through to the arcade index. monsterrobot.games
is actually served by forum-nginx on the GAMES VPS (humanjing@100.71.119.27)
from a bind mount of /home/humanjing/monsterrobot.games, and games are plain
directories under games/ picked up by try_files with no nginx change at all.
Deployed exactly like /games/morpquest/, which is the same engine.

Verified live: all four assets 200 with correct application/wasm content-type,
our title (not the arcade fallback), the shelf renders, a case loads and plays,
and the parser round-trips over the wire. Nothing existing was touched — fresh
directory, no config edited, no cache purge needed for a new path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
type-two 2026-07-27 19:17:04 +10:00
parent 9a64cfdf9f
commit 38b2806401
3 changed files with 114 additions and 3 deletions

View File

@ -93,6 +93,10 @@ isn't → Richard Cane → a New Year's ball drop, a pair of lost trousers, and
barn owl in a 1950s hat who is lit by a different decade than everything around
him.
## Play it online
**[monsterrobot.games/games/policesquadquest/](https://monsterrobot.games/games/policesquadquest/)**
## Web build
The whole campaign bakes into a single self-contained wasm — title screen,
@ -102,9 +106,25 @@ all sixteen cases, ~2.1 MB:
./tools/webbuild.sh
```
Output lands in `MRPGI/web/dist/` (wasm + `index.html` + the macroquad JS
shim). Preview it with any static server; deploy by copying that directory to
the host. The shelf's title comes from [cases/collection.json](cases/collection.json).
Output lands in `MRPGI/web/dist/` (wasm + our page shell from
[web/index.html](web/index.html) + the macroquad JS shim). The shelf's title
comes from [cases/collection.json](cases/collection.json).
Deploy — monsterrobot.games is served by **forum-nginx on the games VPS**
(`humanjing@100.71.119.27`) from a bind mount of
`/home/humanjing/monsterrobot.games`. Games are plain directories under
`games/`; the server block's `try_files $uri $uri/ /index.html` picks them up
with no nginx change. Same pattern as `/games/morpquest/`:
```bash
./tools/webbuild.sh
rsync -az --delete ~/Documents/MRPGI/web/dist/ \
humanjing@100.71.119.27:/home/humanjing/monsterrobot.games/games/policesquadquest/
```
Then curl the live URL cache-busted to confirm. Note the deploy-map's older
note about `/opt/dealgod/images/engine/` on the dealgod VPS is stale for this
domain — that path no longer serves monsterrobot.games.
## Regenerating art

View File

@ -9,4 +9,9 @@ set -e
ENGINE="${MRPGI:-$HOME/Documents/MRPGI}"
cd "$(dirname "$0")/.."
"$ENGINE/web/build.sh" "$(pwd)/cases"
# build.sh looks for a page shell beside the baked dir; ours lives at the repo
# root so the cases/ shelf stays nothing but games.
cp web/index.html "$ENGINE/web/dist/index.html"
echo "page shell: web/index.html"
echo "preview locally: cd $ENGINE/web/dist && python3 -m http.server 8899"

86
web/index.html Normal file
View File

@ -0,0 +1,86 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>POLICE SQUAD QUEST</title>
<meta name="description" content="A Sierra-style EGA adventure. Sixteen cases, three generations of Frank Drebin, 1939 to 2025. Correct police procedure, followed exactly, causing catastrophe. Runs in your browser on the MRPGI engine.">
<style>
html, body { margin: 0; padding: 0; height: 100%; background: #000; overflow: hidden; }
canvas {
position: absolute; inset: 0;
width: 100%; height: 100%;
image-rendering: pixelated;
background: #000;
}
#boot {
position: absolute; inset: 0; display: flex; flex-direction: column;
align-items: center; justify-content: center; gap: 12px;
color: #55ff55; font-family: ui-monospace, Menlo, monospace; font-size: 14px;
pointer-events: none; transition: opacity .4s;
}
#boot b { font-size: 22px; letter-spacing: 3px; color: #ffd250; }
#readme-tab {
position: fixed; bottom: 0; right: 24px; z-index: 10;
background: #ffd250; color: #000; border: 0;
border-radius: 8px 8px 0 0; padding: 7px 14px 5px;
font: bold 13px ui-monospace, Menlo, monospace; letter-spacing: 1px;
cursor: pointer;
}
#readme {
position: fixed; bottom: 34px; right: 12px; z-index: 10; display: none;
width: min(380px, calc(100vw - 24px)); max-height: 80vh; overflow-y: auto;
background: #0a0a12; color: #ccc; border: 1px solid #ffd250; border-radius: 8px;
padding: 14px 16px; font: 13px/1.5 ui-monospace, Menlo, monospace;
}
#readme.open { display: block; }
#readme h1 { font-size: 15px; color: #ffd250; margin: 0 0 6px; letter-spacing: 1px; }
#readme h2 { font-size: 13px; color: #55ffff; margin: 12px 0 2px; }
#readme p { margin: 4px 0; }
#readme kbd {
background: #16161f; border: 1px solid #444; border-radius: 4px;
padding: 0 5px; font: inherit; color: #fff;
}
</style>
</head>
<body>
<div id="boot"><b>POLICE SQUAD QUEST</b><span>tuning the late movie&hellip;</span></div>
<canvas id="glcanvas" tabindex="1"></canvas>
<button id="readme-tab">README</button>
<div id="readme">
<h1>POLICE SQUAD QUEST</h1>
<p>Sixteen cases. Three generations of Frank Drebin, 1939 to 2025. The game
grades you on correct police procedure with a completely straight face, and
the reward for perfect procedure is catastrophe anyway.</p>
<h2>The shelf</h2>
<p><kbd>&uarr;</kbd><kbd>&darr;</kbd> choose a case &middot; <kbd>Enter</kbd>
to play &middot; <kbd>Esc</kbd> inside a case returns you here. Start
anywhere; each case stands alone. Act Zero is 1958 and is not funny on
purpose.</p>
<h2>Playing</h2>
<p><kbd>&larr;&uarr;&darr;&rarr;</kbd> or click to walk &middot; type verbs +
<kbd>Enter</kbd> (<i>look, take badge, dust counter, mirandize sally&hellip;</i>)
&middot; <kbd>1</kbd>&ndash;<kbd>6</kbd> pick a dialogue reply &middot;
<kbd>Esc</kbd> leaves a chat &middot; <kbd>F1</kbd> CRT scanlines &middot;
<kbd>F2</kbd> sound.</p>
<h2>Advice from the files</h2>
<p>Sign out your badge AND your sidearm. Read the rights in order. Fill in
the form. The form is always the answer.</p>
<p>REGULATIONS ARE REGULATIONS.</p>
<p>Every case is 100 points. Several are lethal. One of them is worth 140.
Nobody reads the reports.</p>
<h2>Made with</h2>
<p>The <a href="manual.html" target="_blank" style="color:#55ffff">MRPGI engine</a>
(a Rust reimagining of Sierra's AGI), ~300 sprites generated locally and
crushed into 160&times;168 EGA, and a great deal of paperwork.</p>
</div>
<script>
document.getElementById('readme-tab').onclick = () =>
document.getElementById('readme').classList.toggle('open');
const boot = document.getElementById('boot');
setTimeout(() => { boot.style.opacity = 0; }, 2600);
</script>
<script src="mq_js_bundle.js"></script>
<script>load("mrpgi.wasm");</script>
</body>
</html>