guts/README.md
type-two 77ddf88c31 [infra] GUTS is live at partly.party/gutsy — deploy wired, ship-check clean
README said "target: partly.party, not wired yet". It's wired.

tools/deploy.sh follows the GAMES doctrine (deploy-map skill): QA gate -> rsync
web/ to VPS staging -> docker cp into forum-nginx -> verify. No build step, so
web/ ships as-is: vanilla ES modules + importmap with three r175 vendored, all
paths relative or resolved from import.meta.url, which is why it runs from a
subdirectory with no base rewrite. 6.6 MB. nginx.conf needed no edit — its
catch-all `root /usr/share/nginx/html` already routes any new directory, which is
how blobbo works. /gutsy (no slash) 301s to /gutsy/.

Excludes web/dev/ (ruling #5: never shipped). Verified live, not assumed: the
lane harnesses 404 through to the arcade index.

THE 200 THAT ISN'T. That same catch-all try_files means ANY missing file returns
the arcade's index.html with HTTP 200. A deploy that lost every module would
still curl 200 on all of them. So every check asserts on CONTENT, never on the
status code — this is the failure deploy-map records as ".bin data URLs serving
arcade HTML". The guard caught itself, too: it originally grepped for
`<title>MonsterRobot`, but the arcade's real title is
`~*~W3LC0M3 2 TH3 M0NST3R R0B0T P4RTY 4RC4D3~*~`, so it could never have fired.
Matched against the live box now.

DURABILITY, and it's John's call. This docker-cp's into the container's own
layer, matching blobbo/glytch: zero downtime, nothing else touched, survives
restarts and reboots (restart: unless-stopped) — but NOT `docker compose up
--force-recreate` or an nginx image bump, which wipe it. Re-running the script is
the fix. The durable alternative is a bind mount in forum/docker-compose.yml like
cratewars/roguelike have, which costs a forum-nginx recreate and brief downtime
across ALL of partly.party, so this script does not take that decision.

ship-check (README says run it before deploying — I ran it after; my miss, and it
came back clean):
  1 auth        N/A — static files, no endpoint/API/admin surface
  2 secrets     PASS — nothing secret-shaped in the payload or the diff
  3 input/SSRF  PASS — the only user string reaching a fetch is ?lvl=, and C
                gates it on the CAMPAIGN allowlist BEFORE the load
                (levels/index.js:151). Traversal tested live with
                `curl --path-as-is` (plain curl normalises ../ away and proves
                nothing): /etc/passwd never leaked. DEPOT_BASE in assets.js is
                unused — the manifest has zero external URLs.
  4 money       N/A
  5 deploy      PASS — verified by content + booted in a real browser:
                assets.misses() == [], 15 draws, 69k tris, zero console errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 23:02:04 +10:00

60 lines
3.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# GUTS — a fantastic voyage through the alimentary canal
Browser flight-combat game (three.js, zero build step). You pilot **ENDO-1**, a microscopic
probe, mouth → rectum through five anatomically-grounded biomes: ride peristalsis down the
esophagus, cross the acid sea of the stomach, thread the villi forest of the small intestine,
survive the gas swamps of the colon. *Fantastic Voyage* × *Star Fox* × *Descent*.
- **Design:** [docs/GDD.md](docs/GDD.md) · **Look:** [docs/ART_BIBLE.md](docs/ART_BIBLE.md)
- **Architecture + contracts:** [docs/TECH.md](docs/TECH.md)
- **Asset generation:** [docs/PIPELINE.md](docs/PIPELINE.md)
- **How we work (lanes/rounds):** [docs/PROCESS.md](docs/PROCESS.md) — **read this first if you are a lane**
- **Current round:** [docs/LANES/ROUND1_INSTRUCTIONS.md](docs/LANES/ROUND1_INSTRUCTIONS.md)
## Run it
```bash
cd web && python3 -m http.server 8140
# http://localhost:8140 — the game
# http://localhost:8140/?stub=1&dbg=1 — stub world + debug HUD (works from day 0)
```
No bundler, no npm, no build. ES modules + import map; three.js r175 vendored in `web/vendor/`
(never CDN — the game must run offline). Before you finish a session: `bash tools/qa.sh`.
## The one-paragraph tech pitch
The whole canal is a **spline**. World position is `(s, θ, ρ)` — distance along the canal,
angle and radius in the cross-section. Tube walls are chunked extrusions along
parallel-transport frames; peristalsis and breathing are **vertex-shader displacement**
(cheap, squishy, everywhere); collision is an analytic radius test (no physics engine).
Caverns (mouth, stomach) switch the same controller to free 6DOF. Look is **synthetic
scanner** — dark endoscope void, SEM-style monochrome walls with FLUX-generated detail
textures, emissive-coded enemies. Everything is seeded + deterministic, and every asset is
optional at runtime — the game boots and plays asset-free with procedural fallbacks.
## Hard laws (all lanes)
1. **Determinism.** No `Math.random` outside `js/core/rng.js`. Seeded RNG only. qa.sh greps.
2. **Assets are optional.** Missing texture/model/audio ⇒ procedural fallback, never a crash.
3. **Eyeball everything.** Visual work isn't done until a screenshot is in `docs/shots/laneX/`.
4. **Perf budget:** ≤300 draw calls, 60 fps on M-series / mid laptop. Measure via `window.DBG`.
5. **Free-first.** Local MODELBEAST generation before any paid API; fal.ai is a gated fallback
(John's go). See PIPELINE.md.
6. **Git:** stage only your exact paths, commit + push each session, never `git add .`.
## Deploy
**Live: https://partly.party/gutsy/**`bash tools/deploy.sh` (QA gate → rsync `web/` minus
`dev/``docker cp` into `forum-nginx` → verify). No build step; `web/` ships as-is.
Two things to know before you touch it, both documented at length in the script header:
- **It's ephemeral.** Content lives in the container's own layer (like blobbo/glytch), so a
`docker compose up --force-recreate` or nginx image bump wipes it — re-run the script. The
durable fix is a bind mount in `forum/docker-compose.yml` (what cratewars/roguelike use),
which costs a forum-nginx recreate and brief partly.party downtime.
- **A 404 there returns HTTP 200.** nginx's catch-all `try_files ... /index.html` serves the
arcade index for any missing file. Verify on content, never on status codes.
Origin: `ssh://git@100.71.119.27:222/monster/guts.git`.