Games-lander pattern: rsync to the host path (RO bind mount into forum-nginx, docker cp fails silently) + top-level symlink for the pretty URL, no nginx change. Stamps a version query across the ES-module chain in a staging copy because Cloudflare serves .js with max-age=14400 — without it a redeploy shows stale code for hours. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
67 lines
2.3 KiB
Markdown
67 lines
2.3 KiB
Markdown
# PARADRAMORAMA
|
||
|
||
*Ranarama × Paradroid, finished properly this time.*
|
||
|
||
You are a rogue **Signal** loose in a haunted studio complex. The hardware can't
|
||
see you — you're just noise on the line. Static gremlins CAN see you, and they
|
||
hunt signals. Touch a machine to invade it in a live pitch-matching duel (the
|
||
world does not pause), wear its body while it decays, burn its weapons, and bail
|
||
before it blows. Purge every amp and every machine on the floor and the drone
|
||
resolves to a chord.
|
||
|
||
## Play it
|
||
|
||
Live: **https://monsterrobot.games/paradramorama/**
|
||
|
||
Locally — any static server from the repo root (ES modules won't load off
|
||
`file://`):
|
||
|
||
```
|
||
python3 -m http.server 8474
|
||
```
|
||
|
||
then open http://localhost:8474
|
||
|
||
## Deploy
|
||
|
||
```
|
||
./deploy/deploy.sh
|
||
```
|
||
|
||
Rsyncs to the games VPS (`humanjing@100.71.119.27`) at
|
||
`/home/humanjing/monsterrobot.games/games/paradramorama/` — a **read-only**
|
||
bind mount into `forum-nginx`, so deploys write the host path (`docker cp`
|
||
fails silently). Needs no nginx change; the apex server block serves any
|
||
subdirectory, and a top-level symlink gives the pretty URL.
|
||
|
||
Cloudflare serves `.js` with a 4-hour `max-age`, so the deploy stamps a
|
||
version query across the whole module chain (`index.html` → `game.js` →
|
||
`world.js`/`audio.js`) in a staging copy. Source files are never touched.
|
||
Without that you would test stale code for hours after a redeploy.
|
||
|
||
## Controls
|
||
|
||
| Key | Action |
|
||
|---|---|
|
||
| WASD / arrows | move |
|
||
| touch hardware | start possession duel |
|
||
| W / S (in duel) | tune your oscillator to the target tone, hold the lock |
|
||
| SPACE | fire — **hold** to ride the gain (more damage, more noise) |
|
||
| E | eject from the body (leaves a husk you can re-enter, no duel) |
|
||
| P | pause · M | mute |
|
||
|
||
## The loop
|
||
|
||
1. **Bare signal** — fast, invisible to hardware, helpless. Static hunts you.
|
||
2. **Duel** — bump a machine → picture-in-picture pitch-match under a timer
|
||
while the room stays live. Static hits you mid-duel, you lose the duel.
|
||
3. **Possessed** — the body is your health, ammo and disguise, and it is
|
||
always draining. Firing drains it faster. Gain = damage = noise = every
|
||
machine on the floor hears you.
|
||
4. **Bail** — eject before it blows or eat coherence damage. Hide. Hunt the
|
||
next host.
|
||
|
||
Full design: [DESIGN.md](DESIGN.md)
|
||
|
||
Prototype is vanilla JS + Canvas + Web Audio. No dependencies, no build step.
|