# Postcards: how it is built

Any warp address or short text as Lars's Hamlet place code, read back whole, turned, damaged, or from a scrap.

## What it imports

```html
<script src="../../../sitoolz/js/rangeblends.js"></script>   <!-- at, streamOf: the mask -->
<script src="../../../sitoolz/js/rulerland.js"></script><script src="../../../sitoolz/js/terrain.js"></script>   <!-- a random prize's address -->
<script src="../../../sitoolz/js/hamlet.js"></script>        <!-- SIHamlet: the editions site's hamlet code, byte for byte -->
```

From `SIHamlet`: `postcard(text)` (a 64-module code with the text as the town) → `{N, grid, capacity, place}`, `decode(cells, w, h)` (cells as an Int8Array, −1 for an unknown cell) → `{ok, rotation, place, town, districtsSeen, complete, hamlets}`, `scrap(grid, N, ox, oy, w, h)`. From `SITerrain`: `prizes("ruler-hills", 0)` for a random warp address.

## The twenty lines that make it

```js
const card = SIHamlet.postcard("rulerhills-1jqwv-mgzs-j"), N = card.N;          // 64 x 64 cells, the text in the town, the place round every 32-block
const g = canvas.getContext("2d"), s = canvas.width/N;
for (let y = 0; y < N; y++) for (let x = 0; x < N; x++) if (card.grid[y*N + x]){ g.fillStyle = "#151c2e"; g.fillRect(x*s, y*s, s, s); }
const cells = Int8Array.from(card.grid);                                          // what a reader sees; -1 marks a cell it cannot see
for (let y = 0; y < N; y++) for (let x = 0; x < 20; x++) cells[y*N + x] = -1;      // tear a band of 20 off the left
const d = SIHamlet.decode(cells, N, N);                                           // the ruler finds the phase; no corner marks needed
console.log(d.ok, d.place.seed, d.districtsSeen, d.town && new TextDecoder().decode(d.town));
```

## How to change the law

- The text: anything up to the capacity (203 bytes at N = 64); a longer build asks for N = 128 (`encode({N: 128, place, town})`), where the four rank-5 anchors also carry a village.
- The place: `postcard(text, {world, x, z, t, seed})` sets the 16-byte place that repeats round every 32-block; the seed is up to ten letters and digits.
- The damage: the town's districts are RS(4,3) across at N = 64, so one district lost is rebuilt and two are not; the hamlets are RS(24,16), so the place survives any scrap of side 46. Flip cells with the slider and watch where each gives out.

## How to verify it

`fixtures/hamlet.json` (written by Node from the JavaScript, the original) holds 32 codes at three sizes encoded cell for cell, decoded whole, rotated, damaged, as scraps, quarters and torn cards, 60 RS trials, 10,672 windows and three postcards; `tests/test_hamlet.py` checks the Python twin against it (11,009 checks) and `tests/twins-hamlet.test.cjs` the JavaScript. `smoke.cjs` here encodes two addresses and reads them back whole, turned, with 300 and 150 cells flipped, and with two districts torn off.

## What was missing

Nothing from the kit. One note: `decode` reads a scrap's place from any 46-cell window, but the town text needs the districts, so a band of 20 columns torn off loses two districts and the text with them, as the law says.

![](shot.png)
