Files
deepgrain-foundry/AGENTS.md
T
44r0n7andClaude Opus 5.5 cab9343b26 Run browser tests locally: Playwright 1.64.1 in .venv, scripts switch to it on their own
The browser tests and screenshot tools now work with plain python3 on a machine whose
system Python refuses pip installs: tools/use_venv.py re-runs them with the repo's .venv.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:50:15 -04:00

181 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Deepgrain Foundry: instructions for coding agents
Deepgrain Foundry is a 2D falling-sand factory game in the style of Sandustry, set in a
Terraria-like side-view world. Every grain of sand, ore, water and fire is simulated. The player
flies a small bot, digs with a resonance drill, vacuums up loose material, builds furnaces,
belts, tubes and machines from blocks, casts metal in molds and sells goods at a trade dock to
pay off a land claim. It runs in the browser as one self-contained HTML page, built from small
JavaScript files with no dependencies.
The owner (the user) directs the work and is the real playtester. You build, test and report.
## Start of every session
1. Read `NOTES.md`. It is the user's to-do inbox (see "Working from NOTES.md" below).
2. Read `docs/PROJECT_MAP.md` before searching the code. It says where everything lives. Its
index lists every top-level function and variable by file.
3. Before changing how the game plays, read the relevant part of `docs/DESIGN.md`. Many choices
were made deliberately and are recorded there with the reason.
4. Look at the top of `docs/agent-log.md` for what was done recently.
## Honesty and accuracy
These rules matter more than speed.
- **Do not guess or assume.** If you have not checked something, say so. Keep "I tested this and
it works" separate from "this should work".
- **Prove it with the game.** Run the tests. For anything visible, take a screenshot and look at
it before saying it looks right (see "Testing"). A passing test only covers what it checks.
- **Never invent names.** Look a function or variable up in the project map's index, or search
for it (`rg name src`), before you use it or talk about it.
- **When you are not confident, check more than one source.** Use the web for anything outside
this repository: browser APIs, Playwright, WebGL, real-world materials and temperatures,
physics, how other games do something. Confirm important facts with at least two independent
sources, and give the links.
- **Report problems plainly.** Say when a test fails, when something is only partly done, or when
you could not reproduce a problem. Never weaken or delete a test just to make it pass. If a
test's expectation is outdated because the design changed on purpose, update it and say why.
- **Ask when it matters.** If a request is unclear and getting it wrong would waste a lot of work,
ask first. If the choice is small or easy to undo, take the sensible reading, say which one you
took, and carry on.
## Working from NOTES.md
`NOTES.md` belongs to the user. They add notes at any time and ask you to work on them ("do the
notes", "do the belt note"). Work on notes only when asked.
- **Kinds of note.**
- Tasks ("add...", "make...", "fix...") are built.
- Discussion notes ("let's think about...", "brainstorm...", "what can we do about...",
"let's talk about...") get options with trade-offs and a recommendation. Do not build them
until the user decides.
- Questions get answers.
- **Keep the user's wording.** Never rewrite or tidy a note. If you need to add context, add a
sub-bullet that starts with `(agent)`.
- **When a task is finished**, move the note, word for word, into the "Done, please check"
section at the bottom. Under it, add an `(agent)` sub-bullet saying what changed and how to
check it in the game. Do not delete it: the user deletes it after checking. If the user says
it is not fixed, move it back up and add their feedback as a sub-bullet.
- **Log your work.** Add an entry at the top of `docs/agent-log.md` with the date, the note,
what changed, the files touched, the tests run, and anything left open.
- **Record decisions.** When the user decides something about the design, add it to the
decisions list in `docs/DESIGN.md` with the date and the reason they gave.
## Commands
```sh
python3 build.py # build dist/index.html from src/ (takes a second)
python3 -m http.server -d dist # play at http://localhost:8000 (or open dist/index.html)
python3 test/run_all.py # all headless test suites, in parallel (about a minute)
python3 test/run_all.py pipes # only suites whose name contains "pipes"
python3 test/run_all.py --browser # also the browser tests (rebuilds first; about 3 more minutes)
node test/t_pipes.js # one suite
python3 tools/shot.py shots/x.png --setup tools/scenes/clear-sky.js --js "..." --ticks 60
python3 tools/where.py 7614 # which source line is line 7614 of dist/index.html
python3 tools/map.py # regenerate the index in docs/PROJECT_MAP.md
```
You need Node (tested with 22) and Python 3. Playwright for Python and its Chromium live in
`.venv/` in the repo (not committed); set up as in README.md → Develop. The browser scripts and
`tools/shot.py` switch to `.venv` by themselves (`tools/use_venv.py`), so the commands above work
with plain `python3`.
## How the code is put together
- `build.py` joins the files listed in `src/manifest.json`, in order, into one classic script
inside `src/shell.html`. The output is `dist/index.html`. There are no modules and no
import/export: every file shares one global scope.
- **Order matters only for code that runs when the page loads.** A function can call a function
from any file. But a top-level `const`/`let` must come before top-level code that uses it. New
files go into the manifest in the right place: simulation first, then render, then UI.
- `'use strict'` at the top of `src/sim/base.js` applies to the whole bundle.
- **`src/sim/` must never touch the DOM** (no `document`, `window`, canvas or `localStorage`).
The headless tests load only these files, and keeping the simulation pure keeps a later port to
Rust or WebAssembly possible.
- **Keep files small and on one topic.** Aim for under about 400 lines. Split a file that grows
past that along a clear seam, add the new file to the manifest, and rebuild. Then run
`python3 tools/map.py` and update the hand-written part of the project map.
- **Errors point at real files.** In Node tests, stack traces name the source file and line. In
the browser they point into `dist/index.html`; use `tools/where.py` to find the source line
(`tools/shot.py` does this for you).
## Rules for the simulation
- **Performance.** The simulation runs 60 ticks a second over millions of cells.
- Use the existing typed arrays.
- Do not allocate objects or arrays inside per-cell loops.
- Only chunks that are awake (32×32 grains) are simulated. After changing cells directly,
wake them; `setCell` already does.
- Measure before and after anything in a hot path (`tools/perf.py`,
`tools/experiments/factory_cost.js`).
- **Determinism.** Randomness in `src/sim/` comes only from `rnd()` (seeded) or `mulberry32`.
Never use `Math.random` there. The headless tests rely on this: the same code gives the same
output, line for line.
- **Save compatibility.** The user has saved worlds they care about. Material ids, block codes
(`BP_*`), part ids (`P_*`) and machine type names are stored in saves.
- Never renumber or reuse them. Add new ones at the end (raise `NMAT` for materials).
- New saved fields need a default when an older save lacks them. Migrations go in
`deserializeWorld` (`src/sim/save.js`).
- Only raise `SAVE_VERSION` if old saves truly cannot be read any more, and tell the user first.
- **Undo.** Every building action the player takes must be undoable. Wrap it in
`undoRecord(label, fn)`. The functions that place and remove things record their own steps
with `undoNote`. The bot building ghosts is never an undo step of its own.
## Checklists
**A new material.** It needs:
- an id constant in `src/sim/materials.js` (at the end, before `NMAT`, and raise `NMAT`);
- a `def(...)` entry with a plain description;
- its price in `PRICE` (`src/sim/economy.js`) if it can be sold;
- its place in `BAG_ORDER` (`src/ui/state.js`) if it can go in the bag;
- its place in `MARKET_GROUPS` (`src/ui/notebook.js`) if it is sold;
- any special tables it belongs to: `CASTMETAL`, `SOLIDMETAL`, `METAL_TIER`, `BAR_OF`,
`WALL_OF`/`WALL_LIST`, `REFINE`, `HOTLIQ`, `DROSS`.
Check its colour in both looks.
**A new buildable piece.** It needs:
- an entry in `PIECES` (`src/sim/pieces.js`) with cost and description;
- a block code or machine footprint;
- placing and removing that support undo and Ctrl-replace;
- a tile in `BUILD_CATS` and an icon in `PIECE_ICONS` (`src/ui/build-menu.js`);
- hover info (`hoverInfo` in `src/ui/info.js`);
- drawing in `src/render/` (pixel look, and a smooth-look class if it needs one);
- saving and loading of any state it keeps;
- a line in the controls help (`controlsHtml` in `src/ui/notebook.js`) if it adds controls;
- a headless test.
**Text the player reads** (descriptions, toasts, hover info, help):
- plain words and short sentences;
- what it does and how to use it;
- °C for temperatures, "grains" for cells, "blocks" for the 4×4 build grid;
- no programmer words.
Match the existing descriptions in `PIECES` and the material `def`s.
## Testing
`docs/TESTING.md` has the details: the harness, how to write a suite, the browser tests,
screenshots and the pitfalls. The essentials:
- Every change to the simulation gets a headless check in a `test/t_*.js` suite. Write the
check first when fixing a bug, and see it fail.
- **Test in the pixel look** (the default in the tools). Use the smooth look only when checking
graphics, and then check both looks.
- Look at your screenshots. Open the PNG and check it shows what you meant, especially after
changing anything drawn.
- Before you say you are finished, run `python3 test/run_all.py`. After changing anything in
`src/ui/` or `src/render/`, run `python3 test/run_all.py --browser` too.
- **For a refactor** that should not change behaviour, save the suites' output before and after
and diff them. The headless suites are deterministic, so any difference is a real change (lines
with timings in ms excepted).
## Git
- Small commits, one change each, with a message that says what changed for the player or
developer. Run the tests first.
- `dist/` and `shots/` are build output and are not committed.
- Never commit secrets: tokens, passwords, or keys.
- Work happens one agent at a time. If running several agents side by side is set up later,
this section will say how they coordinate.