Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

loomscape

ASCII terrain maps generated with a from-scratch Wave Function Collapse solver — no external dependencies.

What it is / why it's interesting

Wave Function Collapse (WFC) is a constraint-propagation algorithm usually used to generate tile-based levels or textures from a small rule set. Here it's applied to five terrain tiles (water, sand, grass, forest, mountain) under one rule: adjacent cells may differ by at most one elevation band.

That single local rule, enforced everywhere via arc-consistency-style propagation, is enough to make coastlines, plains, and mountain ranges emerge globally — nobody tells the algorithm "put a beach around the water," it falls out of the constraint. A small neighbor-matching bias is layered on top of the raw WFC pick to favor forming contiguous patches (oceans and forests) over speckled noise, which pure unweighted WFC on such a permissive rule tends to produce.

Install / run

Requires Node.js >= 18. No dependencies to install.

git clone <this-repo>
cd loomscape
node bin/loomscape.js --width 60 --height 20 --seed atlas

Usage example

$ node bin/loomscape.js --width 20 --height 12 --seed harbor
~~~~~~~~~.~~..,#####
~~~~~~~~~.~~..,####,
~~~~~...~.~~..,,###,
~~~~~~~.~.~~..,,,,,.
.~~.......~~..,,,,,,
...,,,,,,,..,...,,..
...,,,,,,,,,,...,,..
...,,,#,,,,,,.......
..,,,##,,,,,,.....,.
.....,,,,,,,,,,,,.,,
~~~~~..,,,,,,###,,,,
~~~~~..,,.,,,####,,,

legend: ~=water  .=sand  ,=grass  #=forest  ^=mountain
seed: harbor

A larger sample lives at examples/atlas-60x20.txt (generated with --width 60 --height 20 --seed atlas).

Options:

-w, --width <n>    map width in cells (default: 50)
-h, --height <n>   map height in cells (default: 20)
-s, --seed <s>     seed (number or word) for reproducible output
--help             show this help

Same seed always produces the same map. A pre-generated sample lives at examples/atlas-60x20.txt.

How it works

  1. Every cell starts "uncollapsed": a bitmask of all 5 possible tiles.
  2. Repeatedly pick the uncollapsed cell with the fewest remaining options (lowest entropy — ties broken randomly), and collapse it to one tile, chosen by weighted random pick among its options. The pick is biased toward tiles matching already-settled neighbors so terrain forms patches instead of noise.
  3. Propagate: for each of that cell's neighbors, remove any tile that isn't compatible (elevation diff > 1) with the collapsed cell. If a neighbor's mask changes, push it onto a queue and propagate further — this is a standard arc-consistency (AC-3-style) pass.
  4. If propagation ever empties a cell's mask (a contradiction — can happen near tight corners), the whole grid is discarded and generation retries with a fresh draw from the seeded RNG (up to 50 attempts).
  5. Repeat until every cell is collapsed, then render each cell's tile symbol into a grid.

Randomness comes from a seeded mulberry32 PRNG (src/rng.js) so any run is fully reproducible from its --seed.

Tests

npm test

Checks: every cell ends up filled, no two adjacent cells violate the elevation-band rule, identical seeds reproduce identical maps, and different seeds (usually) differ.

License

MIT — see LICENSE.

About

ASCII terrain maps generated with a from-scratch Wave Function Collapse solver.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages