Level lakes at the end of world generation, keeping their water (t96)

Volume-preserving levelling pass for water bodies of 50+ cells; the dock foundation is placed
first so it cannot erase levelled water. Seed hashes re-baselined (water and air only).
Started by Codex, finished and reviewed by Claude after Codex hit its usage limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-29 19:28:23 -04:00
co-authored by Claude Opus 5.5
parent 75d4e8ee4e
commit ae78756fa2
10 changed files with 227 additions and 50 deletions
+9 -6
View File
@@ -590,12 +590,15 @@ above, including:
ordinary repose rules take over. Keep stamped moves, barriers, burning-bed protection and
worker independence. The existing worldgen POWDER_FAN switch disables new face releases.
- **New-world lakes wake immediately; keep the seed layout (t96, 2026-10-29).** Keep the
recorded worldgen settling speeds and material/temperature output. Wake water after the
final startup reset so unfinished lakes level without drilling. Retain tree candidates and
their random draws, then omit whole trees whose bases are wet or on an open bank connected
to water at base height after settling. This keeps trees out of the lake as it spreads.
Existing load wake scheduling and later snowmelt/flooding rules stay as they are.
- **Level lakes during world generation (t96, 2026-10-29).** The owner wants new worlds
to start with flat lakes instead of waiting 80–125 seconds for them to flow level. Changed
generated worlds are accepted: seeds no longer reproduce the old water layout. After the
existing settling loop, level four-connected water bodies of at least 50 grains, preserving
their exact volume. Fill reachable air/water from the bottom upward, respecting solid/powder
walls and dry rims; place a partial top row from the middle outward. Establish the dock's
existing foundation first so it cannot erase newly levelled water. Keep the pinned settling
values, startup water wakes, and round-1 wet/water-connected-bank tree filtering. Existing
load wakes and later snowmelt/flooding rules stay as they are.
## Ideas not built yet
+10 -8
View File
@@ -322,9 +322,9 @@ Bars and other loose objects (ents), and the bag: adding, taking, costs and refu
- functions: entSolidCell, entSupportCount, entFreeAt, entMark, spawnBar, removeEnt, entScrewAt, entScrewFree, entScrewMove, entScrewLane, entScrewEdge, entScrewEnter, entScrewTick, entDiagonalScrewTick, entBeltScrewEnter, entSlopeBeltTick, entTick, entsInCircle, bagAdd, bagTake, giveOrDrop, refundAt, canAfford, payCost, fmtMoney, costText, needText
- variables: BAR_W, BAR_H, entCurM, droppedLast
### src/sim/tools.js (65 lines)
### src/sim/tools.js (30 lines)
Tool helpers: reach, brushes, and plain digging.
- functions: setBuildRange, inBuildRange, inReach, forBrush, drillReach, inDrillReach, toolDig
- functions: setBuildRange, inBuildRange, inReach, forBrush, drillReach, inDrillReach
- variables: BUILD_MAX, buildBox
### src/sim/drill.js (183 lines)
@@ -378,12 +378,12 @@ The same chunk schedule runs inline or in workers. Workers only own a pass at a
simTick: one simulation step, in order.
- functions: simTick
### src/sim/worldgen-helpers.js (61 lines)
### src/sim/worldgen-helpers.js (131 lines)
World generation helpers: noise and removal of tiny hard rock specks.
- functions: makeNoise, fbm, clearHardSpecks
- functions: makeNoise, fbm, clearHardSpecks, levelWorldWater
- variables: SPECK_MIN
### src/sim/worldgen.js (303 lines)
### src/sim/worldgen.js (305 lines)
World generation: staged terrain, ore, caves and placement, with synchronous and async entry points.
- functions: generateWorld, generateWorldAsync
@@ -397,9 +397,9 @@ Saving and loading a world (serializeWorld / deserializeWorld) and old-save migr
- functions: serializeWorld, deserializeWorld, startLoadWake, wakeLoadArea, wakeLoadNearBot, loadWakeTick
- variables: SAVE_VERSION, TOFF
### src/render/setup.js (190 lines)
### src/render/setup.js (188 lines)
Drawing (src/render/): browser only. This file: the renderer state R, colour tables (glow, thermal palettes, pipes, trees, sky), canvas setup and the camera.
- functions: glowIndex, thermIdx, pipeCellColor, pipeBodyCell, thinPipeColor, beltLike, buildSky, initRender, resizeRender, viewCells, updateCamera, snapCamera, screenToWorld, worldToScreenPx, renderMonoFont
- functions: glowIndex, thermIdx, pipeCellColor, pipeBodyCell, thinPipeColor, buildSky, initRender, resizeRender, viewCells, updateCamera, snapCamera, screenToWorld, worldToScreenPx, renderMonoFont
- variables: R, GLOW_W, GLOW_R, GLOW_G, GLOW_B, THERM, PC, TREE_R, TREE_G, TREE_B, BG, SKY_R, SKY_G, SKY_B
### src/render/slope-belts.js (167 lines)
@@ -664,7 +664,9 @@ The frame loop and boot.
- `test/t_gpu_light.py`: The former CPU light behavioural checks, now read from the actual GPU light grid.
- `test/t_import_save.js`: Import must preserve the running world before reading or replacing it.
- `test/t_joins.js`: The oracle states the geometric rule independently of the precomputed neighbour tables.
- `test/t_lakes.js`: Generated lakes wake without a tool, settle on their own, and have dry tree bases.
- `test/t_lakes.py`: Pixel startup and fresh/reloaded flat lakes after 600 ticks; shots/t96-level.png.
- `test/t_lakes.js`: Generated lakes start flat, conserve water, and have dry tree bases.
- `test/t_lakes.py`: t96: flat generated lakes, fresh and reloaded, in the real pixel frame loop.
- `test/t_load.js`: Reload wakes nearby areas first, without losing distant water, fire or saved state.
- `test/t_molds.js`: Molds and furnaces stay usable: ingots drop below and keep their stubs, plugs over molds are cleared, spoiled castings can be knocked out, grains never drop through a grate by teleporting, and slag lets the fire breathe.
- `test/t_nozzle.js`: Blowing aims within the nozzle's reach, with room for the brush and settling.
+8 -3
View File
@@ -76,9 +76,14 @@ The conveyor fixture uses a wider feed pile, the screen fixture warms longer, an
checks waking within eight ticks separately from the probabilistic consumption of fuel.
`test/t_lakes.js` pins SHA-256 over raw `mat` followed by Float32 `temp` bytes for seeds
7, 42 and 424242 at 2048x1024. These hashes predate t96 and must not be re-baselined for a
wake/background-tree change. It also checks generated tree bases, startup wakes, and the
seed-7 lake leveling within two grains after 6,000 undisturbed ticks, fresh and reloaded.
7, 42 and 424242 at 2048x1024. t96 round 2 re-baselines only for the lake-levelling pass;
`t_corner_seal.js` also pins three smaller worlds with the same intentional change. The lake
suite checks all five seeds (also 2 and 1): surface pools wider than 20 grains start within
one grain of level and stay so after 600 ticks, exact WATER count from the pre-pass 0.99
progress callback, dry tree bases and startup wakes. Small fixtures cover solid/powder rims,
volume, centered partial rows, the 50-grain cutoff and diagonal separation.
`python3 test/t_lakes.py` checks pixel startup and fresh/reloaded lakes after 600 ticks with
two browser helpers and no page errors; `shots/t96-level.png` shows the untouched new lake.
`test/t_bot_rescue.js` covers deep basalt burial, nearest/upward and diagonal nudges,
unexplored-pocket rejection, newest open trail points, ring wrap/load reset, bounded searches,
+20
View File
@@ -4,6 +4,26 @@ What agents have done, newest first. Add an entry for every piece of work: the d
note or request it was for, what changed, the files touched, the tests run, and anything left
open or not verified. Keep each entry short; the git history has the details.
## 2026-10-29: t96 round 2 — level lakes during generation (Codex)
- Level 50+ grain water bodies with typed-array flood fills, exact volume and centered partial
rows; keep settling switches, startup wakes and tree rules. Establish the existing dock
foundation first (otherwise seed 42 loses 39 grains). Recorded the owner's changed-seed decision.
- Files: src/sim/worldgen{,-helpers}.js, test/t_lakes.{js,py}, test/t_corner_seal.js,
docs/{DESIGN,TESTING,PROJECT_MAP}.md, tasks/t96* and this log.
- Eight regressions failed first; all 40 headless suites pass (59 lake checks). Six world hashes
re-baselined only for WATER/EMPTY redistribution; bypassing the pass restores all six originals.
Pixel browser fresh/reload seed 7 at 600 ticks passes with two helpers and no page errors.
Inspected shots/t96-level.png: flat lake, centered one-grain top row, dry bank trees, dock at right.
- Paired generation medians before→after (ms), seeds 7/42/424242: 871.09→903.88,
921.47→981.33, 1067.50→1119.16. Pass medians 13.67/22.17/15.27 ms; max 24.05
measured / 41.22 cold. Evidence: /tmp/t96-round2-{red,headless-final,browser,paired-times}.log.
Review pending; no full browser suite, no commit.
- Claude finished the run after Codex hit its usage limit: registered test/t_lakes.py in run_all.py's
browser list; full `run_all.py --browser` passed except the known flaky t_smooth.py (t99), which
passed 3/3 reruns. Found that 4 of 12 seeds' levelled lakes now reach the trade dock's wall
(none enter it); cause is the lake lip using the highest rim point (see t96).
## 2026-10-29: t69 hot-load warning, visible damage and build-over repair (Codex)
- Added persistent scorched/fractured screw overlays in both looks, 900°C load warnings,