Files
deepgrain-foundry/AGENTS.md
T
44r0n7andClaude Opus 5.5 3f971a94c2 Deepgrain Foundry: move from a claude.ai artifact to a local repository
The game as of artifact version 24, ready for local development with
coding agents.

- Source split from three large files into 52 small ones under src/sim,
  src/render and src/ui, joined in the order in src/manifest.json by
  build.py. The joined code is unchanged apart from comments; every
  headless suite gives the same output, and screenshots in both looks
  are pixel-identical to before.
- Light tidying with no change in behaviour: one movement scan loop,
  shared hazard-stripe and belt shader helpers, unused code removed, a
  shared check helper for the test suites.
- World files can be exported as an ordinary download outside claude.ai.
- Tests: broken old scripts removed, experiments moved to tools/,
  test/run_all.py added. Tools: shot.py (repeatable screenshots),
  where.py, map.py.
- Docs: AGENTS.md, CLAUDE.md, NOTES.md (the owner's to-do inbox),
  docs/PROJECT_MAP.md, DESIGN.md, TESTING.md, systems notes, the
  owner's requests and an agent log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9kLmYADKSEjuwUN3rFxDA
2026-10-23 16:05:31 -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. 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

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), Python 3, and Playwright for Python with Chromium (pip install -r requirements.txt, then python3 -m playwright install chromium). Playwright officially supports Ubuntu and Debian. On other Linux distributions, such as Arch, its bundled Chromium usually works; if it does not, launch the system Chromium through Playwright's executable_path.

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.