Go to file
type-two 00e6b288c8 Lane E S18 gate 4: THE GLASSHOUSE TIER — the hail-net frame, and the apex made reachable
S16 shipped the glasshouse and priced it at $320. e.test said the rest in its
own words: "nothing in the sim wrecks a glasshouse yet — the value is inert
data". main.js bills collateral off a broken rig corner's baked key, and a
glasshouse rightly offers no anchors, so the most expensive object in the game
could not cost anybody a cent — RULE 2's mirror image, a price with no key that
can reach it.

DESIGN.md line 179 named the missing asset: hail nets rigged OVER glass. You
tie to the frame that straddles it. hail_net_frame_01 / _wrecked: a powder-coat
portal frame clear of the glasshouse on all four sides, head at 2.75 m to clear
the 2.28 ridge, four welded eyes at 2.690 baking collateral 'glasshouse'.

The tell is a POSITION, not a defect — the frame's numbers are good and the
hazard is where it stands. Pinned as geometry off two GLBs (footprint strictly
contains the glass; head clears the ridge) rather than as paint on one. The 20 m
read is metalness: powder-coat at 0.05 renders bright where every trusted
galvanised steel at 0.90 goes near-black with no environment map (S17's measured
lesson, applied on purpose this time).

Rung 0.80, proposal, A rules: it earns the highest rung below the honest post
(engineered frame, four footings, the only structure built to be tied to) and is
de-rated 20% for section, not condition. It usually holds — that is the tier:
the corner failure that costs a shackle on a sail post costs $320 here.

The root deliberately carries NO collateral_key. structFor() takes the first
match, so a frame claiming the glass's key would bill the panes and wreck the
frame, both papers agreeing and both wrong. That omission is gate 5 in one line.

Wreck racks at one end (0.45 in at the head, 0.45 out at the feet) after the
first cut still read as a clean level rectangle in the render. Carries no glass:
the glasshouse swaps independently. Unpriced by ruling.

ANCHOR_TYPE widened with 'hail_net_frame' (contracts.js is A's — revert and tell
me; corroded_post precedent). Manifest unambiguous: 0.80, glasshouse, 4 sources.

Determinism held: runs 2 and 3 are 56/56 byte-identical. NOTE the shipped GLBs
were exported by Blender 5.1.2 and this box has 5.0.1 — the 45-binary churn that
causes is semantically nil (60 nm accessor drift, PNGs losing sRGB/gAMA/cHRM
with identical pixels) and was reverted, not shipped. Documented in the header.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 19:45:42 +10:00
.claude Sprint 11 integration: merge all lanes, wire leadFor + setBudget, untrack launch.json; Sprint 12 plan + prompts 2026-07-17 18:08:32 +10:00
docs assetcheck/look.html: the verify that answers "is this the right shape" 2026-07-18 16:01:39 +10:00
prototype Add side-systems to design doc + playable sail-storm prototype 2026-07-16 20:55:31 +10:00
tools Lane E S18 gate 4: THE GLASSHOUSE TIER — the hail-net frame, and the apex made reachable 2026-07-25 19:45:42 +10:00
web/world Lane E S18 gate 4: THE GLASSHOUSE TIER — the hail-net frame, and the apex made reachable 2026-07-25 19:45:42 +10:00
.gitignore Sprint 11 integration: merge all lanes, wire leadFor + setBudget, untrack launch.json; Sprint 12 plan + prompts 2026-07-17 18:08:32 +10:00
DESIGN.md Add side-systems to design doc + playable sail-storm prototype 2026-07-16 20:55:31 +10:00
LANE_PROMPTS.md SPRINT18 speced: John's ruling (declining costs you), the emergency callout, the glasshouse tier — lane prompts at the tail 2026-07-25 18:45:06 +10:00
PLAN3D.md Correct PLAN3D asset inventory; log M0 contract additions 2026-07-16 21:33:42 +10:00
README.md Merge origin/main: S14 lane integration + review fixes; TEETH becomes SPRINT16 2026-07-19 10:34:21 +10:00
ROADMAP.md Merge origin/main: S14 lane integration + review fixes; TEETH becomes SPRINT16 2026-07-19 10:34:21 +10:00
server.py Vendor three.js r175, add stdlib dev server and launch config 2026-07-16 21:33:42 +10:00
SPRINT2.md Add Sprint 2 assembly instructions: wire proven modules into one playable storm 2026-07-16 22:24:35 +10:00
SPRINT3.md Add Sprint 3 plan and lane prompts: close the game loop 2026-07-17 01:11:16 +10:00
SPRINT4.md Add Sprint 4 plan and lane prompts: face and water 2026-07-17 02:03:47 +10:00
SPRINT5.md Add Sprint 5 plan and lane prompts: hail and the broom 2026-07-17 02:44:30 +10:00
SPRINT6.md Add Sprint 6 plan and lane prompts: winnable, then a week of nights 2026-07-17 08:54:02 +10:00
SPRINT7.md Add Sprint 7 plan and lane prompts: one truth, then the week 2026-07-17 09:48:23 +10:00
SPRINT8.md Add Sprint 8 plan and lane prompts: ship the week 2026-07-17 11:57:51 +10:00
SPRINT9.md Add Sprint 9 plan and lane prompts: pyrrhic call, $80 win, second site 2026-07-17 14:03:45 +10:00
SPRINT10.md Add Sprint 10 plan and lane prompts: sites are data 2026-07-17 15:12:55 +10:00
SPRINT11.md Add Sprint 11 plan and lane prompts: prove the corner block, then the job sheet 2026-07-17 16:44:11 +10:00
SPRINT12.md Sprint 11 integration: merge all lanes, wire leadFor + setBudget, untrack launch.json; Sprint 12 plan + prompts 2026-07-17 18:08:32 +10:00
SPRINT13.md QA pass: fix Enter storm-skip (deployed), log findings; Sprint 13 plan + prompts 2026-07-17 23:26:47 +10:00
SPRINT14.md Sprint 14 plan + prompts: the yard editor — sites are makeable 2026-07-18 14:50:26 +10:00
SPRINT15.md Merge origin/main: S14 lane integration + review fixes; TEETH becomes SPRINT16 2026-07-19 10:34:21 +10:00
SPRINT16.md Merge origin/main: S14 lane integration + review fixes; TEETH becomes SPRINT16 2026-07-19 10:34:21 +10:00
SPRINT17.md Sprint 17 plan + prompts: the book of clients pt 1 — the board; John's seven-night ruling recorded 2026-07-21 00:09:22 +10:00
SPRINT18.md SPRINT18 speced: John's ruling (declining costs you), the emergency callout, the glasshouse tier — lane prompts at the tail 2026-07-25 18:45:06 +10:00
THREADS.md [I] John's ruling (declining costs standing), S18 speced, two-integrator convergence recorded — 522/0/0 2026-07-25 18:51:08 +10:00

