# tui-globe
A ratatui Braille-canvas globe widget. Geometry buffers under `assets/geo/`
are baked from public domain [Natural Earth](https://www.naturalearthdata.com)
data and embedded at compile time via `MapData::embedded()`.
## Regenerating the geometry
The `.gl` buffers are generated by `tools/build_geo.py`. The script fetches
shapefiles from naciscdn.org on demand, caches them, and writes the five
`.gl` blobs to `--out`. The buffers are checked in, so you only need to
re-run the script when bumping the data set or changing the build flags.
### Flags
| `--scale {10m,50m,110m}` | `50m` | Natural Earth resolution. Smaller numbers = denser mesh / larger binary. |
| `--cultural-borders` / `--no-cultural-borders` | on | With borders, triangulate `ne_<scale>_admin_0_countries` (coastlines + country borders) and overlay `ne_<scale>_admin_1_states_provinces_lines`. Without, triangulate `ne_<scale>_land` (coastlines only). |
| `--data-dir PATH` | `$XDG_CACHE_HOME/tui-globe-build-geo` | Where to cache downloaded `.zip`/`.shp` files. |
| `--out PATH` | (required) | Output directory for the five `.gl` files. |
| `--ne-countries PATH` | auto-fetch | Override: custom `admin_0_countries .shp` (cultural mode). |
| `--ne-states PATH` | auto-fetch | Override: custom `admin_1_states_provinces_lines .shp` (cultural mode). |
| `--ne-land PATH` | auto-fetch | Override: custom physical land `.shp` (`--no-cultural-borders` mode). |
The override flags let you swap in locally modified shapefiles (e.g. simplified
geometry, custom border tweaks). They take precedence over auto-fetch for
that one input; the rest still come from the cache or are downloaded.
### Run it
The script is packaged as a Python project at `tools/pyproject.toml`,
declaring `pyshp`, `mapbox-earcut`, and `numpy` as dependencies. Pick
whichever workflow you prefer:
**With `uv`** (no venv management needed):
```bash
uv run --project tui-globe/tools build-geo --scale 50m --out tui-globe/assets/geo
```
**With `pip` into a venv:**
```bash
python3 -m venv .venv
.venv/bin/pip install ./tui-globe/tools
.venv/bin/build-geo --scale 50m --out tui-globe/assets/geo
```
**Without installing** (manual deps):
```bash
pip install pyshp mapbox-earcut numpy
python3 tui-globe/tools/build_geo.py --scale 50m --out tui-globe/assets/geo
```
### Examples
```bash
# Default: 50m with country and state/province borders
build-geo --scale 50m --out tui-globe/assets/geo
# High-detail land mesh with no borders
build-geo --scale 10m --no-cultural-borders --out tui-globe/assets/geo
# Tiny global-overview mesh
build-geo --scale 110m --out tui-globe/assets/geo
# Use custom / locally modified shapefiles (overrides auto-fetch)
build-geo --scale 50m \
--ne-countries ./my-data/ne_50m_admin_0_countries.shp \
--ne-states ./my-data/ne_50m_admin_1_states_provinces_lines.shp \
--out tui-globe/assets/geo
# Override just the country polygons; states still auto-fetched
build-geo --scale 50m \
--ne-countries ./my-data/custom_countries.shp \
--out tui-globe/assets/geo
# Custom physical-land shapefile, no borders
build-geo --no-cultural-borders \
--ne-land ./my-data/custom_land.shp \
--out tui-globe/assets/geo
```
### Verify
```bash
cargo test -p tui-globe
```
The test suite asserts the buffers parse to a thin unit-sphere shell, that
restart markers separate rings, and that no surviving chord exceeds the
0.05 threshold the renderer relies on.
## Output format
Five little-endian binary blobs, the same format the desktop Mullvad client
uploads into WebGL:
| `land_positions.gl` | `f32` xyz | unit-sphere vertices |
| `land_triangle_indices.gl` | `u32` | `GL_TRIANGLES` indices |
| `land_contour_indices.gl` | `u32` | `GL_LINE_STRIP` indices, `0xFFFFFFFF` between rings |
| `ocean_positions.gl` | `f32` xyz | level-4 icosphere vertices (2562) |
| `ocean_indices.gl` | `u32` | `GL_TRIANGLES` indices (5120 tris) |
Coordinate convention (matches `lib.rs::project_point`):
```
x = cos(lat) sin(lon)
y = sin(lat)
z = cos(lat) cos(lon)
```