Commit Graph

9 Commits

Author SHA1 Message Date
m3ultra
4d4f2d7d7f Add carport_01 for site_02, and the pyrrhic end card
carport_01 is site_02's dressing and its whole design. DESIGN.md wants the
corner block anchor-poor, and the interesting way to build that isn't to give
the yard nothing — an empty yard is just a smaller yard. It's to give it
something that looks like four free anchors and isn't. Light posts on small
pads, a beam sized for one sheet of roofing: tie 25 m2 to it in a southerly and
you take the carport, not the shackle. Ships with the worst ratings in the game
(beam 0.22 vs the fascia's 0.35) and collateral="carport", pinned in e.test.js
below the fascia with the reason attached, so nobody quietly fixes them upward
and turns the site back into a small yard.

The pyrrhic card is the third outcome on the same camera: dawn, bed green, gnome
standing, sail post down across the yard behind him. Warm light on purpose — a
pyrrhic result is a win, and the wreckage is the price, not the verdict. Copy
goes to Lane A in THREADS; cardpreview renders all three.

277/0/0, Lane E 60 asserts, 39/39 output files byte-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 14:29:08 +10:00
m3ultra
f8710b56bc Sweep and taper the tree limbs; pin the anchors that ride them
Each limb was one straight uniform tube — a peg poking out of a pole, and the
most visible art problem in docs/yard_day.jpg. They now leave the trunk thick,
sweep up on a bezier and taper to nothing, which is what a gum does. +96 tris on
gum_01, silhouette bounds unchanged.

Nothing physical moved. The tip is a bezier endpoint and the four rng draws per
branch are the same four in the same order, so every branch_anchor_* is
bit-for-bit where it was — verified before and after, all five identical to 6dp.
Lane A's winning line rigs off t2 and is untouched; no balance number can shift.

e.test.js now hard-codes those five world positions as a tripwire, so no future
art change of mine can quietly invalidate a sprint of someone else's physics. If
it goes red, the art moved an anchor — fix the art, not the numbers.

Card text and the dawn-tint treatment go to Lane A in THREADS. The tint is a CSS
snippet rather than a ninth texture: only two of my eight are consumed, and a
full-screen gradient needs no asset at all.

Selftest 262/0/0, 38/38 output files byte-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 11:25:03 +10:00
m3ultra
4bb0efcfd1 Add the pond visual, the broom, and rename the snapped panel
Pond (SPRINT4 §E-1, decision 10): pond_water.png and pond_normal.png, for a
patch Lane B builds from the cloth's own nodes — same ride-the-nodes rule as the
tears, since a rigid disc would sit still while the belly moves under it. Alpha
is a radial feather and RGB darkens toward the centre, both encoded radially so
the shading survives being scaled per pondMass (radius ~ sqrt(mass)). Water is
grey-green, not blue: rain caught in a sail is shallow, murky and mirrors an
overcast sky.

Both at 256², not 512²: smooth low-frequency content, and at 512 they were
256 KB + 320 KB against ~20 KB for every other texture here. The chop is seven
waves at golden-angle directions rather than three crossed sines, which
interfered into a lattice and read as basketweave; the normal map gets six
integer-frequency waves for the same reason, and still asserts its own tiling.

broom_01 (§E-2): poke_tip sits on the bristle end deliberately — a broomstick
jabbed at a loaded sail holes it.

Renames fence_panel_broken to fence_panel_snapped to match SPRINT4 §A-4/§E-3.
Lane A's dress() guards every load, so the mismatch would not have crashed —
the wreckage would silently never have appeared, which is worse.

All 21 assets pass, 33 output files byte-identical across two runs, 186/0/0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:27:55 +10:00
m3ultra
fccbeb9319 Add aftermath wreckage props and verify glTF extras survive
The aftermath screen needs something to point at (SPRINT3 §Lane E-2).
garden_gnome_01_broken snaps at the ankles with the base left where the player
last saw him, head rolled clear with the beard still on, hat off — recognisably
him rather than a shattered pile, because wreckage nobody can identify is just
gravel. fence_panel_broken loses a few palings and hangs one off a nail; most of
it stays standing, which is what makes the hole read as damage rather than as a
design choice. Both keep their intact twin's origin and ground plane so Lane A
swaps mesh-for-mesh with no offsets, asserted both ways.

Also asserts something claimed since Sprint 1 and never checked: that glTF
extras reach three's userData. They do — the gnome's collateral_value, the
canopy's sway_amp, branch_anchor rating_hint and the bin's mass_hint all arrive
as numbers. Had that silently dropped, Lane A's gnome would score $0 and every
anchor would rate identical, which reads as a gameplay decision rather than a
missing field.

Contact-sheet framing now keys the capsule off height, not max(dims): the broken
gnome is 0.39 m across but stands 0.11, so spread-based framing buried it the
same way it once buried the shackle.

Selftest 175/0/0, 30 output files byte-identical across two runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:24:19 +10:00
m3ultra
af2694257a Regenerate the full contact sheet; fill unused tiles
The --only runs during the sprint left a partial sheet committed. Also fills the
empty slots in a partly-filled last row with the background sampled from a
tile's corner, so 19 assets in a 4x5 grid no longer leaves a black hole. The
world colour can't be reused for this — the render is sRGB-encoded, the scene
value is linear.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 00:57:38 +10:00
m3ultra
0f5f4d8368 Make rake_pivot a real pivot; log Sprint 2 in THREADS
rake_pivot shipped as a childless empty, so rotating it moved nothing — and
rotating the whole GLB instead, which is the only alternative, tips the concrete
footing out of the ground along with the post. DESIGN.md makes raking away from
the load a player decision, so the handle has to actually work.

It now holds post + pad_eye + top_anchor, with footing left on the root: rake it
8° and the post leans while the concrete stays planted. Asserted both directions
in e.test.js — the head must travel over 0.3 m and the footing under 0.01.

Same class as the canopy bug, found the same way: by driving the handle in a
test instead of eyeballing the model. Exported dims unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 00:56:15 +10:00
m3ultra
d3e849fcc3 Add sail cloth textures and the storm dressing set
Textures (SPRINT2 §Lane E-2). sail_weave.png is a seamless 512² knitted
shade-cloth weave with the stripe banding real cloth has; the script proves the
wrap by evaluating a second tile and requiring an exact match, because Lane B is
being told to set RepeatWrapping and a bad wrap would seam across the whole
sail. Luminance rides in a narrow band so it multiplies the base colour instead
of replacing it — high contrast reads as burlap, not HDPE. Dropped the per-pixel
noise: invisible at ±0.012 and incompressible, it cost 305 KB of the 323.

sail_tears.png is a strip of 4 escalating rips. Each is a lens, not a slit —
fabric under tension parts widest in the middle and tapers to a point, and a
constant-width gap reads as a drawn line. Threads bridge the gap, scaled to the
local width; without them a dark lens is a hole rather than a tear.

Dressing (§Lane E-3): wheelie_bin_01 (240 L, 12 kg, `lid` on its own node so it
flaps before the bin goes over), washing_line_01 (a Hills Hoist — the `head`
freewheels, giving a second wind tell at head height), garden_gnome_01
(collateral bait: a smashed gnome reads where a damage number doesn't).

Bin and tramp land in models/debris/ for Lane C to glob. All 19 assets pass, 28
output files byte-identical across two runs, selftest 129/0/0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 00:51:51 +10:00
m3ultra
7cd25a5d2a Give the gum trees a canopy sway handle
world.js sways a tree by rotating a `canopy` group whose origin sits at the
trunk top, so the blobs swing about the trunk. The trees shipped canopy_01..03
as siblings of `trunk` with each origin at its own blob centre — rotating one
spins a sphere in place, which is visually nothing. Lane A could not have swayed
these trees, and the canopy lean is the gust telegraph the player reads a beat
before it hits the sail, so the tell would have gone missing rather than looked
wrong.

Adds the `canopy` empty at the trunk top with the blobs parented under it, so
A's existing code works unchanged, plus sway_amp / sway_phase / sway_pivot_y
for the per-tree tuning SPRINT2 §Lane E asks for (gum_01 is big and leans less
at 0.85; gum_02 is whippy at 1.20 and shows a gust first).

sway_phase draws from its own RNG stream: taking it from the shared one would
consume a value and shift every blob draw after it, resilhouetting a tree the
other lanes have already tuned against. Exported dims are identical to Sprint 1.

e.test.js asserts the pivot by rotating the handle and measuring that a blob
actually travels — red before this change, green after.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 00:42:30 +10:00
m3ultra
3815055678 Add generated yard, hardware and debris GLBs
16 generated assets plus the grass billboard atlas and the four debris models
copied verbatim from the 3D-STORE library (copies rule, §0). All meter-scale,
Y-up, and far under the 15k tri budget — garden_bed is heaviest at 2,580.

Regeneration is byte-deterministic: two consecutive runs produce identical
files, so re-running the factory causes no churn.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 21:39:52 +10:00