# How 1000+ Whitebox Geoprocessing Tools Run in the Browser Using WebAssembly

> Discover how 1000+ Whitebox geoprocessing tools run client-side in the browser with WebAssembly. Explore lazy loading, WASI runtime, and efficient data processing for GeoJSON, COGs, and Shapefiles.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: how-to-guide
- Published: 2026-08-22

---

**GeoLibre executes Whitebox geoprocessing tools entirely client-side by lazy-loading a ~5 MB gzipped WebAssembly module into a WASI runtime, mounting an in-memory filesystem for data exchange, and processing outputs through specialized converters for GeoJSON, Cloud-Optimized GeoTIFFs, and zipped Shapefile bundles.**

The GeoLibre project brings the full WhiteboxTools geoprocessing engine—over 1000 algorithms for raster, vector, and LiDAR analysis—directly into the browser through a WebAssembly (WASM) implementation. Unlike traditional geoprocessing architectures that require a Python sidecar or remote server, the `@geolibre/processing` package enables complete client-side execution by porting the Rust-based WhiteboxTools core to WASM and wrapping it in a WebAssembly System Interface (WASI) runtime.

## The WebAssembly Execution Pipeline

The browser-side geoprocessing workflow mirrors the Python sidecar API but replaces remote HTTP calls with in-process WASI execution, maintaining identical request/response shapes through `RunWhiteboxToolRequest` and `WhiteboxJob` objects.

### Lazy-Loading the WASI Runtime

To optimize initial page load performance, the heavy computational module is not bundled with the main application. Instead, [`packages/processing/src/wasm-client.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/wasm-client.ts) exposes the `loadToolsModule()` function that dynamically imports the `geolibre-wasm/tools` module only when the user initiates local execution.

```typescript
// packages/processing/src/wasm-client.ts
function loadToolsModule(): Promise<ToolsModule> { … }

```

This module weighs approximately **5 MB gzipped** and contains the compiled WhiteboxTools algorithms. The lazy-loading strategy ensures that users only download the WASM binary when they explicitly select the *Run locally (WASM)* option.

### Preparing the In-Memory Filesystem

Before tool execution, the system constructs a temporary virtual filesystem at `/work` within the WASI environment. The `runWhiteboxToolWasm` function (specifically lines 90–130) maps toolbox parameters to filesystem entries using the `paramKind` helper, which distinguishes between vector, raster, and file input/output roles.

Input data preparation follows these rules:

- **Vector data** is JSON-encoded and written to `*.geojson` files.
- **Raster and LiDAR files** are written as raw bytes to `*.tif`, `*.las`, or generic `*.dat` files.
- **Remote inputs** specified via URL are fetched using `fetchBytes` before being mounted.

### Building Command-Line Arguments

Each tool parameter translates to a command-line flag. File parameters become `--name=/work/file` paths, while scalar and boolean parameters are passed as `--name=value` arguments. This convention maintains compatibility with the original WhiteboxTools CLI interface while operating inside the browser sandbox.

### Executing the Tool

The actual execution occurs through the WASI runtime's `runTool` function:

```typescript
const { exitCode, stdout, files } = await runTool(request.tool_id, { args, input });

```

This call blocks until the Rust-implemented algorithm completes, returning the exit code, log output, and a map of output files written to `/work`.

## Handling Input and Output Data Formats

Post-processing logic in `runWhiteboxToolWasm` (lines 60–90, 120–135, and 160–180) converts the raw filesystem outputs into browser-friendly formats suitable for rendering or download.

### Vector Output Processing

For vector geoprocessing results, the system supports multiple output formats:

- **GeoJSON** (default): Parsed directly into a standard `FeatureCollection` object for immediate rendering.
- **Geoparquet, FlatGeobuf, and Shapefile**: Returned as raw `Uint8Array` bytes for download.

When exporting to **Shapefile**, the helper `zipShapefileSidecars` bundles the required component files (`.shp`, `.shx`, `.dbf`, plus optional `.prj` and `.cpg`) into a single zip archive, warning users if core members are missing.

### Raster Output Conversion

Raster outputs are always produced as GeoTIFFs. The helper `ensureWhiteboxRasterCog` in [`packages/processing/src/cog-convert.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/cog-convert.ts) re-encodes these as **Cloud-Optimized GeoTIFFs (COG)** via `convertGeoTiffToCog`, ensuring efficient visualization and partial reads over HTTP when the result is served from a remote source.

## Tool Discovery and Catalog Management

