Files
deepgrain-foundry/AGENTS.md
T
44r0n7andClaude Opus 5.5 e0525c1cfb Move the to-do list from NOTES.md to a kandown board
Each note is a task in tasks/ with the owner's words under ## Context; the
board rules are in .kandown/kandown_work.md and docs/kandown.md explains how
kandown works here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 00:44:22 -04:00

10 KiB
Raw Blame History

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. Run kandown work. It prints the user's task board and the rules for working it (see "Working from the task board" 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 the task board

The user's to-do list is a kandown board: one Markdown file per task in tasks/. Read docs/kandown.md before using it: it says how the board works here, which commands are safe (never run kandown <command> --help: it runs the command), and what a task file looks like. The rules for working the board are in .kandown/kandown_work.md, and kandown work prints them. In short:

  • Work on tasks only when asked. Todo tasks are built; Backlog tasks tagged discussion get options with trade-offs and a recommendation, and nothing is built until the user decides.
  • Never reword the user's words in a task's ## Context. Add your notes as subtasks with report: lines, or in the report field.
  • When a task is finished, move it to Review with a report saying what changed and how to check it in the game. Only the user moves tasks to Done.
  • Log your work. Add an entry at the top of docs/agent-log.md with the date, the task, 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

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 defs.

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.

This project uses Kandown. Before task work, run kandown work and follow its output.