Go to file
type-two 975e1a4ec3 [lane B+C] The combo meter starts paying, allies stop counting as kills, and par stops
meaning "miss nothing"

Audit item 13 — the systems the levels were authored against, none of which worked.

THE COMBO MULTIPLIER DID NOT MULTIPLY. balance.js's own comment cites the GDD line "score x style
multiplier"; what shipped was a 2.5 s window and a counter. The HUD printed "x7 chain",
comms shouted about it at 5, the music added a layer at 3 — and combat/index.js added the flat
base score every time. Every par.score in every level was authored against a lever that did not
exist, which is exactly why they all sat at 75-94% of the un-multiplied ceiling. Now step 0.12,
cap 2.5 at a 14-chain: reachable in L4's ileum and nowhere else, because a cap you hit every
fight is not a skill expression. Verified in the running game: six chained floaters pay
100/112/124/136/148/160 where they used to pay 600 flat.

ALLIES COUNTED AS KILLS. combat/index.js did an unconditional score.kills++ on enemy:die, and
the ally branch of enemies.js emits enemy:die with score 0 — so shooting a lactobacillus reef,
the one act this game's whole reputation loop exists to punish, ticked your PATHOGENS tally up
by four. The pause card and the operative record told you that you were doing well at the exact
moment the biome decided otherwise. enemy:die carries `foe` now. Verified: seven deaths, six
kills.

THE PAR CHECK WAS COUNTING A THIRD OF THE GAME. scoreBudget() summed spawn events and nothing
else — not the 500 points a biopsy sample is worth, not the several thousand a boss puts in the
room. Four of six levels therefore shipped a permanent "par.score exceeds the kill budget"
warning, and a warning that is wrong two thirds of the time is one everybody learns to scroll
past. It counts pickups and boss rings now (nodes once per phase — a floor, since a phase
re-rings for as long as the fight lasts and no honest ceiling exists). Six levels, zero
warnings, and the ratios that were 94/75/52/59/44/32% of a fictional budget are now real.

AND THE CHECK THAT SHOULD HAVE CAUGHT L1. The only par test asked whether par exceeded the
ceiling. L1 sat at 94% of it: par the tutorial and you had to kill all eight foes, take all
seven orbs and all three samples — miss ONE sample and the medal was gone. That is a
clear-sheet requirement wearing par's clothes, in the level that exists to teach. par.score is
1900 now (71%), and the validator warns above 85% so the next one gets caught by a machine.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 22:19:34 +10:00
.claude [chore] Drop the throwaway preview ports 2026-07-25 22:52:08 +10:00
docs [lane B+C+F] The Appendix Sovereign: the secret boss, and a reputation you cannot fake 2026-07-25 23:25:36 +10:00
pipeline [lane A] MODELBEAST dresses the molecules: 5 matcaps, and the canal picks space-filling 2026-07-16 21:31:24 +10:00
tools [lane E+F] The game remembers you: a save file, a level select and an ending 2026-07-26 22:02:58 +10:00
web [lane B+C] The combo meter starts paying, allies stop counting as kills, and par stops 2026-07-26 22:19:34 +10:00
.gitignore [lane A] The swept room + the acid sea, built — and it corrected me four times 2026-07-16 18:04:16 +10:00
README.md [infra] GUTS is live at partly.party/gutsy — deploy wired, ship-check clean 2026-07-17 23:02:04 +10:00

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.

Run it

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.