# Build your own: from a blank file to a playable world in an afternoon

For people and for models. Everything below is done with `sitoolz` alone; the five demo games beside this file were built this way, and each one's `HOWTO.md` shows its own twenty lines.

## 1. Pick the arithmetic (ten minutes)

Every world in the kit stands on one law. Choose yours from the cards (`sitoolz/cards/`):

| you want | the law | the call |
|---|---|---|
| hills, ranges, islands, mesas | the ruler sequence (`rulerland.md`) | `SITerrain.window(world, x0, z0, w, h)` |
| towns and cities that are always in the same place | the city law (`citylaw.md`) | `CityLaw.sitesIn(g0, a, b)`, `CityLaw.plan(kind, g)` |
| a railway and roads between them | places (`places.md`) | `SIRails.railway(sites, ground)` |
| dice that anyone can check | indexed randomness (`indexed.md`) | `new SIIndexrng.Index(seed).roll(stream, i, sides)` |
| a wall of stone with a pattern nobody can predict but everyone can verify | the light cone (`prefixlaw.md`) | `RulerLand.coneSpans(g, depth)` |
| weather with a year in it | clocks (`clocks.md`) | `SIClocks.weather(...)` |
| a puzzle with one answer and a proof | puzzles (`puzzles.md`) | `SIPuzzles.solveSingles`, paths in `SISpn` |
| a proof that a number is prime | primes (`primes.md`) | `SIPrimes.verifyCertificate(cert)` |
| a hidden set with a parity trick | logic (`logic.md`) | `SILogic.solve(system)` |

## 2. The page (ten minutes)

```html
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="author" content="you"><title>My world</title><link rel="stylesheet" href="../demo.css"></head>
<body><div class="wrap"><h1>My world</h1><canvas id="c" width="960" height="480"></canvas><p id="told" class="told"></p></div>
<script src="../../../sitoolz/js/rangeblends.js"></script><script src="../../../sitoolz/js/rulerland.js"></script><script src="../../../sitoolz/js/terrain.js"></script>
<script src="game.js"></script></body></html>
```

Load only the engines you use, in dependency order: `rangeblends.js` before `rulerland.js` before `terrain.js`; `blake2b.js` before `indexrng.js`; `spn.data.js` before `spn.js`. From Node, `require("sitoolz")` or `import si from "sitoolz"` gives all of them at once.

## 3. The world (twenty minutes)

```js
const win = SITerrain.window("ruler-hills", 4000, -48, 192, 96);     // heights H[i][j], colours C[i][j], prizes, gate
const g = document.getElementById("c").getContext("2d"), PAL = ["#265496", "#d6c48c", "#609646", "#326430", "#787068", "#ebeef0"];
for (let i = 0; i < win.w; i++) for (let j = 0; j < win.h; j++){ g.fillStyle = PAL[win.C[i][j]]; g.fillRect(i*5, j*5, 5, 5); }
for (const p of win.prizes){ g.fillStyle = "#ffc94d"; g.fillRect((p.x - win.x0)*5, (p.z - win.z0)*5, 5, 5); }
```

That is a world. Every machine that runs these lines draws the same one, because the heights are a function of the column number and nothing else. Change the world name to any key of `SITerrain.WORLDS`; pass an object instead (`{kind: "plateau", base: 22, water: 18, top: 130, args: {unit: 12, unitz: 6, c: 0.25, kmax: 9, kmin: 7, ramp: 6}}`) to make a world of your own from the same laws.

## 4. The people in it (twenty minutes)

```js
const G0 = SITerrain.G0, sites = CityLaw.sitesIn(G0, win.x0, win.x0 + win.w - 1);   // {g, x, k, kind}: hamlets at rank 7, towns at 9, cities at 11
const ground = (x, z) => win.H[x - win.x0][z - win.z0];
const rail = SIRails.railway(sites.map(s => ({...s, z: SITerrain.lane("ruler-hills", s.g)})), ground);   // cells "x,z": [x, z, h, tool]
```

Settlements sit on columns of rank 7 and up, so they are at the same places in every copy of the world, and the railway joins them. `CityLaw.plan(kind, g)` gives a whole town plan when the camera gets close.

## 5. The rules (thirty minutes)

Movement, pickups and turns are yours to write; the kit gives you what has to be the same for everyone:

- dice: `const rng = new SIIndexrng.Index("my world"); rng.roll("foe", turn, 6)`; the same seed, stream and index give the same roll on every machine and there is no state to save. `SIIndexrng.Commit` lets a page prove it did not change the seed after the fact.
- prizes: `win.prizes` are on columns of rank 5 and up with an even square remainder; their `code` is a warp address anyone can type into Wander.
- a lock: `SILogic` for parity puzzles, `SIPuzzles` for Sudoku, `SIPrimes` for a certificate.

## 6. Prove it (twenty minutes)

Write the numbers the game depends on into a small fixture from Python (`from sitoolz import terrain; terrain.window(...)`) and check the page's numbers against it in a smoke, the way `demo/*/smoke.cjs` does with `cdp.cjs`. If the numbers match, the game is the same everywhere; if they do not, a law moved, and the fixture says which.

## 7. Ship it

One directory, three files, no build step. Put it beside the others and link it from the demo page. Say whose laws they are: the cards carry the credit, and so should the page.
