Contributing¶
Thanks for your interest in improving GeoLibre. This guide covers how to set up a development environment, the project layout, the local quality gate, and the pull request workflow. Contributions of all sizes are welcome, from fixing a typo to adding a new processing tool or plugin.
By participating, you agree to keep interactions respectful and constructive.
Ways to Contribute¶
- Report a bug or request a feature by opening an issue. Include steps to reproduce, what you expected, and what happened, plus your OS and whether you hit it in the web or desktop build.
- Improve the documentation under
docs/(this site). - Fix a bug or build a feature in the app or one of the packages.
- Write a plugin using the external plugin API (see Plugins below).
If you plan a large change, open an issue first so we can agree on the approach before you invest time in a pull request.
Prerequisites¶
- Node.js 22 or newer
- Rust toolchain (rustup) for Tauri desktop builds
- Linux only:
webkit2gtkandlibayatana-appindicator(see the Tauri prerequisites) - Python 3.10 or newer for pre-commit (the commit hooks below) and, if you work on the backend, the conversion sidecar and its tests
Setup¶
Fork the repository, then clone your fork. Replace YOUR_GITHUB_USERNAME with
your GitHub username:
git clone https://github.com/YOUR_GITHUB_USERNAME/GeoLibre.git
cd GeoLibre
npm install
GeoLibre is an npm workspaces monorepo, so a single npm install at the root
wires up every package. Use npm; the repository tracks package-lock.json.
Run it locally¶
Web build (map in the browser):
npm run dev
Open http://localhost:5173.
Desktop build (Tauri, required for filesystem dialogs, local MBTiles, and local raster reads):
npm run tauri:dev
Repository layout¶
apps/geolibre-desktop # Tauri + React app (shell, composition, Tauri I/O)
packages/core # Domain types, Zustand store, project format
packages/map # MapLibre integration and layer sync
packages/ui # Tailwind + shadcn/ui primitives
packages/plugins # Plugin API and built-in plugins
packages/processing # Client-side algorithm registry
workers/viewer # Cloudflare viewer worker (geolibre-viewer-worker)
backend/geolibre_server # Optional FastAPI conversion sidecar (Python)
docs/ # This documentation site (MkDocs)
See the Architecture reference for how these fit together, and the Project Format reference for the saved project schema.
Development workflow¶
- Create a feature branch off
main. Never commit directly tomain.
git switch -c feat/short-description
- Make your change, keeping it focused. Match the style of the surrounding code rather than introducing new patterns.
- Run the quality checks and confirm they pass.
- Commit with a clear message. The history follows a
Conventional Commits style prefix,
for example
feat:,fix:,docs:,refactor:, orchore:. - Push your branch and open a pull request against
main. Describe what changed and why, and link any related issue.
Pull requests are reviewed before merging. Automated reviewers may leave inline comments; address them or explain why a suggestion does not apply.
Quality checks¶
Run the fast TypeScript unit tests while you work:
npm run test:frontend
Before opening a pull request, run the formatting hooks and the full local quality gate:
pre-commit run --all-files
npm run ci
npm run ci runs the complete gate that mirrors continuous integration:
| Step | Command | Covers |
|---|---|---|
| Build | npm run build |
TypeScript compile and Vite build |
| Frontend tests | npm run test:frontend |
Fast unit tests under tests/ |
| Worker typecheck | npm run test:worker |
The viewer worker package |
| Backend tests | npm run test:backend |
pytest for the Python sidecar |
| Rust check | npm run check:rust |
cargo check for the Tauri shell |
You only need the toolchains for the areas you touched. A docs-only or
frontend-only change does not require Rust or Python, though the full npm run
ci gate does.
End-to-end smoke tests¶
npm run test:e2e runs the Playwright smoke suite in e2e/ against the built
web app (it builds, serves it with vite preview, and drives a headless
Chromium). It is a render-path guardrail — it loads a GeoJSON layer, opens the
attribute table, toggles visibility, and runs an accessibility check — not
exhaustive coverage. Install the browser once with npx playwright install
chromium. The suite runs as a separate E2E smoke (Playwright) job in CI and
uploads its report as an artifact on failure.
Coding conventions¶
- Automated formatting runs on every commit via pre-commit hooks.
pre-commit.ci runs the same hooks on every PR
(including forks) and auto-commits a
style: auto-formatfix back to the PR branch, so anything the local hooks missed gets fixed automatically. It does not run on push tomain, so auto-formatted commits never bypass review. Tooling is split by language: - Python + Jupyter notebooks (
.py,.ipynb) — ruff formats and lints (ruff.toml, line length 100, rulesF/I/W/E). - JS/TS/JSON/CSS/YAML/TOML — oxfmt
(npm, NAPI bindings) formats (
.oxfmtrc.json, 2-space indent, double quotes, semicolons, width 100). Note that oxfmt also sortspackage.jsonkeys into its conventional order (e.g.scriptsbeforedependencies), so expect key reordering, not just whitespace changes, when editing those.ignorePatternsin.oxfmtrc.jsonkeeps oxfmt off paths that either belong to another tool or churn on every build: Jupyter notebooks and Python source (owned by ruff), lockfiles (package-lock.json,pnpm-lock.yaml,yarn.lock), generated/vendored bundles (dist/,build/,target/,node_modules/, minified files,.d.ts), Vite-plugin output (*.generated.js,*.generated.py,cesium/,jupyterlite/), and the machine-generated app assets underapps/geolibre-desktop/public/(Cesium assets, MapLibre sprite atlases, the Whitebox tool-catalog snapshot, which grows ~64% under oxfmt). The intentionally malformede2e/fixtures/malformed.geojsonfixture is also excluded. - ESLint enforces the React Hooks rules on TS/JS; a
npm run buildtypecheck runs too. - All text files are normalized to LF via
.gitattributes(* text=auto eol=lf), so line endings are consistent across platforms;core.autocrlfis overridden. - The remaining pre-commit hooks enforce LF line endings (
mixed-line-ending --fix=lf) and basic whitespace (end-of-file and trailing-whitespace fixers). You rarely need to format by hand — commit once, let the hooks rewrite, thengit addthe fixed files and commit again. Install the hooks after cloning withpre-commit install. - Do not edit files in
node_modules. If a third-party MapLibre control needs app-specific styling, add a scoped override inapps/geolibre-desktop/src/index.csslimited to that control's class. - Keep changes scoped to the package they belong to, and prefer reusing the
shared primitives in
packages/uiand helpers inpackages/core.
Documentation¶
The site is built with Zensical, the successor to
MkDocs Material from the same team. It reads the existing mkdocs.yml
configuration directly. To preview your changes locally:
python -m pip install -r requirements-docs.txt
zensical serve
Open http://localhost:8000. When you add a new page, add it to the nav in
mkdocs.yml. The site is built with zensical build --strict in CI, so broken
links and pages left out of the navigation fail the build. Link to other docs
pages with a relative path (for example architecture.md), and link to files
outside docs/ with a full GitHub URL.
Plugins and extensions¶
GeoLibre supports external plugins loaded from a zip, a local directory, or a hosted manifest URL. To build one, start from the GeoLibre plugin template and follow the Plugin API contract. You do not need to fork GeoLibre itself to ship a plugin.
Backend sidecar¶
The optional FastAPI sidecar
powers the server-side conversion tools. The conversion extra installs the
conversion runtime (DuckDB, rio-cogeo, and friends) and the dev extra installs
the test runner, so install both when working on it:
cd backend/geolibre_server
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[conversion,dev]"
geolibre-server
For a base, conversion-free run (pip install -e . plus a plain uvicorn
launch), see the sidecar README.
Run its tests with npm run test:backend from the repository root, or
python -m pytest from the backend directory.
License¶
GeoLibre is released under the MIT License. By contributing, you agree that your contributions are licensed under the same terms.