HARD YARDS — rig it, then survive the night

(repo/product history: the project was codenamed SHADES through Sprint ~8; the shipped game is HARD YARDS. Internal docs and the gitea repo name still say shades — that's the same thing, not a second game.)

Geometry/tower-defense: you're a small person rigging shade sails against Australian storms. three.js r175 (vendored, no build step) + a zero-dep Python server. Everything the repo needs is in the repo.

Run it

python3 server.py --port 8801     # any free port
# game:     http://localhost:8801/web/world/index.html
# selftest: http://localhost:8801/web/world/selftest.html   (must be all green)
# 2D proto: http://localhost:8801/prototype/index.html      (the original thesis)

No pip, no npm, no build. Python 3.8+ and a browser.

Read in this order

  1. DESIGN.md — the design canon (what the game is)
  2. PLAN3D.md — the build canon (stack, contracts, lane model) · docs/MANUAL.md — the HOW: tool map, asset/site cookbooks, earned gotchas · ROADMAP.md — the growth canon (the arcs from the week to the business)
  3. THREADS.md — the append-only lane log. The project's memory. Read the last few [I] integrator entries to know the current state.
  4. SPRINT15.md — the current sprint (highest-numbered fired sprint wins: SPRINT16 is pre-speced TEETH and fires only when 15 integrates — its own header says so)
  5. LANE_PROMPTS.md — copy-paste prompts per lane, per sprint (bottom = newest)

The lane model (how this repo is built)

Five parallel Opus agents ("lanes"), each in its OWN clone, on its own branch:

lane owns
A main.js, world.js, camera, hud, week, sites, server — shell & integration, merge shepherd
B sail.js, rigging — cloth sim, economy, balance.test pen
C weather, skyfx, debris, storm/site wind data
D player, interact, ladder, broom — and the designated playtester
E Blender asset factory (tools/blender), models/, textures

Hard rules (they exist because each was earned — see THREADS):

  • One clone per lane. Never two agents in one working tree.
  • Rebase onto latest main before starting; small commits; push your branch.
  • File ownership is the merge strategy; cross-lane needs go in THREADS.md.
  • Selftest green after every landing. Skips must be real. An assert that cannot fail is decoration.
  • All sim code is deterministic (dt, t) — no Date.now, no rAF.
  • Measure, don't reason: the repo's biggest bugs were all "a number gathered from the wrong harness". When two harnesses disagree, find the variable.

Setup on a new machine

Gitea's SSH runs over tailscale (the public host is Cloudflare-proxied, no direct SSH). Add to ~/.ssh/config:

Host gitea.partly.party
    HostName 100.71.119.27
    Port 222
    User git

Then:

git clone git@gitea.partly.party:monster/hardyards.git ~/Documents/shades
for L in A B C D E; do
  git clone git@gitea.partly.party:monster/hardyards.git ~/Documents/shades-lane$L
  git -C ~/Documents/shades-lane$L checkout -B lane/$(echo $L | tr 'A-Z' 'a-z') origin/lane/$(echo $L | tr 'A-Z' 'a-z')
done

~/Documents/shades is the integration checkout (main; where merges and sprint docs happen). The five shades-lane* clones are where lane agents run.

Per clone, once: cp .claude/launch.example.json .claude/launch.json and pick a port of your own (integration 8823, lanes AE 88248828). The real launch.json is untracked — six checkouts on one laptop can't share one port.

Sprint cycle

  1. Fire lanes with the newest prompts at the bottom of LANE_PROMPTS.md (Lane A usually first if the sprint gives it rulings/blocking items).
  2. Lanes work, push their branches, log in THREADS.md.
  3. Integrate in the main checkout: merge origin/lane/{e,c,b,d} (THREADS.md conflicts resolve keep-both-chronological; real code conflicts get read), run selftest, play the result, write SPRINT(n+1).md + prompts, push main AND fast-forward all five lane/* branches to main.