## 1. Project Overview & Quickstart (opengeos/GeoLibre)

## File: README.md

# GeoLibre

[](https://web.geolibre.app/)
[](https://share.geolibre.app)
[](https://plugins.geolibre.app)
[](https://pypi.python.org/pypi/geolibre)
[](https://r.geolibre.app/)
[](https://colab.research.google.com/github/opengeos/GeoLibre/blob/main/python/examples/getting-started.ipynb)
[](https://anaconda.org/conda-forge/geolibre)
[](https://github.com/conda-forge/geolibre-feedstock)
[](https://apps.microsoft.com/detail/9nwt67rv531x)
[](https://apps.apple.com/app/geolibre-desktop/id6796848769)
[](https://apps.apple.com/app/geolibre/id6796039674)
[](https://play.google.com/store/apps/details?id=org.geolibre.app)
[](https://aur.archlinux.org/packages/geolibre-bin)
[](https://flatpark.org/apps/app.geolibre.GeoLibre/)
[](https://opensource.org/licenses/MIT)
[](https://doi.org/10.5281/zenodo.20785400)
[](https://deepwiki.com/opengeos/GeoLibre)

A free and open-source, lightweight, cloud-native GIS platform for visualizing, exploring, and analyzing geospatial data. It runs everywhere you do, in the web browser, on the desktop, on mobile, and inside Jupyter notebooks, all while keeping your data local and private.

It also ships **1,000+ geoprocessing tools** that run *entirely in your browser* on WebAssembly — terrain, hydrology, LiDAR, remote sensing, and vector analysis with no server, no install, and no data ever leaving your machine.

GeoLibre is built with **Tauri v2**, **React**, **TypeScript**, **MapLibre GL JS**, **DuckDB-WASM Spatial**, and **deck.gl**. The same workspace runs as a native desktop app, native Android and iOS apps, in any modern web browser, and adapts responsively to mobile and small screens.

- **[Launch GeoLibre Web](https://web.geolibre.app/)** — the full app in your browser, nothing to install
- **[Download the desktop app](https://geolibre.app/downloads/)** — Windows, macOS, and Linux installers
- **[Get it on the Mac App Store](https://apps.apple.com/app/geolibre-desktop/id6796848769)** — the sandboxed macOS build
- **[Get it on the App Store](https://apps.apple.com/app/geolibre/id6796039674)** — the native iOS app for iPhone and iPad
- **[Get it on Google Play](https://play.google.com/store/apps/details?id=org.geolibre.app)** — the native Android app
- **[Use the Python package](https://geolibre.app/python/)** — embed and control the full app in Jupyter notebooks
- **[Use the R package](https://r.geolibre.app/)** — build interactive maps in RStudio, Quarto, R Markdown, and Shiny
- **[1,000+ geoprocessing tools](https://geolibre.app/user-guide/processing/#whitebox-toolbox)** — the full toolbox, in the browser
- **[Get started](https://geolibre.app/getting-started/)** — install, run from source, and configure
- **[Features](https://geolibre.app/features/)** — the complete feature list

## Demos

**Click any screenshot to open it at full resolution, or any animation to play the full-quality video.**

### 3D Tiles

[](https://assets.geolibre.app/images/GeoLibre-demo.webp)

[Open the live project](https://share.geolibre.app/giswqs/3d-tiles)

### NYC buildings and subways

Manhattan building footprints extruded in 3D and colored by construction era, with the MTA subway lines and stations on top and a legend generated automatically from the layers' symbology.

[](https://assets.geolibre.app/images/nyc-buildings.webp)

The animation below runs the Time Slider along the buildings' construction year, from 1850 to 2025, so Manhattan fills in era by era. Click it to play the full-quality video.

[](https://assets.geolibre.app/demos/nyc-buildings.webm)

[Open the live project](https://share.geolibre.app/giswqs/nyc-buildings-and-subways)

### Planetary basemaps

GeoLibre is not limited to Earth. Planetary basemaps from OpenPlanetaryMap and USGS Astrogeology cover the Moon, Mars, Mercury, Venus, the Galilean moons (Io, Europa, Ganymede, Callisto), Titan, Pluto, and Charon, with a per-project ellipsoid so distance, area, and scale measurements match the body you are mapping. The deep-space starfield behind each globe comes from the Atmosphere Effects plugin.



| [](https://assets.geolibre.app/images/earth.webp) | [](https://assets.geolibre.app/images/moon.webp) | [](https://assets.geolibre.app/images/mars.webp) |
| --- | --- | --- |
| **Earth** | **Moon** | **Mars** |
| [](https://assets.geolibre.app/images/mercury.webp) | [](https://assets.geolibre.app/images/pluto.webp) | [](https://assets.geolibre.app/images/venus.webp) |
| **Mercury** | **Pluto** | **Venus** |
| [](https://assets.geolibre.app/images/europa.webp) | [](https://assets.geolibre.app/images/callisto.webp) | [](https://assets.geolibre.app/images/charon.webp) |
| **Europa** | **Callisto** | **Charon** |



Switch bodies from the planet switcher in the Layers panel. See [Demos](https://geolibre.app/demos/) for more.

### Video tutorials

- [GeoLibre 1.0: A Free, Open-Source Cloud-Native GIS That Runs Anywhere (Browser, Desktop & Jupyter)](https://youtu.be/87Cm0QagtxI)
- [Geoprocessing in the Browser: 700+ Free GIS Tools in GeoLibre, Zero Install](https://youtu.be/W32bIQO_nG8)
- [GeoLibre + GeoLens: A Modern GIS Stack for Self-Hosting Geospatial Data](https://youtu.be/kQqgrxXGd4o)

## Geoprocessing: 1,000+ tools, zero install

[](https://assets.geolibre.app/images/whitebox.webp)

**Processing → Whitebox Toolbox** opens a toolbox of **1,000+ geoprocessing tools** that
execute in the browser through a WebAssembly runtime with native raster and
vector I/O. There is no Python sidecar to install and no server to call — the
tools, your data, and the results all stay on your machine, so the full toolbox
is available on [GeoLibre Web](https://web.geolibre.app/), on the desktop app,
and on Android alike.

The tools come from the [Whitebox Next Gen](https://github.com/opengeos/Whitebox-Next-Gen-ArcGIS)
suite plus GeoLibre's own WASM tools, and are browsable by category straight from
the Processing menu:

| Category | Tools | Examples |
| --- | --- | --- |
| **Vector** | 313 | overlays, buffers, joins, cleaning, topology, generalization |
| **Raster** | 256 | algebra, filters, reclassification, zonal and focal statistics |
| **Remote sensing** | 154 | spectral indices, band math, classification, change detection |
| **Hydrology** | 100 | flow accumulation, watersheds, stream networks, depression filling |
| **Terrain** | 99 | slope, aspect, hillshade, curvature, ruggedness, viewsheds |
| **LiDAR** | 65 | point-cloud filtering, ground classification, DEM/DSM generation |
| **Conversion** | 49 | format translation to cloud-native GeoParquet, PMTiles, and COG |
| **Network** | 26 | connectivity, cost distance, and routing analysis |
| **Projection** | 4 | reprojection for raster and vector data |

Any tool is deep-linkable with a `?tool=` URL parameter that preselects it and
pre-fills its form. See the [Processing Tools guide](https://geolibre.app/user-guide/processing/#whitebox-toolbox)
for details, and [Geoprocessing in the Browser](https://youtu.be/W32bIQO_nG8) for
a video walkthrough.

## Documentation

Full documentation, including the User Guide and Tutorials, is published at
**[geolibre.app](https://geolibre.app)**.

- **[Getting Started](https://geolibre.app/getting-started/)** - use GeoLibre on the web, desktop, Android, iOS, or in Jupyter; run it from source; run it with Docker; and configure optional credentials.
- **[Features](https://geolibre.app/features/)** - the complete, feature-by-feature list of what GeoLibre can do today.
- **[Demos](https://geolibre.app/demos/)** - a visual tour: 3D Tiles, 3D city data, planetary basemaps, the SQL Workspace, and embeds.
- **[Downloads](https://geolibre.app/downloads/)** - installers and package managers for Windows, macOS, and Linux.
- **[User Guide](https://geolibre.app/user-guide/interface/)** - a feature-by-feature reference for the interface, adding data, layers, styling, the attribute table, map controls, processing, the SQL Workspace, data integrations, plugins, settings, and embedding.
- **[Tutorials](https://geolibre.app/tutorials/)** - hands-on, end-to-end workflows: your first map, cloud-native data, vector analysis, terrain analysis, spatial SQL, and sharing and embedding.
- **Reference**
  - [Architecture](docs/architecture.md)
  - [Android](docs/android.md)
  - [iOS](docs/ios.md)
  - [Project format](docs/project-format.md)
  - [Plugin API](docs/plugin-api.md)
  - [UI Profiles](docs/ui-profiles.md)
  - [Internationalization](docs/i18n.md)
  - [Python package (Jupyter)](docs/python.md)
  - [R package (RStudio, Quarto, and Shiny)](docs/r.md)
  - [Notebook Panel](docs/notebook.md)
  - [Roadmap](docs/roadmap.md)
  - [Contributing](docs/contributing.md)
  - [How to Cite](docs/citation.md)
  - [Become a Sponsor](docs/sponsor.md)

Contributions are welcome. See the [Contributing](docs/contributing.md) guide
for the development setup, repository layout, and quality gate.

## Sponsor

GeoLibre is free and open source, and stays that way. If it is useful to you or your team, sponsorship is the most direct way to keep development, hosting, and cross-platform distribution going.

- [**GitHub Sponsors**](https://github.com/sponsors/giswqs) - monthly or one-time, billed through your GitHub account.
- [**Buy Me a Coffee**](https://buymeacoffee.com/giswqs) - a quick one-off contribution, no account required.

See the [Become a Sponsor](https://geolibre.app/sponsor/) page for what sponsorship supports and for other, free ways to help.

## Acknowledgements

GeoLibre is built on the free and open-source geospatial and web communities — including MapLibre GL JS, deck.gl, DuckDB-WASM Spatial, Turf.js, Tauri, React, and many more. See the full [Acknowledgements](https://geolibre.app/acknowledgements/) page for the complete list of projects and community contributors.

- The **Atmosphere Effects** plugin (deep-space backdrop, parallax starfield, comets, and the globe atmosphere halo) adapts the technique and visual design from [Leonel Dias](https://leoneljdias.github.io/)'s article [*Globe atmosphere, halo, and comets*](https://leoneljdias.github.io/posts/globe-atmosphere-halo-comets/) — the layered Canvas 2D approach, the halo gradient and "screen" blend, the limb-sampling that keeps the halo aligned under pitch, and the starfield/comet parameters.
- **Community contributors** — thanks to [**Ryanphoenix**](https://github.com/Ryanphoenix) for many valued contributions, including issue reports, feedback, and improvements.
- **Beta testers** — thanks to [**René van der Velde**](https://github.com/renevandervelde) (Netherlands) for early testing, detailed bug reports, and feature requests.

## Citation

If you use GeoLibre in your work, please cite it. GeoLibre is archived on [Zenodo](https://zenodo.org/), which mints a DOI for every release. The concept DOI below always resolves to the latest version.

[](https://doi.org/10.5281/zenodo.20785400)

> Wu, Q. (2026). GeoLibre: A lightweight, cloud-native GIS platform for visualizing, exploring, and analyzing geospatial data. Zenodo. <https://doi.org/10.5281/zenodo.20785400>

You can also use GitHub's **"Cite this repository"** button (which reads [`CITATION.cff`](CITATION.cff)) to copy a ready-made APA or BibTeX entry. See the [How to Cite](https://geolibre.app/citation/) page for more formats.

## License

[MIT](LICENSE)

---

## File: apps/geolibre-desktop/public/plugins/README.md

# Bundled plugins (drop-in folder)

Drop a plugin here to **bake it into the GeoLibre build**. It loads
automatically on startup with no Settings entry and no manifest URL — on both
the **web** build and the **desktop** build (the desktop app ships the same
frontend, so one folder serves both).

## Layout

One folder per plugin, named by its plugin id, with a `plugin.json` at its root
(the exact same content a manifest URL would serve):

```text
public/plugins/
  my-plugin/
    plugin.json        # { "id", "name", "version", "entry", "style"? }
    dist/
      index.js         # the "entry" referenced by plugin.json
      style.css        # the optional "style" referenced by plugin.json
```

`entry` and `style` in `plugin.json` are resolved relative to the manifest, so
keep them inside the plugin's own folder.

## How it works

The `bundledPlugins()` Vite plugin
(`apps/geolibre-desktop/vite-plugins/bundled-plugins.ts`) scans this directory
at build and dev-server start and exposes the discovered manifest paths via the
`virtual:bundled-plugins` module. `usePlugins.ts` turns those into origin-absolute
URLs and loads them through the normal external-plugin path (fetch → blob import
→ register). Adding or removing a plugin is just adding or removing a folder —
no code changes.

Discovery happens at **build time**, so a dev server or production build must be
(re)started after adding, updating, or removing a plugin folder.

## Private plugins

The bundles are **git-ignored** (see `.gitignore`) so private plugin code stays
out of this repo's history. Copy the plugin folder in at build/deploy time (for
example, in CI before `npm run build`, or with a plugin repo's own install
script). The discovery code is generic and committed; only the plugin payload
is excluded.

---

## File: backend/geolibre_server/README.md

# GeoLibre Server (Python sidecar)

Optional FastAPI backend for heavy geoprocessing. **Not required** to run GeoLibre Desktop UI.

## Install

```bash
cd backend/geolibre_server
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install -e .
```

## Run

```bash
uvicorn geolibre_server.app.main:app --host 127.0.0.1 --port 8765 --reload
```

Or:

```bash
geolibre-server
```

## Test

```bash
python -m pytest
```

## Whitebox runtime

Whitebox tools use a dedicated GeoLibre-managed Python environment. On first
use, the sidecar looks for `uv`; if it is not available, it downloads the
official uv standalone installer and installs uv into the GeoLibre runtime cache.
It then creates a Whitebox virtual environment and installs
`whitebox-workflows`.

Useful overrides:

```bash
GEOLIBRE_RUNTIME_DIR=/path/to/cache
GEOLIBRE_UV=/path/to/uv
GEOLIBRE_UV_DIR=/path/to/managed-uv
GEOLIBRE_WHITEBOX_ENV=/path/to/whitebox-venv
GEOLIBRE_WHITEBOX_PACKAGE='whitebox-workflows>=2.0.2'
WBW_EXTERNAL_PYTHON=/path/to/python
```

## Conversion runtime

The **Processing → GeoLibre Toolbox → Conversion** menu uses a dedicated managed
runtime (DuckDB + rio-cogeo + freestiler), bootstrapped the same way as Whitebox:
the sidecar finds or installs `uv`, creates a virtual environment, and installs
the conversion packages on first use.

- **Vector → GeoParquet** and **CSV → GeoParquet** also run entirely in the
  browser with DuckDB-WASM, so they work in the web build with **no sidecar**.
- **Vector → FlatGeobuf**, **Vector → PMTiles**, and **Raster → COG** have no
  in-browser writer and require the sidecar.

To enable them, install the optional extras and run the sidecar:

```bash
pip install -e ".[conversion]"
geolibre-server
```

For the **web** build, serve the app from `localhost:5173` — CORS is restricted
to that origin and the Tauri origins, so other ports cannot reach the sidecar.

Useful overrides:

```bash
GEOLIBRE_CONVERSION_PYTHON=/path/to/python   # reuse an existing env (skip bootstrap)
GEOLIBRE_CONVERSION_ENV=/path/to/venv        # managed runtime location
GEOLIBRE_CONVERSION_PACKAGES='duckdb>=1.1.0 rio-cogeo>=5.0.0 freestiler>=0.1.0'  # whitespace-separated
GEOLIBRE_CONVERSION_ROOTS=/data:/srv/geo      # confine inputs/outputs to these roots (os.pathsep-separated; unset = no restriction)
```

When the sidecar is reachable by untrusted same-origin content (e.g. the
bundled Docker image), set `GEOLIBRE_CONVERSION_ROOTS` so conversions cannot
read or overwrite arbitrary filesystem paths. It is unset by default for the
desktop app, where paths are the user's own filesystem.

## Spatial SQL runtime (Apache Sedona)

The **Apache Sedona** engine of the SQL Workspace runs Sedona spatial SQL on
[SedonaDB](https://sedona.apache.org/sedonadb/) (the single-node Rust engine)
through the `/sql` endpoints. It is an optional extra:

```bash
pip install -e ".[sedona]"   # 'apache-sedona[db]' + geopandas + shapely
geolibre-server
```

The sidecar reports availability through `/sql/status`. When the extra is **not**
installed (or the sidecar is not running), the SQL Workspace falls back to the
in-browser [CereusDB](https://github.com/tobilg/cereusdb) engine — a WebAssembly
build of SedonaDB — so the Apache Sedona engine works with **no sidecar** too.
`/sql/run` registers each posted layer as a named view, runs one statement, and
returns rows (geometry as WKT) plus a GeoJSON FeatureCollection when the result
has a geometry column.

## PostGIS connections

The optional PostGIS endpoints are disabled until their database destinations
are explicitly allowed. Set `GEOLIBRE_POSTGIS_HOSTS` to a comma-separated list
of exact hostnames or IP addresses before starting the sidecar:

```bash
GEOLIBRE_POSTGIS_HOSTS='db.internal,db.example.com:5433,[2001:db8::10]:5432'
geolibre-server
```

An entry without a port allows that host on any port; include `:port` to
restrict it. IPv6 entries must be bracketed either way (`[2001:db8::10]`),
since an unbracketed `2001:db8::10:5432` is itself a valid address rather than
an address and a port. Every host in a libpq failover connection string must be allowed.
Implicit local connections, Unix sockets, `service=`, and `hostaddr=`
connection strings are rejected so they cannot bypass the allowlist.

Set it to `*` — on its own, since mixing it with hosts reads as a narrowing but
is not one — to lift the restriction and accept any connection string. The
**desktop app** passes `*` when it spawns its own sidecar — that one is
loopback-bound, token-authenticated, and serves the single user who is also its
operator. Setting the variable before launching the desktop app overrides that
default, so a desktop user can still narrow it. A deployment where the sidecar
is reachable by untrusted same-origin content (the bundled Docker image) leaves
it unset, and PostGIS stays off until an operator lists the databases.

## Endpoints

| Method | Path | Description |
|--------|------|-------------|
| GET | `/health` | Health check |
| GET | `/algorithms` | List algorithms |
| POST | `/run` | Run algorithm (501 placeholder) |
| GET | `/conversion/status` | Conversion runtime availability |
| POST | `/conversion/vector-to-geoparquet` | Vector → Hilbert-sorted GeoParquet |
| POST | `/conversion/vector-to-flatgeobuf` | Vector → Hilbert-sorted FlatGeobuf |
| POST | `/conversion/csv-to-geoparquet` | CSV (lon/lat) → GeoParquet |
| POST | `/conversion/vector-to-pmtiles` | Vector → PMTiles (freestiler) |
| POST | `/conversion/raster-to-cog` | Raster → Cloud Optimized GeoTIFF |
| GET | `/conversion/jobs/{id}` | Conversion job status |
| GET | `/sql/status` | Spatial SQL (SedonaDB) availability |
| POST | `/sql/run` | Run Sedona spatial SQL over registered layers |
| GET | `/ml/status` | Segmentation backend availability + models |
| POST | `/ml/segment/text` | Text-prompt segmentation (SAM 3) |
| POST | `/ml/segment/automatic` | Automatic mask generation |
| POST | `/ml/segment/predict` | Box/point prompt segmentation |

## AI segmentation runtime (SamGeo / SAM 3)

The `/ml` endpoints back GeoLibre's AI segmentation toolbox. They are a thin
reverse-proxy in front of a **separate `samgeo-api` server** (the REST server
shipped with [segment-geospatial](https://github.com/opengeos/segment-geospatial)),
which runs SAM 3 and returns GeoJSON. The heavy model stack (PyTorch + SAM 3) is
**not** imported into this sidecar; install and run it on its own (ideally on a
GPU host):

```bash
# the model server (in an env with a working PyTorch build)
pip install "segment-geospatial[api,samgeo3]"
# the sidecar's ml extra (just an HTTP client)
pip install -e ".[ml]"
```

`samgeo-api` is launched on demand when it is on the `PATH`, otherwise the proxy
returns `available: false` with an actionable message. The desktop app runs the
sidecar in a managed (uv) environment that includes the `ml` extra but not
`segment-geospatial`, so `samgeo-api` is not on its `PATH`; launch the desktop
app with `GEOLIBRE_ML_SAMGEO_URL` set to an external `samgeo-api` (the spawned
sidecar inherits the app's environment). Configuration:

| Variable | Purpose |
|----------|---------|
| `GEOLIBRE_ML_SAMGEO_URL` | Proxy to an already-running `samgeo-api` (no child process is launched). |
| `GEOLIBRE_ML_SAMGEO_CMD` | Command to launch `samgeo-api` on demand (default `samgeo-api`). |
| `GEOLIBRE_ML_DEFAULT_MODEL` | Model the UI defaults to (default `sam3`). |

Each `/ml/segment/*` request takes a multipart `file` plus `model_version`
(default `sam3`) and `output_format` (default `geojson`).

## Future stack

The sidecar will further integrate (see `docs/roadmap.md`):

- **Leafmap** — notebook-style geospatial utilities

GDAL/Rasterio (raster tools), GeoPandas (vector engine), DuckDB Spatial
(conversion), WhiteboxTools, Apache Sedona (spatial SQL), and GeoAI/SamGeo
segmentation now ship as optional extras (`raster`, `vector`, `conversion`,
`whitebox`, `sedona`, `ml`).

Tauri will bundle the sidecar as an `externalBin` in a later release.

---

## File: docs/tutorials/cloud-native-data.md

# Cloud-Native Data

GeoLibre is built for cloud-native geospatial formats: GeoParquet and FlatGeobuf for vector, Cloud-Optimized GeoTIFF (COG) for raster, and PMTiles for tiles. This tutorial loads them from remote URLs and converts a local dataset.

## Load a remote GeoParquet

GeoParquet is a compressed, columnar vector format that reads well over HTTP.

1. Open **Add Data → GeoParquet Layer** (or **Vector Layer**).
2. Enter a GeoParquet URL, for example:
   ```text
   https://data.source.coop/giswqs/opengeos/countries.parquet
   ```
3. To avoid copying a large file into memory, enable **Stream GeoParquet (no copy)**, which queries it in place with HTTP range requests. This works best for large remote files whose rows are spatially sorted (for example, Hilbert order, as written by GeoLibre's own Conversion tools), so only the relevant row groups are fetched.
4. Click **Load**.

## Load a FlatGeobuf

FlatGeobuf is a streaming-friendly vector format with a spatial index.

1. Open **Add Data → FlatGeobuf Layer**.
2. Enter a `.fgb` URL and load it. GeoLibre fetches only the features in view where the format allows.

## Load a COG

A Cloud-Optimized GeoTIFF is a regular GeoTIFF organized so clients can read just the tiles they need.

1. Open **Add Data → Raster Layer**.
2. Enter the URL of a COG (`.tif`) and load it. You can then adjust brightness, contrast, saturation, and hue in the [Style panel](../user-guide/styling.md).

!!! tip "Drag and drop"
    You can also drag a local GeoTIFF or COG onto the map to add it as a raster layer. See [Adding Data](../user-guide/adding-data.md#drag-and-drop).

## Convert local data to cloud-native

Use **Processing → GeoLibre Toolbox → Conversion** to write cloud-native files. See [Processing Tools](../user-guide/processing.md#conversion).

- **Vector to GeoParquet** and **CSV to GeoParquet** run in the browser with DuckDB-WASM.
- **Vector to FlatGeobuf**, **Vector to PMTiles**, and **Raster to COG** run on the Python sidecar (desktop app).

For example, to publish a local GeoJSON as GeoParquet:

1. Open **Processing → GeoLibre Toolbox → Conversion → Vector to GeoParquet**.
2. Choose the input file and an output path.
3. Run the conversion, then add the resulting GeoParquet back to the map to verify it.

## Next steps

- Query these formats directly in [Spatial SQL](spatial-sql.md); the SQL Workspace reads Parquet, CSV, JSON, and GeoJSON from URLs.
- Animate a time series of COGs with the Time Slider plugin. See [Data Integrations](../user-guide/data-integrations.md).

---

## File: docs/tutorials/first-map.md

# Your First Map

This tutorial takes you from an empty workspace to a styled map with inspectable data, in a few minutes. You can do all of it in the [live viewer](https://web.geolibre.app/).

## 1. Open GeoLibre

Open [web.geolibre.app](https://web.geolibre.app/), or launch the desktop app. You start with a basemap and an empty [Layers panel](../user-guide/layers.md).

## 2. Add a layer

1. Open **Add Data → Vector Layer**.
2. In the Add Vector panel, enter a vector URL. You can use the sample countries dataset:
   ```text
   https://data.source.coop/giswqs/opengeos/countries.parquet
   ```
3. Click **Load**. The countries appear on the map and a `countries` layer is added to the Layers panel.



See [Adding Data](../user-guide/adding-data.md) for every supported source.

## 3. Style the layer

1. Select the `countries` layer in the Layers panel, then expand the [Style panel](../user-guide/styling.md) on the right if it is collapsed.
2. Adjust the **Fill color**, **Outline color**, and **Fill opacity** to taste.
3. To make a choropleth, set **Style type** to **Graduated**, pick a numeric field (for example a population or GDP column), choose a **Colormap**, and click **Apply style type**.

## 4. Inspect the data

1. Click **Attribute table** on the status bar to expand it, then select the `countries` layer to load its records. See [Attribute Table](../user-guide/attribute-table.md).
2. Sort by a column, or filter to find a feature. Selecting a row highlights it on the map.
3. You can also turn on **Identify features** for the layer and click a country on the map to see its attributes in a popup.

## 5. Save or share

- In the desktop app, use **Project → Save** to write a `.geolibre.json` file.
- Anywhere, use **Project → Share** to upload the project and get a public link. See [Sharing & Embedding](sharing-embedding.md).

## Next steps

- Load cloud-native and remote formats in [Cloud-Native Data](cloud-native-data.md).
- Run geometry tools in [Vector Analysis](vector-analysis.md).
- Query your data in [Spatial SQL](spatial-sql.md).

---

## File: docs/tutorials/index.md

# Tutorials

These tutorials walk through common GeoLibre workflows end to end. Each one is short, builds on the [User Guide](../user-guide/interface.md), and links back to the reference pages for the features it uses.

## Before you start

- You can follow most tutorials in the **live viewer** at [web.geolibre.app](https://web.geolibre.app/), which is the browser build of GeoLibre. No installation required.
- A few steps need the **desktop app**: opening and saving project files, reading local MBTiles and rasters, and the Python sidecar tools (raster processing and sidecar conversions). These are called out where they appear. See [Downloads](../downloads.md) to install. The Whitebox geoprocessing toolbox is not among them — its 1,000+ tools run in the browser on WebAssembly.
- The sample dataset used in several tutorials is a public GeoParquet file of world countries: `https://data.source.coop/giswqs/opengeos/countries.parquet`.

## The tutorials

| Tutorial | You will learn to |
| --- | --- |
| [Your First Map](first-map.md) | Add a layer, style it, inspect attributes, and save. |
| [Cloud-Native Data](cloud-native-data.md) | Load remote GeoParquet, FlatGeobuf, and COG, and convert local data. |
| [Vector Analysis](vector-analysis.md) | Buffer and overlay layers, then export the result. |
| [Terrain Analysis](terrain-analysis.md) | Derive hillshade, slope, and contours from a DEM. |
| [Spatial SQL](spatial-sql.md) | Query data with DuckDB Spatial and map the results. |
| [Sharing & Embedding](sharing-embedding.md) | Share a project and embed it in a web page. |

Work through them in order for a guided tour, or jump to the one that matches your task.

## Video tutorials

- [GeoLibre 1.0: A Free, Open-Source Cloud-Native GIS That Runs Anywhere (Browser, Desktop & Jupyter)](https://youtu.be/87Cm0QagtxI)
- [Geoprocessing in the Browser: 700+ Free GIS Tools in GeoLibre, Zero Install](https://youtu.be/W32bIQO_nG8)
- [GeoLibre + GeoLens: A Modern GIS Stack for Self-Hosting Geospatial Data](https://youtu.be/kQqgrxXGd4o)

---

## File: docs/tutorials/sharing-embedding.md

# Sharing & Embedding

Once you have a map you like, you can publish it as a public link and embed it in any web page. This tutorial covers both. See [Embedding & Sharing](../user-guide/embedding.md) for the full reference.

## 1. Set your share token

Sharing uploads to `share.geolibre.app` using a personal API token.

1. Open **Settings → Environment Variables**.
2. Paste your token into the **Share.GeoLibre API token** field. Create one under Settings → API tokens at [share.geolibre.app/settings](https://share.geolibre.app/settings).

You only need to do this once.

## 2. Share the project

1. Build your map: add layers, style them, and set the map view you want viewers to land on.
2. Open **Project → Share...**.
3. Confirm the project title and upload. GeoLibre returns a public URL to a `.geolibre.json` file, for example:
   ```text
   https://share.geolibre.app/you/my-map.geolibre.json
   ```

The shared file captures the same layers, styles, plugin state, and map view as a local save.

## 3. Open the shared map

Anyone can open the shared project in the live viewer by passing it as the `url` parameter:

```text
https://web.geolibre.app/?url=https://share.geolibre.app/you/my-map.geolibre.json
```

## 4. Embed it in a page

Use an `` and the embed parameters to control the chrome. For a clean, map-only embed:

```html

```

Adjust the look with parameters (they combine):

- `maponly` hides all chrome, leaving only the map.
- `layout=viewer` gives a read-only map: Layers, View, Controls, basemaps, and
  search/identify stay, while everything that edits the project is hidden.
- `layout=compact` keeps a slim, icon-only toolbar.
- `toolbar=none` hides the top toolbar while keeping panels and the status bar.
- `panels=none` hides the side and bottom panels but keeps the toolbar.
- `theme=dark` forces the dark theme on load.

Reach for `layout=viewer` when readers should be able to toggle layers and
explore the data but not change it, and `maponly` when the map is a figure in
your page rather than something to interact with.

See the full [parameter table](../user-guide/embedding.md#url-parameters).

## 5. Drive the map from your page

URL parameters configure the embed once, at load. To keep talking to it — fly to
the record someone just clicked in your own UI, and hear what they do inside the
map — install the typed client:

```bash
npm install @geolibre/embed
```

```ts
import { connect } from "@geolibre/embed";

const map = await connect(document.querySelector("iframe"), {
  origin: "https://web.geolibre.app",
});

map.on("selectionChanged", ({ featureIds }) => showRecordFor(featureIds[0]));

async function focusField(field) {
  await map.setView({ bbox: field.bbox });
  await map.highlightFeature({ layerId: "fields", filter: { parcel_id: field.id }, fit: true });
}
```

This works only against a deployment that has allowlisted your page's origin —
`web.geolibre.app` has not, so the runtime API is for your own hosted build. See
[Talking to the map at runtime](../user-guide/embedding.md#talking-to-the-map-at-runtime)
for the allowlist, the full command list, and the raw `postMessage` protocol if
you would rather not add a dependency.

## Next steps

- Tune which controls appear before sharing with the [Controls menu](../user-guide/map-controls.md).
- Revisit [Your First Map](first-map.md) to build the map you want to share.

---

## File: docs/tutorials/spatial-sql.md

# Spatial SQL

The [SQL Workspace](../user-guide/sql-workspace.md) lets you analyze data with DuckDB Spatial SQL and add the results to the map. It runs on DuckDB-WASM, so it works in the browser as well as the desktop app. Open it from **Processing → SQL Workspace**.

## 1. Query a loaded layer

Every loaded vector layer is a queryable table. Load the sample countries layer (see [Your First Map](first-map.md)), then run:

```sql
SELECT NAME, CONTINENT, GDP_MD_EST
FROM countries
ORDER BY GDP_MD_EST DESC
LIMIT 10;
```

Click **Run** to see the ten countries with the highest estimated GDP.

!!! note "Sample dataset columns"
    `NAME`, `CONTINENT`, `POP_EST`, and `GDP_MD_EST` are Natural Earth field names in the sample `countries.parquet`, whose geometry column is `geom`. A different dataset will have its own column names. To discover them, run `DESCRIBE SELECT * FROM 'your-file-url'` first.

## 2. Query a remote file directly

You do not have to load a file first. The Workspace detects a bare URL in a `FROM` clause and wraps it in the right reader automatically, then streams the file over HTTP range requests so you do not download it in full. This bare-URL shorthand is a SQL Workspace convenience; in the standard DuckDB CLI you would write `read_parquet('https://...')` explicitly.

```sql
SELECT COUNT(*) AS n
FROM https://data.source.coop/giswqs/opengeos/countries.parquet;
```

## 3. Use spatial functions

The spatial extension is loaded, so `ST_*` functions are available. For example, compute area and keep the `geom` column so the result can be mapped:

```sql
-- area is in square degrees because the data is in EPSG:4326;
-- the ranking is valid, but use ST_Area_Spheroid(geom) / 1e6 for km2.
SELECT NAME, ST_Area(geom) AS area, geom
FROM https://data.source.coop/giswqs/opengeos/countries.parquet
WHERE CONTINENT = 'Africa'
ORDER BY area DESC;
```

## 4. Add the result to the map

When a query returns a geometry column, use **add to map** to create a new layer from the result, optionally naming it. The result layer supports [identify, selection, and the attribute table](../user-guide/attribute-table.md) like any vector layer, and you can add several result layers at once.

## 5. Export

Export the query result as **CSV** or **GeoParquet** straight from the workspace. See [SQL Workspace](../user-guide/sql-workspace.md).

!!! tip "Sample queries and history"
    Use the **Sample queries** menus to start from a working query, and the **history** to rerun a previous one.

## Next steps

- Do equivalent geometry operations with the menu-driven [Vector Analysis](vector-analysis.md) tools.
- Convert results to cloud-native formats in [Cloud-Native Data](cloud-native-data.md).

---

## File: docs/tutorials/terrain-analysis.md

# Terrain Analysis

This tutorial derives terrain products from a digital elevation model (DEM): a hillshade, a slope map, and contour lines. It uses the [Raster tools](../user-guide/processing.md#raster) under **Processing → GeoLibre Toolbox → Raster**.

!!! note "Desktop app required"
    The raster tools run on the rasterio Python sidecar, which the desktop app manages. They are not available in the browser build. See [Getting Started](../getting-started.md#optional-python-sidecar).

## 1. Load a DEM

Add an elevation raster as a layer, for example a GeoTIFF or COG DEM (see [Adding Data](../user-guide/adding-data.md)). The raster tools take a file path in and write a file path out, so a local or accessible raster works best.

## 2. Hillshade

1. Open **Processing → GeoLibre Toolbox → Raster → Hillshade**.
2. Choose the DEM as input and set the azimuth, altitude, and z-factor if you want to adjust the lighting.
3. Run it. The shaded-relief raster is added to the map. Place it under your other layers and lower their opacity for a relief backdrop.

## 3. Slope and aspect

- **Processing → GeoLibre Toolbox → Raster → Slope** computes steepness from the DEM.
- **Processing → GeoLibre Toolbox → Raster → Aspect** computes the compass direction of the steepest slope.

Run either against the DEM and style the output with a [colormap](../user-guide/styling.md). Open the **Colorbar** from the [Controls menu](../user-guide/map-controls.md) to show the value scale.

## 4. Contours

1. Open **Processing → GeoLibre Toolbox → Raster → Contour**.
2. Choose the DEM and set the contour **interval** (the elevation difference between lines).
3. Run it to generate contour lines as a vector layer, which you can label and style like any vector data.

## 5. Clip to an area of interest

To restrict outputs to a study area, use **Processing → GeoLibre Toolbox → Raster → Clip by extent** (a bounding box) or **Clip by mask layer** (a vector mask). See [Processing Tools](../user-guide/processing.md#raster).

## Next steps

- Convert raster outputs to vectors with **Polygonize**, or write a **Raster to COG** for sharing. See [Cloud-Native Data](cloud-native-data.md).
- Animate a time series of rasters with the Time Slider plugin. See [Data Integrations](../user-guide/data-integrations.md).

---

## File: docs/tutorials/vector-analysis.md

# Vector Analysis

This tutorial runs a small vector workflow: buffer a layer, overlay it with another, and export the result. It uses the [Vector tools](../user-guide/processing.md#vector) under **Processing → GeoLibre Toolbox → Vector**.

## 1. Load input data

Add at least one vector layer (see [Adding Data](../user-guide/adding-data.md)). For an overlay you will need two layers, for example a set of points or lines and a polygon layer to clip against.

## 2. Buffer a layer

1. Open **Processing → GeoLibre Toolbox → Vector → Buffer**.
2. Set **Input layer** to your layer.
3. Set the **Distance** and **Units** (kilometers, meters, or miles).
4. Choose an **Engine**:
   - **Client (Turf.js)** runs in the browser with no setup.
   - **Sidecar (GeoPandas)** runs on the Python sidecar for projection-aware distances (desktop app).
5. Click **Run**. A buffered layer is added to the map.

!!! tip "Projection-aware distances"
    The client engine buffers in geographic coordinates. For accurate metric distances over large areas, use the GeoPandas sidecar engine, which reprojects before buffering.

## 3. Overlay two layers

With the buffer (or any polygon layer) and a second layer, run an overlay:

- **Clip** keeps the part of the input that falls inside the overlay, preserving the input's attributes.
- **Intersection** keeps only the overlapping areas of two polygon layers.
- **Difference** removes the overlay's area from the input.
- **Union** merges two polygon layers into one (attributes are not preserved, on either engine).
- **Spatial join** attaches a join layer's attributes to each input feature based on a spatial relationship (intersects, within, or contains) — for example, tagging each point with the polygon that contains it. Works with any geometry type.
- **Attribute join** attaches a join table's attributes to each input feature where a key field matches — no geometry involved (for example, joining census statistics to boundary polygons by a shared FIPS code). It is one-to-one (the first matching join row wins); pick the key field on each side, optionally list which fields to bring over, and choose an inner or left join.

Open the tool from **Processing → GeoLibre Toolbox → Vector**, pick the input and overlay layers, and **Run**.

## 4. Inspect and refine

Open the [Attribute table](../user-guide/attribute-table.md) on the result layer to check the output, and adjust its [style](../user-guide/styling.md) so it stands out from the inputs.

## 5. Export the result

To save the output as a cloud-native file, use **Processing → GeoLibre Toolbox → Conversion** (for example **Vector to GeoParquet** or **Vector to FlatGeobuf**). See [Cloud-Native Data](cloud-native-data.md). You can also export records from the [Attribute table](../user-guide/attribute-table.md) or the [SQL Workspace](../user-guide/sql-workspace.md).

## Next steps

- Do the same kind of analysis in SQL with [Spatial SQL](spatial-sql.md).
- Move to raster analysis in [Terrain Analysis](terrain-analysis.md).

## 2. Official Technical Reference & Guides (opengeos/opengeos.github.io)

# Open Geospatial Solutions

## Introduction

The Open Geospatial Solutions ([opengeos](https://github.com/opengeos)) GitHub organization hosts a collection of open-source geospatial software projects. The projects are developed by a community of geospatial software developers and researchers. The projects are maintained by the community and are free to use and modify. The projects are open-source and are licensed under the MIT license. If you are interested in hosting an open-source project with us, please submit a request on the [Discussion Board](https://github.com/opengeos/opengeos.github.io/discussions). We always welcome new contributors and collaborators.

## OAuth Application

Open Geospatial Solutions is the public home page for the Open Geospatial Solutions OAuth application. The app is used by OpenGeoS geospatial tools, notebooks, plugins, and web applications to let users sign in with Google and, only after user consent, connect to the Google services needed for geospatial workflows such as mapping, data access, catalog exploration, and analysis.

The app requests only the Google permissions required by the specific OpenGeoS tool a user chooses to run. User data is used to provide the requested geospatial workflow and is handled according to the [Privacy Policy](https://opengeos.org/privacy/) and [Terms of Service](https://opengeos.org/terms/).

Join our Discord server 👇

[](https://discord.gg/UgZecTUq5P)

## Python Packages

- [anymap](https://github.com/opengeos/anymap)
- [geemap](https://github.com/gee-community/geemap)
- [GeoAgent](https://github.com/opengeos/GeoAgent)
- [geoai](https://github.com/opengeos/geoai)
- [geospatial](https://github.com/opengeos/geospatial)
- [geospatial-ml](https://github.com/opengeos/geospatial-ml)
- [HyperCoast](https://github.com/opengeos/HyperCoast)
- [leafmap](https://github.com/opengeos/leafmap)
- [lidar](https://github.com/opengeos/lidar)
- [mapwidget](https://github.com/opengeos/mapwidget)
- [open-buildings](https://github.com/opengeos/open-buildings)
- [pygis](https://github.com/opengeos/pygis)
- [segment-geospatial](https://github.com/opengeos/segment-geospatial)
- [whitebox-python](https://github.com/opengeos/whitebox-python)
- [whiteboxgui](https://github.com/opengeos/whiteboxgui)

## Data Catalogs

- [geospatial-data-catalogs](https://github.com/opengeos/geospatial-data-catalogs)
- [aws-open-data](https://github.com/opengeos/aws-open-data)
- [aws-open-data-geo](https://github.com/opengeos/aws-open-data-geo)
- [aws-open-data-stac](https://github.com/opengeos/aws-open-data-stac)
- [Earth-Engine-Catalog](https://github.com/opengeos/Earth-Engine-Catalog)
- [NASA-CMR-STAC](https://github.com/opengeos/NASA-CMR-STAC)
- [NASA-Earth-Data](https://github.com/opengeos/NASA-Earth-Data)
- [stac-index-catalogs](https://github.com/opengeos/stac-index-catalogs)
- [maxar-open-data](https://github.com/opengeos/maxar-open-data)
- [datasets](https://github.com/opengeos/datasets)
- [data](https://github.com/opengeos/data)
- [ee-tile-layers](https://github.com/opengeos/ee-tile-layers)

## QGIS Plugins

- [Basemaps](https://github.com/opengeos/qgis-basemaps)
- [CDSE](https://github.com/opengeos/qgis-cdse-plugin)
- [Earth Engine Data Catalogs](https://github.com/opengeos/qgis-gee-data-catalogs-plugin)
- [Geemap](https://github.com/opengeos/qgis-geemap-plugin)
- [GeoAI](https://github.com/opengeos/geoai)
- [HyperCoast](https://github.com/opengeos/HyperCoast)
- [Leafmap](https://github.com/opengeos/qgis-leafmap-plugin)
- [Map](https://github.com/opengeos/qgis-map)
- [Maxar Open Data](https://github.com/opengeos/qgis-maxar-plugin)
- [NASA Earthdata](https://github.com/opengeos/qgis-nasa-earthdata-plugin)
- [NASA OPERA](https://github.com/opengeos/qgis-nasa-opera-plugin)
- [Notebook](https://github.com/opengeos/qgis-notebook-plugin)
- [OpenGeoAgent](https://geoagent.gishub.org/qgis-plugin)
- [Plugin Template](https://github.com/opengeos/qgis-plugin-template)
- [SamGeo](https://github.com/opengeos/qgis-samgeo-plugin)
- [STAC](https://github.com/opengeos/qgis-stac-plugin)
- [Terminal](https://github.com/opengeos/qgis-terminal-plugin)
- [Terrascope](https://github.com/opengeos/qgis-terrascope-plugin)
- [Timelapse](https://github.com/opengeos/qgis-timelapse-plugin)
- [Whitebox AI Agent](https://github.com/opengeos/qgis-whitebox-agent)

## MapLibre GL JS Plugins

- [maplibre-gl-components](https://github.com/opengeos/maplibre-gl-components)
- [maplibre-gl-earth-engine](https://github.com/opengeos/maplibre-gl-earth-engine)
- [maplibre-gl-extend](https://github.com/opengeos/maplibre-gl-extend)
- [maplibre-gl-geo-editor](https://github.com/opengeos/maplibre-gl-geo-editor)
- [maplibre-gl-geoagent](https://github.com/opengeos/maplibre-gl-geoagent)
- [maplibre-gl-html-widget](https://github.com/opengeos/maplibre-gl-html-widget)
- [maplibre-gl-layer-control](https://github.com/opengeos/maplibre-gl-layer-control)
- [maplibre-gl-layer-manager](https://github.com/opengeos/maplibre-gl-layer-manager)
- [maplibre-gl-lidar](https://github.com/opengeos/maplibre-gl-lidar)
- [maplibre-gl-noaa-lidar](https://github.com/opengeos/maplibre-gl-noaa-lidar)
- [maplibre-gl-planetary-computer](https://github.com/opengeos/maplibre-gl-planetary-computer)
- [maplibre-gl-plugin-template](https://github.com/opengeos/maplibre-gl-plugin-template)
- [maplibre-gl-splat](https://github.com/opengeos/maplibre-gl-splat)
- [maplibre-gl-storymaps](https://github.com/opengeos/maplibre-gl-storymaps)
- [maplibre-gl-streetview](https://github.com/opengeos/maplibre-gl-streetview)
- [maplibre-gl-swipe](https://github.com/opengeos/maplibre-gl-swipe)
- [maplibre-gl-time-slider](https://github.com/opengeos/maplibre-gl-time-slider)
- [maplibre-gl-typescript-examples](https://github.com/opengeos/maplibre-gl-typescript-examples)
- [maplibre-gl-usgs-lidar](https://github.com/opengeos/maplibre-gl-usgs-lidar)

## R Packages

- [whiteboxR](https://github.com/opengeos/whiteboxR)

## ArcGIS Toolboxes

- [WhiteboxTools-ArcGIS](https://github.com/opengeos/WhiteboxTools-ArcGIS)

## Web Apps

- [streamlit-geospatial](https://github.com/opengeos/streamlit-geospatial)
- [streamlit-map-template](https://github.com/opengeos/streamlit-map-template)
- [solara-geemap](https://github.com/opengeos/solara-geemap)
- [solara-geospatial](https://github.com/opengeos/solara-geospatial)
- [solara-template](https://github.com/opengeos/solara-template)
- [solara-maxar](https://github.com/opengeos/solara-maxar)
- [voila-geospatial](https://github.com/opengeos/voila-geospatial)
- [geospatial-dataviz](https://github.com/opengeos/geospatial-dataviz)
- [surface-water-app](https://github.com/opengeos/surface-water-app)

## Useful Resources

- [Awesome-GEE](https://github.com/opengeos/Awesome-GEE)
- [python-geospatial](https://github.com/opengeos/python-geospatial)