Skip to content
Merged
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ MeshMonitor supports multiple deployment methods:
- **Modern UI** - Catppuccin theme with message reactions and threading
- **Interactive Maps** - Unified node positions and network topology visualization across all sources
- **Terrain Link Profile** - Two-point terrain elevation, line-of-sight, and Fresnel-zone link-budget planning tool in Map Analysis, with per-source frequency/RX-sensitivity auto-detection and a configurable DEM source
- **3D Terrain View** - Pitched-terrain MapLibre GL view in Map Analysis with DEM/hillshade rendering, adjustable exaggeration, and clickable node markers, available when a tile-based elevation source is configured
- **Multi-Database Support** - SQLite (default), PostgreSQL, and MySQL via Drizzle ORM
- **Notifications** - Web Push and Apprise integration for 100+ services, with inactive-node and low-battery alerts
- **Automation** - Autoresponders, scheduled announcements, timers, and geofence triggers with rich message templates, plus an airtime-utilization cutoff that automatically pauses bot traffic when the mesh is busy
Expand Down
47 changes: 47 additions & 0 deletions docs/api/REST_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,53 @@ Probes a candidate DEM source URL and reports what it found. Requires `settings:

A failing probe still returns HTTP 200 — the probe outcome (`data.success: false` plus `data.error`) is the payload, not a request error.

### Get 3D Terrain Capabilities

#### GET /api/elevation/capabilities

Reports whether the [Map Analysis 3D terrain view](../features/map-analysis.md#3d-terrain-view) can be offered, without exposing the configured `elevationSourceUrl` (a secret setting). Public (no authentication), no outbound network calls — derived from settings already loaded server-side.

**Response:**
```json
{
"success": true,
"data": {
"enabled": true,
"terrainTiles": true,
"provider": "terrarium"
}
}
```

- `enabled` — mirrors the admin's **Enable terrain elevation** setting.
- `provider` — `"terrarium"` or `"json"`, auto-detected from the configured (or default) elevation source URL, same detection used by `POST /test`.
- `terrainTiles` — `true` only when `enabled` **and** `provider === "terrarium"`. A JSON point-API source can power the 2D Link Profile but has no tiles to build a 3D surface from, so `terrainTiles` is `false` in that case even though `enabled` is `true`.

### Get Terrain Tile

#### GET /api/elevation/tiles/{z}/{x}/{y}

Proxies a single Terrarium-encoded DEM tile from the configured (or default) elevation source, for MapLibre GL's `raster-dem` terrain source in the 3D view. Public (no authentication), rate-limited to **600 requests/minute per IP** in production (private/internal IPs exempt) — a single 3D view load legitimately fetches dozens of tiles.

Returns raw `image/png` bytes on success (**not** the `{success, data}` envelope) with:
```
Content-Type: image/png
Cache-Control: public, max-age=604800, immutable
```

**Example:**
```bash
curl http://localhost:8080/api/elevation/tiles/10/163/395 --output tile.png
```

**Errors** (JSON envelope, `Cache-Control: no-store`):
- `403 ELEVATION_DISABLED` — the admin has disabled elevation.
- `409 TERRAIN_TILES_UNAVAILABLE` — the configured elevation source is a JSON point API, which has no tiles to serve. There is no fallback to the public Terrarium source in this case.
- `400 INVALID_TILE_COORDS` — `z`, `x`, or `y` isn't a valid integer, or `x`/`y` falls outside `[0, 2^z − 1]` for the given zoom (zoom is capped at 15, the source's native maximum).
- `502 TILE_FETCH_FAILED` — the upstream tile fetch failed (network error, non-OK response, or the SSRF guard blocked the request).

The resolved source URL (and any embedded API key) is never included in a response or error message.

---

## Statistics
Expand Down
36 changes: 36 additions & 0 deletions docs/features/map-analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ The toolbar runs across the top of the canvas. From left to right:
| **Time slider toggle** | Show/hide the floating time-window slider. |
| **Measure** | Straight-line distance between two positioned nodes. Disabled until at least two positioned nodes exist; mutually exclusive with Link Profile. |
| **Link Profile** | Terrain, Fresnel clearance, and link-budget verdict between two points. See [Terrain Link Profile](#terrain-link-profile). Only shown when the server has elevation enabled. |
| **3D** (box icon) | Toggle between the flat 2D map and a pitched-terrain 3D view. See [3D terrain view](#3d-terrain-view). Disabled with a tooltip when elevation is off or the configured elevation source can't serve DEM tiles. |
| **Layer buttons (×8)** | Toggle each visualization layer on/off. The right-edge chevron opens a popover for layer-specific options (lookback window, sub-options). |
| **Progress bar** | Shows aggregate loading state while any layer is fetching. |
| **Inspector toggle** | Show/hide the right-side detail panel. |
Expand Down Expand Up @@ -244,6 +245,41 @@ For a node seen by several sources (say, a Meshtastic radio *and* an MQTT bridge

The terrain data (SRTM-derived, roughly 90 m per pixel) is a bare-earth elevation model — it does **not** account for buildings, trees, or other vegetation, so a "Clear" verdict is a first-pass estimate of geometric line-of-sight, not a guarantee of a working RF link. Node GPS altitude is not factored into antenna height; only the DEM terrain height plus your entered AGL value is used.

## 3D terrain view

::: tip New in 4.14
:::

The toolbar's **3D** button (box icon) switches the canvas from the flat Leaflet map to a pitched-terrain [MapLibre GL](https://maplibre.org/) view — the current basemap draped over a real elevation surface with hillshading, so you can tilt and rotate to see how terrain actually sits between nodes.

### Requirements

The button is disabled with an explanatory tooltip unless all of the following hold:

- **Elevation is enabled** on the server (**Settings → Elevation / Terrain**). If it isn't, the tooltip reads *"Elevation is disabled."*
- **The configured elevation source serves DEM tiles.** 3D terrain needs a Terrarium-encoded tile source (the default public AWS/Mapzen source, or a custom tile-template URL). If the admin has instead configured an Open-Topo-Data-style **JSON point API** — which the 2D [Terrain Link Profile](#terrain-link-profile) tool can still use — there's no tile source to build a 3D surface from, and the tooltip reads *"3D terrain is unavailable with the configured elevation source."* There is deliberately no fallback to the public terrarium tiles in this case: an admin who configured a JSON source did so on purpose (often for an air-gapped or cost-controlled deployment), and silently routing 3D traffic elsewhere would leak requests to a provider they explicitly opted away from.
- **Your browser supports WebGL.** If it doesn't, the 3D map degrades to a plain-language message and the view automatically switches back to 2D rather than showing a blank canvas.

### Using the 3D view

- **Navigate** with the built-in MapLibre control: drag to pan, scroll/pinch to zoom, right-drag (or two-finger drag) to pitch and rotate. A compass resets bearing to north.
- **Terrain exaggeration** — a slider (0–2×, default **1.3×**) vertically stretches the DEM so subtle elevation changes read more clearly. It's a per-session view setting, not persisted between visits.
- **Node markers** render with short-name labels at their real position, draped onto the terrain surface. Click a marker to select it — the same inspector panel used in 2D opens with that node's details.
- **Basemap** — the 3D view reuses whichever raster tileset you have selected for the 2D map. If your selected tileset is **vector-only**, 3D can't drape a vector style over terrain yet, so it substitutes the default OpenStreetMap raster basemap and shows a small note; your 2D tileset selection is unaffected.

The **2D/3D toggle state persists per-browser** alongside the rest of your Map Analysis toolbar configuration.

### What's not in 3D yet

The 3D view is a foundation, not full layer parity. Not yet available while in 3D mode (all still work normally after switching back to 2D):

- Neighbor links and traceroute paths
- Coverage heatmap, position trails, range rings, hop shading, and the SNR overlay
- The time slider
- Launching the Terrain Link Profile tool directly from the 3D canvas

These are planned for a follow-up phase of the 3D map work.

## Time slider

The slider appears bottom-center when enabled. It has two handles defining a `[start, end]` window inside the loaded lookback range. Movement is purely client-side — no refetch — and applies only to time-bounded layers (trails, heatmap, SNR overlay, traceroutes, neighbors). Markers, rings, and hop shading always reflect the current state.
Expand Down
4 changes: 4 additions & 0 deletions docs/features/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,10 @@ Description: Offline OpenStreetMap tiles via TileServer GL
- Implausible DEM samples (below −500 m or above 9000 m — an artifact of open-water/void pixels in some tile sets, not real terrain) are discarded server-side and shown as gaps in the Link Profile chart rather than distorting it.
- The `POST /api/elevation/profile` endpoint used by the tool is public (unauthenticated) but rate-limited to 20 requests/minute per IP in production (requests from private/internal IPs are exempt); the Test button's endpoint requires `settings:write`.

::: tip Also powers the 3D terrain view (New in 4.14)
This same elevation source drives Map Analysis's [3D terrain view](/features/map-analysis#3d-terrain-view). A **tile-template** URL (the default Terrarium source, or a custom one) works for both the 2D Link Profile chart and the 3D pitched-terrain map. A **JSON point API** source only supports the 2D Link Profile — there are no tiles to build a 3D surface from, so the 3D toggle stays disabled with an explanatory tooltip for that configuration (no fallback to the default tile source is attempted).
:::

## Display Preferences

### Default Landing Page {#default-landing-page}
Expand Down
Loading
Loading