SPRINT10 gate 1a, carried since Sprint 8. Everything that was a module constant
— bed rect, house line, tree and post placements, shed, gnome, sun angle, fence
sides — is now data/sites/backyard_01.json, and world.js is a builder.
The extraction is byte-identical, and that's checkable rather than claimable:
E's branch-anchor tripwires pin five positions to 6 dp, a.test's quad-band
asserts pin the whole rigging geometry (>=3 quads in 18-45 m2, full coverage
still >45 m2), D's ladder field and B's balance lines all pass unchanged.
287/0/0.
It's byte-identical by construction, not by luck: the site-derived values keep
the builder's original local names, so ~500 lines of geometry that was already
correct is untouched and only its SOURCE changed.
Two things earned their place:
Anchors carry D's `work: "cloth" | "bracket"` — the MECHANISM, not the type. A
post is tensioned from a cleat at its base and a tree strop is thrown, but a
bracket bolted up a bare wall is the one you cannot fake. Keyed on mechanism
because `type` is a closed enum ('house'|'tree'|'post') that site_02's carport
doesn't fit, and needsLadder keyed on type FAILS OPEN there — the ladder
silently vanishes and you re-rig a 2.6 m bracket standing on the grass.
p4's swept position table moved INTO the JSON's `_why`, beside the coordinate it
justifies. That table is the only thing stopping someone nudging the post toward
the bed and collapsing DESIGN.md's central tension; it belongs with the number,
not in a file the number left.
validateSite() fails loud: sites are content, and a missing bed silently becomes
NaN coverage while a missing anchor list silently becomes an unriggable site.
createWorld now requires a site and says so.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
87 lines
3.6 KiB
JSON
87 lines
3.6 KiB
JSON
{
|
|
"id": "backyard_01",
|
|
"name": "The Backyard",
|
|
"blurb": "Your own place. You know where everything is, which is the only advantage you get.",
|
|
|
|
"yard": { "width": 30, "depth": 20 },
|
|
|
|
"sun": { "elevationDeg": 55, "azimuthDeg": -125 },
|
|
|
|
"gardenBed": { "x": 1, "z": 2, "w": 6, "d": 4 },
|
|
|
|
"house": {
|
|
"model": "house_yardside_v1",
|
|
"x": 0, "z": -10.5,
|
|
"anchors": [
|
|
{ "id": "h1", "node": "fascia_anchor_01", "type": "house", "work": "bracket" },
|
|
{ "id": "h2", "node": "fascia_anchor_02", "type": "house", "work": "bracket" },
|
|
{ "id": "h3", "node": "fascia_anchor_03", "type": "house", "work": "bracket" }
|
|
]
|
|
},
|
|
|
|
"trees": [
|
|
{
|
|
"id": "t1", "model": "tree_gum_01_v1",
|
|
"x": -9, "z": 2, "phase": 0.7, "trunkH": 4.2, "anchorY": 3.4,
|
|
"anchors": [
|
|
{ "id": "t1", "node": "branch_anchor_01", "type": "tree", "work": "cloth" },
|
|
{ "id": "t1b", "node": "branch_anchor_02", "type": "tree", "work": "cloth" },
|
|
{ "id": "t1c", "node": "branch_anchor_03", "type": "tree", "work": "cloth" }
|
|
]
|
|
},
|
|
{
|
|
"id": "t2", "model": "tree_gum_02_v1",
|
|
"x": 8, "z": -2, "phase": 2.9, "trunkH": 3.8, "anchorY": 3.1,
|
|
"anchors": [
|
|
{ "id": "t2", "node": "branch_anchor_01", "type": "tree", "work": "cloth" },
|
|
{ "id": "t2b", "node": "branch_anchor_02", "type": "tree", "work": "cloth" }
|
|
]
|
|
}
|
|
],
|
|
|
|
"posts": [
|
|
{ "id": "p1", "x": -4.5, "z": 5.5, "h": 4.0, "type": "post", "work": "cloth" },
|
|
{ "id": "p2", "x": 4.0, "z": 6.0, "h": 4.0, "type": "post", "work": "cloth" },
|
|
{ "id": "p3", "x": 0, "z": 7.0, "h": 4.0, "type": "post", "work": "cloth" },
|
|
{
|
|
"id": "p4", "x": -3.2, "z": -1.2, "h": 4.0, "type": "post", "work": "cloth",
|
|
"_why": [
|
|
"DO NOT move this post toward the bed. Its position is swept, not chosen, and it is the",
|
|
"single number holding DESIGN.md's central tension open.",
|
|
"",
|
|
"Before p4 the wild night had NO winnable line, for a geometric reason: every anchor near",
|
|
"the bed (p1/p2/p3) is SOUTH of it and nothing stands north short of the house 10 m away,",
|
|
"so covering rigs had to span the yard and died while rigs small enough to survive sat",
|
|
"beside the bed rather than over it. p4 supplies the missing north-west corner.",
|
|
"",
|
|
"Swept against the smallest quad covering 90% of the bed:",
|
|
" (-2.2, -1.2) -> 44.4 m2 DO NOT: full coverage lands INSIDE the survivable band,",
|
|
" so covering the bed stops costing risk and the rigging",
|
|
" puzzle loses its wrong answers.",
|
|
" (-3.2, -1.2) -> 48.6 m2 <- here (with the 8 deg rake the top anchor lands at",
|
|
" -3.72,-1.40 and full coverage costs 51.6 m2)",
|
|
" (-3.2, -2.0) -> 51.7 m2",
|
|
" (-4.2, -3.0) -> 60.0 m2",
|
|
" beyond z=-4 -> 63.5 m2, i.e. too far out to matter at all",
|
|
"",
|
|
"Full coverage costs 63.5 m2 without it and 51.6 with: a real new option, still bigger",
|
|
"than the 23-38 m2 rigs that survive unaided. a.test.js asserts the >45 m2 floor, so",
|
|
"moving this inward goes red — that assert is the tension's only guard."
|
|
]
|
|
}
|
|
],
|
|
|
|
"shed": { "model": "shed_01_v1", "x": 11.8, "z": 6.2, "rotYDeg": -90 },
|
|
"shedTable": { "model": "shed_table_v1", "x": 9, "z": 6, "rotYDeg": -90, "pickupNode": "pickup_anchor" },
|
|
|
|
"gnome": { "model": "garden_gnome_01_v1", "x": 4.3, "z": 4.4, "rotYDeg": -126, "collateralValue": 25 },
|
|
|
|
"fence": {
|
|
"sides": ["south", "west", "east"]
|
|
},
|
|
|
|
"wind": {
|
|
"venturi": []
|
|
}
|
|
}
|