terrain generation
==================

the world is a 2D grid of tiles generated deterministically from a seed.
same seed = same world, always.

how it works
------------

1. generate a permutation table from the seed (shuffled 0-255)
2. compute elevation at 1/4 resolution using layered Perlin noise (3 octaves)
3. normalize elevation to [0, 1]
4. bilinear interpolate up to full resolution
5. derive terrain from elevation thresholds:
     > 0.75  mountain  ^
     > 0.55  forest    T
     > 0.25  grass     .
     > 0.15  sand      :
     <= 0.15 water     ~
6. trace rivers from random high-elevation points downhill to water

the 1/4 resolution trick is why generation takes ~1s instead of ~9s for a
1000x1000 map. terrain features are large enough that interpolation doesn't
lose visible detail.

geography emerges naturally from noise: mountain ranges form along ridges,
forests cluster at foothills, sand appears at shorelines, oceans fill low
basins. rivers connect highlands to water bodies.

world config lives in worlds/<name>/config.toml:

    [world]
    name = "Earth"
    seed = 42
    width = 1000
    height = 1000

rendering
---------

viewport is centered on the player (@). size comes from NAWS (terminal
dimensions) — eventually. for now it's a fixed 21x11.

ANSI colors per terrain type:
    .  grass     green
    ^  mountain  dark gray
    ~  water     blue
    T  forest    green
    :  sand      yellow
    @  player    bold white
    *  entity    bold red

passability
-----------

mountains and water are impassable. forest, grass, sand are walkable.
water will eventually have shallow/deep variants (wadeable vs boat-only).

code
----

src/mudlib/world/terrain.py   world generation + noise
src/mudlib/render/ansi.py     ANSI color mapping
worlds/earth/config.toml      earth config
