# Agent log What agents have done, newest first. Add an entry for every piece of work: the date, which 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-23: build menu hover popup, top-left card hidden while building (Claude Code, with Codex) Notes: "mouse hover reviels a new info popup…" and "dont need the short description in the build menu…". The owner chose to hide the top-left card entirely while building. - `src/ui/build-menu.js`: `#bb-pop` above the hovered tile (icon, name, cost, size, power, full description, how to place, filter help, build keys), clamped to the window; on a gamepad it shows for the selected tile. The `.bb-tip` row became `.bb-status`: variant (material, direction, filter) chips, Replace · Ctrl, ghosts waiting, and status messages. The bar now updates its parts separately so hovering doesn't rebuild the tiles. - `src/ui/selection.js`: `#selcard` is hidden for the build tool unless copying, cutting or pasting; the build branch moved to the bar. `src/styles/style.css`: popup and status styles; on narrow screens the bottom-right panel moves up while building. - `src/ui/notebook.js`, `docs/DESIGN.md`, `docs/PROJECT_MAP.md`. - Tests: `play.py` 118 checks (popup on hover, switching tiles, hidden on leave, gamepad, no `.bb-tip`, card hidden while building and back for tools 1 and 2, status in the bar; the Ctrl replace check now reads the bar). All 11 headless suites pass. `t_smooth.py`'s half-resolution check is still flaky under load (~4.8): 1 pass in 3 runs, as before. - Screenshots in `shots/` (build-popup-*) at 1280×800 and 900×700 in both looks. - Open: at 900px wide the bottom-left hover-info panel sits partly under the build bar. ## 2026-10-23: a backed-up heap on a belt no longer shears (Claude Code, with Codex) Note: "belts with a big pile on top only move the grains on the top of the stack…". The owner's setup: a belt ending in a screw tube going up; material mixed into the bottom layers never moved. - Cause: `carryColumn` (`src/sim/conveyors.js`) skipped a blocked grain and carried on up the column, so with the front backed up the top slid over a stuck bottom. Reproduced headlessly first: over 4,000 ticks, 8,815 shear steps at the tube (1,415 against a wall) and only 57 of 192 bottom sand grains left the belt. - Fix: on a belt, the walk stops at the first blocked powder grain, so the load above stands still. On a filter the walk goes on only so chosen materials can still drop through; nothing above a blocked grain is carried. After: no shear, 119 of 192 sand grains out through the tube. - `test/t_conveyors.js`: 3 new checks (no shear into an up tube, none against a wall, bottom layer leaves through the tube). `tools/scenes/belt-heap.js` sets up the owner's case for `tools/shot.py`; shots at 30 and 900 ticks look right. `docs/DESIGN.md`, `docs/PROJECT_MAP.md`. - Tests: all 11 headless suites and `play.py` (109) pass. `t_smooth.py` failed its half-resolution check once at load 6.5 and passed on the rerun. - Open: `t_smooth.py`'s half-resolution check is flaky on a busy machine (the game drops to pixel when frames are slow). It is worth making that test immune to the slow fallback. ## 2026-10-23: ingots drop out of the bottom of the mold (Claude Code, with Codex) Note: "copper bars go into the furnace. also they shouldnt require the player to press F…". The owner confirmed the first part was a bug: the knock-out threw bars up into the furnace. - `src/sim/molds.js`: `ejectIngot` runs from `checkMolds` (every 15 ticks). Bars spawn directly under the mold, only where `entFreeAt` says there is room; the rest wait in the trough. Metal is taken from the top so the short stub stays on the floor. `ingot_drop` and `ingot_blocked` events (blocked is said once per spell via `mo.blockedSaid`, not saved). F on a ready ingot never launches bars upward; F on an empty, short or spoiled mold still cleans and rakes. - `src/ui/events.js`: first drop gets a card, later drops a toast; blocked gets a toast. Ingots no longer emit `cast_ready`. - Text: `pieces.js`, `progress.js`, `notebook.js`, `info.js`, `docs/DESIGN.md` (with the decision), `docs/systems/stone-and-liquids.md`, `docs/PROJECT_MAP.md`. - Tests: `t_molds` (38 checks: downward drops, stub kept, top-up, blocked and warned once, partial drops, full entity pool, slag), `t_basics`, `t_stone`, `furnace_play.js` and `play.py` section 6 changed to the new behaviour. All 11 headless suites, `play.py` (109) and `t_smooth.py` (8) pass. A shot of a mold with a belt one block below shows the bars riding off. - Open: a belt touching the mold's underside counts as blocked; bars need one open block. The owner may want a belt directly under the mold to work. ## 2026-10-23: Shift+Q/E build tabs, G pick key removed (Claude Code, with Codex) Notes: "add shift + q/e to move tabs" and "having the "g pick" there is confusing". - `src/ui/build-menu.js`: `selectBuildCat(c)` (shared with tab clicks) and `cycleBuildCat(d)`; the menu hint now reads Q/E cycle · Shift+Q/E tab. - `src/ui/input.js`: Shift+Q/E switch tabs with the build tool; G is unbound. - Text: build card (`selection.js`), notebook controls (`notebook.js`), `actions.js` comment, `docs/DESIGN.md`, `docs/PROJECT_MAP.md` (regenerated, `--check` passes). - `test/play.py`: checks for Shift+Q/E, wrapping, the remembered piece per tab, plain Q/E, and that G no longer calls pick while middle mouse still does (109 checks). - Tests: all 11 headless suites and `play.py` pass; a `tools/shot.py` shot of the Moving tab shows the new hint. `t_smooth.py` passes, but its "half-resolution smooth still draws" check failed on several runs with the 'slow' pixel fallback while the machine was busy (load ~14). The previous commit fails the same way under the same load, so this change didn't cause it. - Open: that check is timing-sensitive on a loaded machine; rerun it when the machine is idle. ## 2026-10-23: browser tests run locally (Claude Code, with Codex) Request: get the browser tests, Playwright and Chromium working on the owner's Arch machine (Python 3.14 refuses a system-wide pip install). - Playwright 1.64.1 and its Chromium 156 (revision 1248) are in an in-repo `.venv/` made with uv. - Added `tools/use_venv.py` and called it before Playwright imports in `tools/shot.py`, `tools/perf.py`, `tools/playthrough.py`, `test/play.py` and `test/t_smooth.py`. The `sys.prefix` guard prevents an exec loop if the venv lacks Playwright. - Updated `requirements.txt`, `.gitignore`, `README.md`, `AGENTS.md`, `docs/TESTING.md` and `docs/PROJECT_MAP.md` for Playwright 1.64.1 and venv setup. - Checks: regenerated the project map and ran `tools/map.py --check`. - Tests run with plain `python3`: `test/run_all.py --browser` all passed (11 headless suites, `play.py` 101 checks, `t_smooth.py` 8 checks) on the newer Chromium; `tools/shot.py` shots of the stone-uses scene look right in both looks. With `.venv` moved away, `play.py` exits with the setup message instead of a traceback. - Open: nothing. ## 2026-10-23: export from claude.ai to a local repository (Claude, in claude.ai) Request: split the source into small files, deduplicate and tidy a little, test fully, and write the notes, docs and agent instructions for local development. - **Source split.** - `core.js` (3,688 lines), `main.js` (2,012) and `render.js` (938) became 52 files in `src/sim/`, `src/render/` and `src/ui/`, each with a header line. The build order lives in `src/manifest.json`. - Checked that the joined code was identical to before, apart from comments and blank lines. - Every headless suite gave the same output, line for line, before and after. - Screenshots of two scenes, in both looks, were pixel-identical before and after (`tools/shot.py --freeze`). - **Tidying, behaviour unchanged.** - One scan loop in `simMove` instead of two mirrored copies. - A `drawHazardRims` helper replaced 3 copies. - The belt and filter shader code shares `beltLineSD`, `bandRidge` and `bandColor`. - Removed unused `refundCost`, `wakeArea`, `brushFor`, and the `PARTS` / `PART_BY_ID` aliases. - The suites share `suite()` (check / done) from the harness, and failures now set the exit code. - **Tests.** - Six broken old scripts were deleted; they used functions removed long ago. - Experiments and reports moved to `tools/experiments/`. - `t_v2` / `t_v4` / `t_v9` were renamed `t_basics` / `t_world` / `t_conveyors`. - Added `test/run_all.py`. - **Tools.** - `tools/shot.py`: repeatable screenshots of a scene set up in JavaScript. - `tools/where.py`: maps built-page line numbers back to source files. - `tools/map.py`: the project map's index. - `tools/scenes/`: example scenes. - The game skips cursor previews when `GAME.hidePreviews` is set, for clean screenshots. - **World files outside claude.ai.** - Pause → Export world file only worked inside claude.ai, through its downloads hook. - It now falls back to an ordinary browser download (`exportWorld` in `src/ui/saves.js`). - `test/play.py` checks that an exported file downloads and imports back on the title screen as the same world. - **Build.** `build.py` writes `dist/index.html` (a full page), `dist/deepgrain-foundry.html` (the same without the document wrapper, as the claude.ai artifact used) and `dist/bundle-lines.json`. - **Docs.** `AGENTS.md`, `CLAUDE.md`, `README.md`, `NOTES.md`, `docs/PROJECT_MAP.md`, `docs/DESIGN.md`, `docs/TESTING.md`, `docs/systems/*`, `docs/history/requests.md`. - **Tests run.** All 11 headless suites pass, as do `test/play.py` (101 checks) and `test/t_smooth.py` (8 checks). - **Open.** - The owner reports that big piles on belts still only move at the top (NOTES.md); not yet reproduced. - The game's last claude.ai artifact was version 24.