Writing a hunt
Your code runs once per seed inside a sandboxed Web Worker with the map's own engine behind it. The worker hands it one argument, the seed object, and takes back one verdict: a truthy return is a hit and lands on the results list; anything else moves the walk on.
the two shapes your code can take
A plain body: return truthy on a hit.
return seed.biomeAt(0, 0) === 1; // plains at the origin
Or declare a check function; it is detected and called.
function check(seed) { return seed.heightAt(0, 0) > 100; }
The seed object
The table below is the whole API. The values it answers are the SAME values the map, the finder and /api/check answer: same resolution, same heights, same climate decode, one engine.
The seed object
Your code runs once per seed with one argument: the seed object. It is the SAME mutable object on every call (no per-seed allocation), so read it inside the call. value is a Number when the seed fits safely and a BigInt otherwise; big and u64 always carry the exact 64-bit value.
- seed.value
- The world seed, signed 64-bit reading. Number when it fits safely (|v| <= 2^53 - 1), BigInt otherwise. Cheap arithmetic pre-filters belong here: an early return on seed.value costs zero engine time.
- seed.big
- The exact signed 64-bit seed, always a BigInt, never a float.
- seed.u64
- The unsigned 64-bit view (0 .. 2^64 - 1).
- seed.hex
- The unsigned hex reading, "0x" prefixed.
- seed.dim()
- The run's active dimension: 0 overworld, 1 nether, 2 end. Set on the hunt panel before the run; biome and terrain answers follow it, and structures() answers an empty list for types alien to it. Free - no engine call, so it costs nothing even inside a pre-filter.
returns number | bigint
if (seed.value % 7 !== 0) return false; // free pre-filter
returns bigint
returns bigint
returns string
returns 0 | 1 | 2
if (seed.dim() !== 0) return false; // overworld-only hunt
Biomes
Block coordinates, the same resolution the map paints. Passing a y samples the REAL 3D biome at that height (the only place the cave biomes answer); without it you get the depth-0 surface voice.
- seed.biomeAt(x, z)
- The surface biome id at block (x, z). The same number the map paints and /api/check reports.
- seed.biomeAt(x, z, y)
- The 3D biome at block height y. This is where Dripstone Caves (174), Lush Caves (175), Deep Dark (183) and Sulfur Caves (187) live; the surface voice never answers for them.
- seed.biomeName(id?)
- The biome's display name for an id, or for the biome at (0, 0) when omitted. Ids never collide across dimensions, so one table serves all three.
- seed.biomeId(name)
- The reverse lookup: 'lush_caves' -> 175, 'Cherry Grove' -> 185. Spaces, hyphens or underscores, case-insensitive - the same normalization the structure slugs use. null when the name is not in the table; it never guesses. Free - no engine call.
- seed.biomeList()
- The engine's known-biome table, [{ id, name }] sorted by id - the same 66-entry catalog the biome table further down this page prints. Frozen (the array and every entry) and cached, so it costs nothing per seed and is safe to stash.
- seed.biomeFind(target, x, z, radius)
- The NEAREST cell of any target biome within radius blocks of (x, z), or null. The fast way to ask 'cherry grove near spawn?': the map's own batched fill walks the biome lattice in RINGS around your point, chord-clipped to the circle, and stops the moment an exact rule proves nothing closer exists - a near hit answers in a handful of rings, an absent one pays the full disc. Measured: ~1.9us per lattice cell, ~1.8x cheaper per cell than a biomeAt loop, and on real hunts (spawn + search, 40 random seeds) 1.5x a hand-written smart ring walk, 2.7x a naive full-grid walk at radius 2048, 5.6x at radius 512. target is one id, one name, or an array mixing both (any-of); the answer is { biome, name, x, z, dist, cells } - x and z the hit cell's center block (the map's own sample point, so biomeAt(x, z) confirms the hit), dist whole blocks to your query point, cells the honest count of lattice cells the engine computed (early exit means it is far below the full disc on near hits). Ties break to the lowest x then z, so the answer is deterministic. Radius is 0..4096 blocks (a full 4096 disc costs ~1.5s overworld; the End's per-block lattice costs ~16x that). Runs in the active dimension, surface voice only - the cave biomes answer through caveAt.
returns number
return seed.biomeAt(0, 0) === 132; // Flower Forest at spawn-ish
returns number
return seed.biomeAt(0, 0, 0) === 175; // Lush Caves at y 0
returns string
const name = seed.biomeName(seed.biomeAt(sp.x, sp.z));
returns number | null
const LUSH = seed.biomeId('lush caves'); // 175, no magic number in your gate
returns array
const OCEAN = seed.biomeList() .filter((b) => b.name.includes('Ocean')) .map((b) => b.id);
returns object | null
// nearest Cherry Grove within 2 km of spawn, with its distance const sp = seed.spawn(); const hit = sp && seed.biomeFind('cherry grove', sp.x, sp.z, 2048); return hit && { biome: hit.name, dist: hit.dist, cells: hit.cells };
Terrain
The engine's own ground answers, per active dimension: fastHeight overworld, netherSurfaceY nether, endGroundY end (the End answers 0 for open void, the engine's own convention). The column profile goes one step deeper: the solid runs under a block, the floating-terrain detector the floating-soil hunt is built on. Overworld only; null elsewhere.
- seed.heightAt(x, z)
- Terrain height under block (x, z) in the run's dimension. The same number the map popup shows. Overworld surfaces answer per QUART (4-block cell), so the worker memoizes them per seed: a repeat probe inside an already-answered quart is a Map read instead of a fresh ~41us binary search, and seed.spawn() pre-answers the spawn's own quart - which means sp.y and heightAt(sp.x, sp.z) are the same number; read sp.y and it costs nothing. The nether and End answer per block column (no memo there).
- seed.columnAt(x, z, floor?)
- The column's solid-interval profile: { surface, intervals, grounded }. intervals is the list of solid runs under (x, z), TOP run first, each [bottom, top] inclusive; interval 0's top is the surface. An empty list is the classic solid column - anything else means AIR below the top run: a floating slab (one run, nothing under it) or a slab over a gap. grounded tells whether the lowest run reaches the scan floor. floor sets that scan floor (default 0, range -64..255). The same record the 3D flight view meshes, on the engine's raw terrain density - caves do not answer here, only real hollow ground. Overworld only; null elsewhere. Costs more than heightAt, so gate it behind the cheap checks.
returns number
return seed.heightAt(0, 0) > 120; // a high spawn point
returns object | null
const col = seed.columnAt(sp.x, sp.z); return col && !col.grounded; // soil flying: no run reaches the floor
Area scans
One seed, many probes: the questions a single block cannot answer (how much of this kilometer is ocean, is the spawn plateau flat, how many slime chunks sit nearby). A biome census is one batched engine call - the map's own tile fill - so its probes are the cheapest in the API (measured ~1.9-2.6us per lattice cell). Height probes run the per-point surface search (~41us per cold call, ~10x a biomeAt call), so their grids cap tighter - though the engine batches the overworld ones into a single fill and memoizes repeats, and the pool of workers runs up to 6 shards. All three scans take probe counts, not block sizes: w x h samples spaced step blocks apart from (x, z). The nearest-biome question does not need a census at all - biomeFind walks the rings for you and stops early. ORDER YOUR GATES CHEAP-FIRST: a ~30us biome census that rejects 95% of seeds before a ~0.9ms height grid is the difference between 347 and 468 seeds per second per thread on the same hunt (measured - same hits, same walk).
- seed.biomeArea(x, z, w, h, step?)
- A w x h biome census, probes `step` blocks apart (default 16), from (x, z): { x, z, w, h, step, ids, counts, unique, dominant }. ids is the flat grid, row-major (z outer, x inner); counts maps each biome id to its sample count; unique is the distinct count; dominant is the most-probed id. Probes sit on the dimension's native biome lattice - 4-block quarts in the overworld and nether, single blocks in the End - so a sub-lattice step rounds up to whole cells and the returned step is the EFFECTIVE spacing, never a lie. Sides cap at 512 (262,144 probes, the map's own tile budget); measured ~2us per probe - a 33 x 33 census costs ~2.4ms per seed, the island hunt's sparser 17 x 17 one ~0.65ms.
- seed.heightArea(x, z, w, h, step?)
- A w x h terrain summary, heightAt probes `step` blocks apart (default 16), from (x, z): { min, max, avg, minAt, maxAt } in the active dimension. avg carries one decimal; minAt and maxAt name the block coordinates of the extremes. Sides cap at 64 x 64 - measured ~34-43us per probe (a 13 x 13 grid costs ~5-6ms per seed, a 32 x 32 one ~35ms), so keep grids small and gate them behind cheap biome checks. Overworld grids whose step is a multiple of 4 run as ONE batched fill (the map's own height tile, bit-exact with the per-probe loop) and seed the height memo - a follow-up heightAt inside the grid answers for free. Odd steps and the nether/end keep the per-probe loop. The flatness and prominence questions live here.
- seed.slimeArea(x, z, w, h, step?)
- A w x h slime census, probes `step` blocks apart (default 16), deduped to 16-block chunks - probes inside one chunk are the same slime answer, so the census counts chunks, not probes: { x, z, w, h, step, slime, spots }, with spots listing each slime chunk's block origin. Sides cap at 64 x 64; measured ~4us per probe. An overworld organ: other dimensions answer 0 (the structures() rule, not a throw).
returns object
// is the kilometer around spawn at least 90% ocean? const ring = seed.biomeArea(sp.x - 512, sp.z - 512, 17, 17, 64); const OCEAN = new Set([0, 10, 24, 44, 45, 46, 48, 49, 50]); let sea = 0; for (const id in ring.counts) if (OCEAN.has(+id)) sea += ring.counts[id]; return sea / ring.ids.length >= 0.9;
returns object
// a flat spawn plateau: nothing sticks out more than 8 blocks const h = seed.heightArea(-96, -96, 13, 13, 16); return h.max - h.min <= 8 && { flat: h.max - h.min, avg: h.avg };
returns object
// slime farm country around spawn: 44+ chunks in the box const g = seed.slimeArea(sp.x - 128, sp.z - 128, 17, 17, 16); return g.slime >= 44 && { slime: g.slime };
Caves & surfaces
Below the surface voice. caveAt walks the column per block and reports the CAVE-BIOME bands (the F3 readout's own scan - the only place those bands answer as runs); surfacesAt answers the checked surface trio the /api/check page prints. Both are overworld organs; null elsewhere.
- seed.caveAt(x, z, top?)
- The column's cave-biome bands: up to 64 { biome, yLow, yHigh } runs, HIGHEST first, scanned per block from top (default 60, the F3 readout's own top) down to -64. Only the four 3D cave biomes ever answer - Dripstone Caves 174, Lush Caves 175, Deep Dark 183, Sulfur Caves 187 - so an empty array means the column has no cave-biome band at all. For a single point's 3D biome use biomeAt(x, z, y) instead. Measured ~0.1ms per column (the whole scan). Overworld only; null elsewhere.
- seed.surfacesAt(x, z)
- The checked surface trio at one block: { world, oceanFloor, preliminary }. world is the worldSurface heightAt answers; oceanFloor is the game's own CHECKED topmost solid (the real seabed under the water - the difference between the two is the water depth); preliminary is the k_l preliminary surface level. The checked scan is the most expensive single-block call in the API - measured ~0.8ms, ~20x a cold heightAt - so gate it behind the cheap checks. Overworld only; null elsewhere.
returns array | null
// a lush band close enough to dig into: within 20 blocks // of the grass const surf = seed.heightAt(sp.x, sp.z); const runs = seed.caveAt(sp.x, sp.z, 64); return runs.some((r) => r.biome === 175 && surf - r.yHigh <= 20);
returns object | null
// a shallow reef: water no deeper than 12 blocks const s = seed.surfacesAt(x, z); return s && s.world - s.oceanFloor <= 12;
Structures
The full structure catalog, by slug or engine id. Every type the map draws is here, including the two computed highlights: enchanted_apple (the desert temples whose hidden chest rolled the apple) and zombie_village (the 2% zombie roll). Types are per-dimension, set the run's dimension accordingly; a type alien to the dimension just answers an empty list.
- seed.structures(type, x, z, radius)
- All structures of the type within radius BLOCKS of block (x, z), each { x, z, chunkX, chunkZ, y }. y is the engine's own placement height where it computed one (trial chamber, ruined portal, camp, geode, well, gateway), else null. Radius caps at 8192.
- seed.nearest(type, x, z, radius)
- Sugar over structures(): the CLOSEST structure of the type within radius blocks of (x, z), or null. The same hit shape { x, z, chunkX, chunkZ, y }, reduced by true squared distance - the loop every 'nearest one' hunt used to hand-roll.
returns array
const v = seed.structures('village', 0, 0, 512); return v.length >= 2 && Math.hypot(v[0].x - v[1].x, v[0].z - v[1].z) <= 180;
returns object | null
const v = seed.nearest('village', 0, 0, 2048); return v && { gap: Math.round(Math.hypot(v.x, v.z)) };
Spawn
The engine's own spawn point hunt, overworld only (the engine's rule, not ours).
- seed.spawn()
- The spawn point { x, y, z } the map's S marker draws, or null outside the overworld. y is the surface heightAt(sp.x, sp.z) would answer (the same quart's binary search), so gate on sp.y directly - the redundant probe answers for free, but the read is cleaner anyway. THE cost anchor of every spawn-centered hunt: the engine's own spiral (coarse rings to 2048, then a fine pass to 512, ~917 climate samples) runs ~1.9ms per seed inside the pinned wasm - measured, irreducible, and paid before any other organ. Stage everything else cheap-first after it.
returns object | null
const sp = seed.spawn(); return sp && seed.biomeAt(sp.x, sp.z) === 132; // Flower Forest spawn
Slime chunks
One chunk-level lookup, the same answer the map's SC badge gives.
- seed.slimeChunk(x, z)
- Whether the chunk containing block (x, z) is a slime chunk.
returns boolean
let n = 0; for (let i = 0; i < 8; i++) if (seed.slimeChunk(i * 16, 0)) n++; return n >= 3;
Climate & noise
The climate channels the map's climate layer paints, decoded through the SAME table ranges (ob_para_extremes), so the numbers match what the map legend prints. 2D channels (temp, humid, cont, ero, weird, pv, shiftx, shiftz, jagged) answer at the surface; the 3D cave-router noises need a y. Overworld only, the engine's climate tables are an overworld organ. Values carry the fill's 255-step quantization (span/255 raw units), the honest precision, stated here like the finder states it.
- seed.climate(x, z)
- All six climate channels at block (x, z): { temp, humid, cont, ero, weird, pv }.
- seed.climate(x, z, channel)
- One 2D channel's value. channel is a name or id 0..8.
- seed.noiseAt(x, y, z, channel)
- The 3D cave-router noises (ids 9..24: cavelayer, cavecheese, caveent, the spaghetti and pillar noises), sampled at block height y.
- seed.climateRange(channel)
- The channel's measured [min, max], for writing honest bands. The six climate ranges are static; the cave-router ranges are measured per y.
returns object
return seed.climate(0, 0).cont < -0.3; // the deep-ocean side of the continent
returns number
returns number
returns [number, number]
const [lo, hi] = seed.climateRange('cont'); return seed.climate(0, 0).cont < lo + (hi - lo) * 0.25;
Sister seeds
The Bedrock structure seed is the world seed's low 48 bits: every structure seed corresponds to 65,536 sister world seeds (seed + k * 2^48) with IDENTICAL structure placement and completely reshuffled biomes. The finder's Sister seeds toggle walks these classes; in code you can both walk them (run mode: Sisters) and ask about them from a seed.
- seed.structureSeed()
- The seed & 0xFFFFFFFFFFFF - the part that decides structure placement.
- seed.sister(k)
- The k-th sister world seed of this seed's class (k 0..65535). Same structures, different biomes.
- seed.sisters(count)
- The first count sisters as an array. Caps at 65,536.
- seed.kIndex()
- This seed's in-class index (the top 16 bits), 0..65535.
- seed.isSisterOf(other)
- Whether the other seed (bigint or parseable) shares this seed's low 48 bits.
returns bigint
returns bigint
returns bigint[]
returns number
returns boolean
The region grid
Every region structure (villages, outposts, mansions, temples...) places on a grid of spacing x spacing cells: each cell rolls ONE candidate chunk, and a gate chain decides whether the structure exists there. regionOf hands your code the map popup's own detective answer for any cell - the placement verdict, and the exact reason it failed when it did.
- seed.regionOf(type, x, z)
- The region cell containing block (x, z), for the type: { spacing, separation, region, candidate, gate, gateName, py, centerBiome, killX, killY, killZ, killBiome, roll, extra, placed }. region is the cell's grid id; candidate is the chunk the cell rolled; gateName reads the engine's own verdict - 'pass' (placed), 'surface', 'biome' (the kill fields name the killing block and biome), 'monument', 'roll' (the roll field is the dice), 'ground' (extra is the failing y), 'jigsaw'. placed is the placed hit ({ x, z, chunkX, chunkZ, y }) when the gate passed, else null. The type's own dimension must be the run's active dimension - an alien type throws, naming where to switch. Measured ~10us per call.
returns object
// does the region cell AT the origin hold a village? const r = seed.regionOf('village', 0, 0); return r.gateName === 'pass' && r.placed && { at: r.placed.x + ', ' + r.placed.z };
Structure slugs
The type argument of seed.structures: a slug (spaces or underscores, case-insensitive) or the engine id. Aliases like woodland_mansion or desert_pyramid land on the same types.
| slug | structure | dimension |
|---|---|---|
| 'village' | Village | Overworld |
| 'outpost' | Pillager Outpost | Overworld |
| 'monument' | Ocean Monument | Overworld |
| 'mansion' | Woodland Mansion | Overworld |
| 'treasure' | Buried Treasure | Overworld |
| 'mineshaft' | Mineshaft | Overworld |
| 'stronghold' | Stronghold | Overworld |
| 'desert_temple' | Desert Temple | Overworld |
| 'jungle_temple' | Jungle Temple | Overworld |
| 'witch_hut' | Witch Hut | Overworld |
| 'igloo' | Igloo | Overworld |
| 'shipwreck' | Shipwreck | Overworld |
| 'ocean_ruin' | Ocean Ruin | Overworld |
| 'ancient_city' | Ancient City | Overworld |
| 'trial_chamber' | Trial Chamber | Overworld |
| 'trail_ruins' | Trail Ruins | Overworld |
| 'slime_chunk' | Slime Chunk | Overworld |
| 'geode' | Amethyst Geode | Overworld |
| 'fossil' | Fossil | Overworld |
| 'desert_well' | Desert Well | Overworld |
| 'ravine' | Ravine | Overworld |
| 'ruined_portal' | Ruined Portal (Overworld) | Overworld |
| 'camp' | Abandoned Camp | Overworld |
| 'dungeon' | Dungeon | Overworld |
| 'fortress' | Nether Fortress | Nether |
| 'bastion' | Bastion Remnant | Nether |
| 'ruined_portal_nether' | Ruined Portal (Nether) | Nether |
| 'nether_fossil' | Nether Fossil | Nether |
| 'end_city' | End City | End |
| 'end_gateway' | End Gateway | End |
| 'enchanted_apple' | Enchanted Apple (desert temples whose chest rolled the apple) | Overworld |
| 'zombie_village' | Zombie Village (the 2% zombie roll) | Overworld |
Biome ids
The ids biomeAt answers and biomeId looks up: the engine's own catalog, 66 known biomes, ids never colliding across dimensions. The four cave biomes (174 Dripstone Caves, 175 Lush Caves, 183 Deep Dark, 187 Sulfur Caves) only answer with a y - through biomeAt(x, z, y) or caveAt's bands - never from the depth-0 surface voice.
| id | biome | where it answers |
|---|---|---|
| 0 | Ocean | Overworld surface + 3D |
| 1 | Plains | Overworld surface + 3D |
| 2 | Desert | Overworld surface + 3D |
| 3 | Windswept Hills | Overworld surface + 3D |
| 4 | Forest | Overworld surface + 3D |
| 5 | Taiga | Overworld surface + 3D |
| 6 | Swamp | Overworld surface + 3D |
| 7 | River | Overworld surface + 3D |
| 8 | Nether Wastes | Nether (run dim 1) |
| 9 | The End | the End (run dim 2) |
| 10 | Frozen Ocean | Overworld surface + 3D |
| 11 | Frozen River | Overworld surface + 3D |
| 12 | Snowy Plains | Overworld surface + 3D |
| 14 | Mushroom Fields | Overworld surface + 3D |
| 16 | Beach | Overworld surface + 3D |
| 18 | Windswept Forest | Overworld surface + 3D |
| 21 | Jungle | Overworld surface + 3D |
| 23 | Sparse Jungle | Overworld surface + 3D |
| 24 | Deep Ocean | Overworld surface + 3D |
| 25 | Stony Shore | Overworld surface + 3D |
| 26 | Snowy Beach | Overworld surface + 3D |
| 27 | Birch Forest | Overworld surface + 3D |
| 29 | Dark Forest | Overworld surface + 3D |
| 30 | Snowy Taiga | Overworld surface + 3D |
| 32 | Old Growth Pine Taiga | Overworld surface + 3D |
| 35 | Savanna | Overworld surface + 3D |
| 36 | Savanna Plateau | Overworld surface + 3D |
| 37 | Badlands | Overworld surface + 3D |
| 38 | Wooded Badlands | Overworld surface + 3D |
| 40 | Small End Islands | the End (run dim 2) |
| 41 | End Midlands | the End (run dim 2) |
| 42 | End Highlands | the End (run dim 2) |
| 43 | End Barrens | the End (run dim 2) |
| 44 | Warm Ocean | Overworld surface + 3D |
| 45 | Lukewarm Ocean | Overworld surface + 3D |
| 46 | Cold Ocean | Overworld surface + 3D |
| 48 | Deep Lukewarm Ocean | Overworld surface + 3D |
| 49 | Deep Cold Ocean | Overworld surface + 3D |
| 50 | Deep Frozen Ocean | Overworld surface + 3D |
| 129 | Sunflower Plains | Overworld surface + 3D |
| 131 | Windswept Gravelly Hills | Overworld surface + 3D |
| 132 | Flower Forest | Overworld surface + 3D |
| 140 | Ice Spikes | Overworld surface + 3D |
| 155 | Old Growth Birch Forest | Overworld surface + 3D |
| 160 | Old Growth Spruce Taiga | Overworld surface + 3D |
| 163 | Windswept Savanna | Overworld surface + 3D |
| 165 | Eroded Badlands | Overworld surface + 3D |
| 168 | Bamboo Jungle | Overworld surface + 3D |
| 170 | Soul Sand Valley | Nether (run dim 1) |
| 171 | Crimson Forest | Nether (run dim 1) |
| 172 | Warped Forest | Nether (run dim 1) |
| 173 | Basalt Deltas | Nether (run dim 1) |
| 174 | Dripstone Caves | 3D only (with a y) |
| 175 | Lush Caves | 3D only (with a y) |
| 177 | Meadow | Overworld surface + 3D |
| 178 | Grove | Overworld surface + 3D |
| 179 | Snowy Slopes | Overworld surface + 3D |
| 180 | Jagged Peaks | Overworld surface + 3D |
| 181 | Frozen Peaks | Overworld surface + 3D |
| 182 | Stony Peaks | Overworld surface + 3D |
| 183 | Deep Dark | 3D only (with a y) |
| 184 | Mangrove Swamp | Overworld surface + 3D |
| 185 | Cherry Grove | Overworld surface + 3D |
| 186 | Pale Garden | Overworld surface + 3D |
| 187 | Sulfur Caves | 3D only (with a y) |
| 188 | Dappled Forest | Overworld surface + 3D |
The walk modes
Where the seeds come from, chosen on the hunt panel before the run. The walk itself is sharded across a pool of worker threads sized to your machine (cores minus one, RAM and device class trimmed, capped at 8) - each thread tests its own slice of the same walk in parallel, so the hunt runs as fast as your machine allows.
- Random walk
- a random odd 64-bit stride over the whole seed space, full period: every one of the 2^64 world seeds is visited exactly once, in a shuffled order. The default hunt.
- Sequential
- from the From seed upward, one by one. For watching a known neighborhood.
- Range
- From through To, inclusive. For exhaustive small-space sweeps, like every seed from 0 to 100000.
- Sister seeds
- structure-seed classes instead of world seeds: each class holds From + classIndex, and the worker hands you its sisters k = 0..Sisters/class. Structures are IDENTICAL inside a class; biomes differ. The stronghold sits at the same coordinates for every sister, the biome under it does not.
The sandbox's honest rules
what your code can and cannot do
- No network, no storage. The worker deletes its own fetch, XMLHttpRequest, WebSocket, importScripts, Worker and indexedDB globals before your code runs, so the code cannot reach anywhere. The engine module and its memory stay in the worker's closure, out of the code's reach.
- Sync code, one seed at a time. There is no await in a check; keep it synchronous and quick.
- A 4-second silence kills the run. A healthy worker posts progress at least every 200ms; the page terminates the whole pool when every worker goes silent for 4 seconds (an infinite loop) and names the cause. That silence guard is a hang detector, not a time limit: runs have no budget, so a walk ends only at its seed count, the hit cap, or your Stop.
- A throw ends the hunt with the error and the failing seed on the error panel.
- Cheap first, engine second. A check that returns on
seed.valuearithmetic never touches the engine: order the code so free pre-filters run before biome and structure calls.
That is the whole language. Thirteen ready hunts ship on the editor's template row, each one a working example of a different part of this table, and a blank canvas starts your own.
Write a hunt