The Problem

Clients that need to explore USGS 3DEP LiDAR point clouds often resort to downloading massive COPC files and writing custom viewers. The manual workflow is slow, error‑prone, and forces each team to re‑implement map interaction, search, and streaming logic.

What This Does

maplibre-gl-usgs-lidar delivers a ready‑made MapLibre GL plugin that searches the USGS STAC catalog, draws item footprints, and streams COPC point clouds directly on the map. The core implementation lives in src/lib/core/UsgsLidarControl.ts (≈830 LOC) and its React wrapper src/lib/core/UsgsLidarControlReact.tsx. UI construction is in src/lib/gui/PanelBuilder.ts. Example entry points are examples/basic/main.ts (vanilla) and examples/react/main.tsx (React). All TypeScript source is compiled via Vite (vite.config.ts) and can be containerised with the provided Dockerfile.

How It Is Wired

Execution starts at the HTML entry points (examples/basic/index.html or examples/react/index.html). The scripts import the control:

  • Vanilla – examples/basic/main.ts imports src/index.ts, which re‑exports UsgsLidarControl.
  • React – examples/react/main.tsx renders <UsgsLidarControlReact> imported from src/lib/core/UsgsLidarControlReact.tsx.

Both paths instantiate UsgsLidarControl. Its constructor registers event listeners (_setupEventListeners) and creates UI components via PanelBuilder. The most‑used internal functions are:

  • setState – called from 22 places, propagates UI and map updates.
  • _emit – invoked 8 times, dispatches custom events (searchcomplete, loadcomplete).
  • getState – read from 8 locations, provides the current control state.

The control’s search flow (searchByBbox) calls StacSearcher.search, then setState and _emitWithData. Footprint rendering is handled by FootprintLayer (src/lib/results/FootprintLayer.ts). The plugin’s hub modules are:

ModuleCa (importers)Ce (imports)Instability
src/index260.75
src/lib/core/UsgsLidarControl350.63
src/lib/core/types800
src/lib/gui/PanelBuilder220.5

No circular dependencies were detected. The largest blast radius belongs to setState and _emit, because any change there ripples through >20 functions across the UI and map layers.

How To Use It

# Clone the repo
git clone https://github.com/moses-y/maplibre-gl-usgs-lidar
cd maplibre-gl-usgs-lidar

# Install dependencies (npm is the declared manager)
npm ci

# Run the vanilla example locally
npm run dev   # Vite dev server serves examples/basic

# Or build and run the Docker image
docker build -t maplibre-gl-usgs-lidar .
docker run -p 8080:80 maplibre-gl-usgs-lidar

The Dockerfile serves the built assets with an Nginx front‑end. No environment variables are required; the plugin contacts the public USGS STAC endpoint directly.

Real‑World Use

A municipal GIS team can embed the React component in an existing dashboard, passing the MapLibre map instance. The control lets analysts draw a bounding box, automatically fetches matching LiDAR tiles, and streams them into the map without pre‑loading gigabytes of data, keeping the web app responsive.

Code Health & Issues

  • HIGH – Pin third‑party GitHub Actions to commit SHAs (.github/workflows/*).
  • MEDIUM – Declare least‑privilege permissions for GITHUB_TOKEN (publish.yml).
  • MEDIUM – Add Dependabot or Renovate (.github/dependabot.yml).
  • MEDIUM – Pin Docker base images by digest (Dockerfile).
  • MEDIUM – Add a dependency‑vulnerability scan step in CI.
  • MEDIUM – Set persist-credentials: false on checkout (deploy-pages.yml).
  • MEDIUM – Run container as non‑root (Dockerfile).
  • LOW – Define timeout-minutes for workflow jobs (deploy-pages.yml).

Static analysis also reported duplicated 6‑line blocks across seven files and two oversized modules (UsgsLidarControl.ts, PanelBuilder.ts), suggesting a refactor to extract shared helpers and split responsibilities.

The Bottom Line

The repository offers a functional, TypeScript‑based viewer that eliminates the need to build a LiDAR search UI from scratch. It is well‑structured but suffers from duplicated code, large monolithic files, and several CI‑related hardening gaps. Teams comfortable with MapLibre and React will find it immediately useful; a modest cleanup and security tightening will make it production‑ready.