The WASM binary ships with a complete manifest of available tools. The function `listWhiteboxWasmTools` (lines 28–32 in [`wasm-client.ts`](https://github.com/opengeos/GeoLibre/blob/main/wasm-client.ts)) enumerates all tool IDs embedded in the binary:

```typescript
import { listWhiteboxWasmTools } from "@geolibre/processing";

const ids = await listWhiteboxWasmTools(); // e.g. ["fill_depressions", "slope", …]
console.log("WASM tools:", ids);

```

The UI constructs its toolbox catalog by merging this WASM-only manifest with the Python sidecar catalog using `mergeWasmToolManifests`, ensuring users see a unified interface regardless of the execution backend. Tool registration logic resides in [`packages/processing/src/registry.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/registry.ts), while [`packages/processing/src/wasm-convert.worker.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/wasm-convert.worker.ts) provides a Web Worker wrapper to offload WASM execution from the main thread.

## Practical Implementation Example

The following TypeScript example demonstrates running the **Fill Depressions** tool entirely in the browser:

```typescript
import { runWhiteboxToolWasm } from "@geolibre/processing";

/* Example: fill depressions */
const request = {
  tool_id: "fill_depressions",
  vector_output_format: "geojson",
  parameters: { z_factor: "2" },
  layer_inputs: {
    dem: {
      name: "dem",
      kind: "raster_in",
      bytes: await fetchBytes("https://example.com/dem.tif"),
    },
  },
  tool: {
    id: "fill_depressions",
    params: [
      { name: "dem", io_role: "raster_in", required: true },
      { name: "output", io_role: "raster_out", required: false },
    ],
  },
};

const job = await runWhiteboxToolWasm(request);
if (job.status === "succeeded") {
  // `job.outputs` contains the raster COG (Uint8Array) under the key “output”
  const cog = job.outputs["output"] as Uint8Array;
  // render or download...
}

```

To download a Shapefile result as a zipped bundle:

```typescript
if (job.outputs["output"] instanceof Uint8Array) {
  const zipBytes = job.outputs["output"]; // already zipped shapefile bundle
  const blob = new Blob([zipBytes], { type: "application/zip" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = "output.zip";
  a.click();
}

```

## Summary

- **GeoLibre's `@geolibre/processing` package** executes 1000+ WhiteboxTools algorithms client-side by compiling the Rust codebase to WebAssembly and running it in a WASI environment.
- **Lazy loading** in [`wasm-client.ts`](https://github.com/opengeos/GeoLibre/blob/main/wasm-client.ts) defers the ~5 MB WASM module download until the user explicitly requests local execution, preserving initial load performance.
- **Virtual filesystem management** at `/work` handles data exchange between JavaScript and the WASM runtime, supporting GeoJSON, raw raster bytes, and LiDAR formats.
- **Post-processing helpers** like `ensureWhiteboxRasterCog` and `zipShapefileSidecars` convert raw tool outputs into standards-compliant Cloud-Optimized GeoTIFFs and bundled Shapefiles.
- **Tool discovery** via `listWhiteboxWasmTools` enables dynamic UI generation, while [`wasm-convert.worker.ts`](https://github.com/opengeos/GeoLibre/blob/main/wasm-convert.worker.ts) offloads computation to a background thread for responsive user experiences.

## Frequently Asked Questions

### How does GeoLibre handle large raster files in the browser?

GeoLibre processes raster data as raw byte arrays within the WASM heap, converting outputs to Cloud-Optimized GeoTIFFs (COG) using `convertGeoTiffToCog` in [`packages/processing/src/cog-convert.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/cog-convert.ts). The COG format enables efficient partial reads and streaming visualization without loading the entire dataset into memory, making it feasible to handle large rasters client-side.

### What vector output formats are supported when running tools in WebAssembly?

The WASM runner supports **GeoJSON** (parsed immediately into FeatureCollections), **Geoparquet**, **FlatGeobuf**, and **Shapefile** exports. For Shapefile outputs, the `zipShapefileSidecars` helper automatically bundles all required sidecar files (`.shp`, `.shx`, `.dbf`, `.prj`, `.cpg`) into a single zip archive for download, according to the logic in `runWhiteboxToolWasm`.

### Is the WebAssembly module loaded immediately when the GeoLibre page loads?

No. The module implementing [`packages/processing/src/wasm-client.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/wasm-client.ts) uses dynamic imports via `loadToolsModule()` to fetch the ~5 MB gzipped `geolibre-wasm/tools` binary only when the user clicks *Run locally (WASM)*. This lazy-loading strategy prevents bloating the initial JavaScript bundle and preserves application startup time.

### How does the browser-based WASM implementation compare to the Python sidecar?

Both implementations share identical API contracts using `RunWhiteboxToolRequest` and `WhiteboxJob` types defined in [`packages/processing/src/sidecar-client.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/sidecar-client.ts). The WASM version replaces HTTP calls to a Python backend with in-process WASI execution via `runTool`, eliminating server dependencies and network latency while maintaining the same parameter schemas and output formats.