vccs
Composable charting components for Vue 3, ported from Recharts
Real-time station status map for the Montana Mesonet network — see which HydroMet and AgriMet stations are reporting, and how recently.
DataJavaScript · HTMLGitHub @mt-climate-officeOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
A real-time station status map for the Montana Mesonet, built and operated by the Montana Climate Office.
Shows the current reporting state of every station across the HydroMet and AgriMet sub-networks. Two view modes:Read the full README ↗A real-time station status map for the Montana Mesonet, built and operated by the Montana Climate Office.
Shows the current reporting state of every station across the HydroMet and AgriMet sub-networks. Two view modes:
In Health mode the legend footer reports sensor-list loading progress and, afterwards, how many fresh stations have no sensor list (those count as operational).
Color is Crameri's roma from the house palette (MCO.palette, mco-web-style 0.12.0), sampled at 0.1–0.9 and reversed: blue = fresh → pale → brown = stale. It is perceptually uniform, ordered, and safe for the major color-vision deficiencies, and the two ends differ in lightness, so they survive grayscale.
Other features:
↑ ↓ Enter), and a / global shortcut to jump to it from anywhere on the page.prefers-reduced-motion and prefers-color-scheme.Every piece of UI state is mirrored to the URL via history.replaceState. The view is fully shareable and bookmarkable.
| Param | Values | Notes |
|---|---|---|
lng | float | Map center longitude. Omitted at the default Montana fit. |
lat | float | Map center latitude. Omitted at the default Montana fit. |
zoom | float | Map zoom. Omitted at the default Montana fit. |
mode | status | timesince | health | Visualization mode |
net | +/space/comma list (hydromet+agrimet) | Active sub-networks. Empty = none. Case-insensitive. |
scat | list (fresh+stale, null) | Visible Status-mode categories. Omitted = all. |
tcat | list (0+1+2+3+4, null) | Visible Time-since bins (0 = <2 h, 4 = >24 h). Omitted = all. |
hcat | list (operational+partial+outage) | Visible Health classes. Omitted = all. |
labels | on | off | Station-ID labels |
legend | open | collapsed | Legend panel state |
theme | light | dark | high-contrast | Theme override. Omitted when it matches the OS preference. |
station | station id (e.g. aceabsar) | Open this station's popup on load; deep-link |
Precedence per setting: URL param > localStorage > built-in default.
All enum-string values (mode, theme, labels, legend, network names, category keys, station IDs) are matched case-insensitively. List params accept +, spaces, or commas as separators.
Examples:
/?station=aceabsar
/?station=aceabsar&lng=-109.61&lat=45.56&zoom=12
/?mode=timesince&net=agrimet&theme=light&labels=on&legend=collapsed
/?net=hydromet+agrimet&scat=fresh+stale
station column). If the API doesn't serve all yet, it ignores the flag and returns the bare catalog, which the app detects by the missing station column and falls back to the per-station form https://mesonet2.climate.umt.edu/api/elements/<station>/?type=json (e.g. https://mesonet2.climate.umt.edu/api/elements/acemidwa/?type=json). Without type=json the endpoints return HTML; per-station rows are duplicated and are de-duplicated by element.Health cross-references the two: an expected element whose description_short column ("<description_short> [<unit>]") is null in the station's latest record counts as a sensor not reporting. The element lists are fetched once (one bulk request, or 8 concurrent per-station requests on the fallback path, ~10 s cold for the full network) and cached in localStorage under mco-status-elements-v1 with a 24 h per-station TTL, so a reload paints Health from cache immediately. Clear that key (or the site's storage) to force a refetch. Stations whose list fails to load are counted as operational when fresh and called out in the panel footer.
All API reads go to mesonet2.climate.umt.edu (the page CSP's connect-src pins that host). The per-station dashboard link stays on mesonet.climate.umt.edu/dash/.
The latest endpoint is polled every 5 minutes. Each response is merged into our in-memory store rather than replacing it — the Mesonet API occasionally drops a (different) station per call, and merging keeps a station's last-known timestamp from flickering to "no record" between polls. If a station genuinely stops reporting, its timestamp just ages naturally into the very-stale bin. Dot colors are also refreshed every 30 seconds against the local clock so freshness stays current between API calls.
Static overlay GeoJSON files in data/ (state, reservations, counties) are built by data.R from tigris + rmapshaper and checked into the repo so the app has zero runtime dependencies beyond the Mesonet API.
The app is a single static index.html with no build step. Serve it locally with any static server:
# Python
python -m http.server 8000
# Node
npx serve .
Open http://localhost:8000.
Published via GitHub Pages from the main branch. To enable for a fresh fork:
main.https://<owner>.github.io/mesonet-status/ within a minute or two. Add a CNAME file later if you want a custom subdomain..github/workflows/preview.yml runs nightly (and on manual dispatch) and commits assets/og-card.png back to main — always pull/rebase before pushing, or you race it.
scripts/generate_preview.py screenshots the live Pages site at 2400×1260 (a 1200×630 viewport at 2×) with ?mode=status, which pins the Status view and, as a deep link, keeps the first-visit help dialog closed. It waits for the #refresh-stamp text to read refreshed … and then 4 seconds for tiles to paint — that param, element id and stamp text are a contract with the script. Run it locally to check:
pip install playwright
playwright install --with-deps chromium
python scripts/generate_preview.py
MCO.map.loadMapLibre(); SRI in the import map).MIT — Copyright (c) 2026–present Montana Climate Office