HopReach

August 2, 2026 · View on GitHub

HopReach

See where your mesh actually reaches — over real terrain, not circles on a map.

Live demo — ScotMesh Repeater Coverage  ·  Technical reference  ·  Simulator model


HopReach

HopReach turns a MeshCore observation backend — CoreScope or MeshCore Beacon — into an interactive coverage map for your repeater network, then lets you plan changes to it and simulate how traffic would actually flow.

It reads every role=repeater node, keeps the ones inside your region, and computes a terrain-aware coverage estimate from real elevation data with line-of-sight and diffraction analysis on every path. Not a distance circle around each site — the actual hills in the way.

Everything runs from one Docker container that refreshes itself daily.

Bring your own observation backend

HopReach does not watch the mesh itself — it reads someone else's record of what was heard. Which one is a single config key:

source:
  type: corescope   # or: beacon

Both are first-class: same map, same coverage rasters, same planner and simulator, same packet replay. Everything the app needs goes through one internal interface, so the browser never sees a vendor's API and adding a third backend means implementing that interface — not touching the front end.

One difference is worth knowing. Beacon scopes its region list to the observers in your configured IATAs, so it answers "regions somebody local was heard on" rather than "every region on this mesh". Region-wide features need the complete set to be truthful — a region missing from a filter looks like a region with no repeaters in it — so with a partial list they are switched off rather than drawn wrong.

If you know your regions, just say so and they come back on:

source:
  type: beacon
  scopes: ["#sco", "#fif", "#tay"]

That is enumeration only. Which repeater carries which region is still decoded from real traffic either way, so a region you list that nobody has been heard on gets no observations rather than an invented one.

The backend declares what it can answer (Capabilities.ScopeCatalog), so the pipeline, the API and the front end all switch together. See Beacon compatibility for the feature-by-feature matrix, verified by loading one real mesh into both backends and comparing the output.

Quick start

git clone https://github.com/A13xB0/hopreach.git
cd hopreach
cp config.example.yaml config.yaml
docker compose up --build

Open http://localhost:8080. No GPU required, no API keys, no accounts.

HopReach map view, showing estimated coverage over central Scotland

⚠️ Vibe-coded software. Built with heavy AI assistance rather than fully by hand. The core physics is cross-checked between the server and the WebAssembly build the browser shares with it, it's been exercised against real data, and human review has been endeavoured throughout — but it hasn't had independent code review from someone who wasn't also steering the AI. Read the source before relying on it for anything safety-critical or professional.


What you can do with it

See real coverage

A nightly terrain-aware raster over your whole region, rendered as a heatmap you can fade in and out. Four versions are computed — reported vs. calibrated positions, each at standard and high detail — and a dropdown switches between them live. Repeaters are colour-coded active / degraded / silent, and each one's popup lists the neighbours it's actually been heard by.

Filter the whole map down to a single region tag (#edi, #fif, …) — including a coverage overlay computed for just that region's repeaters, so you can see what one community's own infrastructure covers on its own.

Planning and what-if tools

Sketch changes to the network entirely in your browser — nothing is sent anywhere, and it uses the same physics as the real map.

Add repeater mode: a planned site's predicted coverage overlaid in blue→purple over the real map's orange→green

  • Add a repeater — click to drop a site and watch its predicted coverage appear in blue→purple, deliberately distinct from the real map's orange→green so proposed and existing never blur together. Drag it around and the prediction follows.
  • Check line of sight — click a chain of points and get each hop drawn by margin: green clear, orange marginal, red blocked, with distances and dB in the panel.
  • 🔗 Connect two repeaters — it works out the fewest new sites needed to bridge them, reusing existing infrastructure for free, and offers up to three route options to choose between.
  • ▱ Cover an area — draw a polygon and it places up to N new repeaters for maximum coverage of what's inside, reporting the before/after percentage.
  • ✎ Adjust a real repeater — reposition or re-height any existing site for yourself to test a "what if we moved it" idea. The official marker never changes; your version renders as a linked amber marker.
  • 📍 Companion pin — drop a pin anywhere and see who'd hear a handheld at that spot, with its own adjustable height.

Connect repeaters: a route bridging two real repeaters with 5 new relays, with alternative options listed

Plans live in your browser, export to .json or .kml for Google Earth, and Share produces a link anyone can open — carrying the plan's structure, never a stale rendered image, so it stays live and interactive for whoever you send it to.

LoRa flood simulator

Test and tune MeshCore's flood-relay timing before touching a real device.

The LoRa flood simulator with 73 real repeaters loaded and 364 terrain-derived links built

Built from a faithful port of MeshCore's own airtime, packet-score, retransmit-delay and duty-cycle formulas — verified line-for-line against the firmware source, not a secondhand approximation.

  • Load your network — planned repeaters, the real ones, or both, plus virtual companion devices anywhere you click.
  • Choose how links are decided — the terrain model, the backend's real observed reach data, or a blend of the two.
  • Schedule sends and watch the flood — an animated replay steps through it wave by wave, with a scrub bar to drag back and forth through time.
  • See exactly why a packet didn't arrive — not one vague "collided", but the real cause: nothing ever locked, lock lost to a stronger interferer, or the listener's own transmitter was keyed (LoRa is half-duplex).
  • 🏆 Per-repeater scoreboard — duty cycle, real delivery, and the one that matters most: unique deliveries vs. redundant relays. Is this repeater's airtime reaching anyone new?
  • 🧬 Search better settings — grid-search and multi-rule policy search ranked by actual delivery ratio, ending in a per-repeater action list with copy-pasteable MeshCore CLI lines.
  • 🔥 Stress test — push synthetic load until it breaks and report the knee: how many messages this specific network can actually handle.

Replay a real packet. Paste a packet hash and it reconstructs what genuinely happened — every relay there's proof of — then runs its own simulation from the same origin and compares. Hops the model predicted but nobody observed show as dashed amber (candidates for where interference actually hit); hops that really happened but the model doesn't even think possible show in blue. That difference is the interesting part.

Works properly on a phone

Not a shrunken desktop layout. Below 700px the whole thing switches to a phone design: a bottom tab bar, and Plan/Simulate/Map as drag-resizable bottom sheets you can minimise to a title strip to watch a simulation run on the live map behind them.

HopReach on a phone: full-bleed map with a bottom tab bar The Map options sheet, holding the basemap picker, filters and legend The simulator as a bottom sheet with the map still visible above it


Not just Scotland

Scotland is the built-in default, but nothing is hard-wired to it. Point region.boundary_url or region.boundary_path at any GeoJSON — a country, a county, a custom shape you drew — and that becomes the area of interest. See Region.

Want it faster?

Coverage computation is the expensive part. With a compatible GPU it's roughly 50× faster for the same raster — one extra compose file, no code changes. There's also a remote-worker mode, so a headless box with a GPU can do the maths for a small VPS that hasn't got one. See GPU-accelerated compute.

Going further

Technical referenceHow the coverage estimate works, position calibration, the detail tiers, GPU and remote-worker setup, the shared WASM core, full configuration reference, local development, project layout
Simulator modelThe event model, airtime and frame sizing, capture/collision rules, timing, region scoping, and where it deliberately diverges from real firmware
config.example.yamlEvery setting, documented inline

License

AGPL-3.0 plus the Commons Clause — see LICENSE for the full text. In short: use, copy, and modify freely; if you distribute it or run a modified version as a network service others can talk to, you must make the corresponding source available under the same license; you may not sell this software or a service substantially based on it. Provided free of charge, for personal and non-commercial use, with no warranty and no support.