UrbanViable’s frontend is a single-page application built with React 18 and Vite 6. The map is rendered by MapLibre GL JS 4, which uses WebGL to evaluate scoring expressions directly on the GPU. When a user moves a slider, the new weighted score is computed across every census section simultaneously on the GPU — no fetch, no server round-trip, no re-render of the React tree beyond updating the paint property on the map layer.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/danizd/urbanviable/llms.txt
Use this file to discover all available pages before exploring further.
Technology Stack
| Package | Version | Role |
|---|---|---|
react + react-dom | 18.3.x | UI framework and DOM rendering |
react-router-dom | 6.28.x | Client-side SPA routing |
maplibre-gl | 4.7.x | WebGL map engine — GPU paint expressions |
axios | 1.7.x | HTTP client (used only for the /api/status call) |
vite | 6.0.x | Dev server and production bundler |
Pages
The router (App.jsx) defines three routes. Any unmatched path redirects to /.
| Page component | Route | Purpose |
|---|---|---|
<HomePage /> | / | Landing page with CTA button linking to /scouting |
<ScoutingPage /> | /scouting | Main scouting tool — header + sidebar + full-screen map |
<HowToUsePage /> | /como-usar | Static how-to page with centred text content |
ScoutingPage Layout
Components
| Component | File | Responsibility |
|---|---|---|
MapViewer | components/MapViewer.jsx | Initialises MapLibre map, adds source and layers, fires click/hover events |
ToolPanel | components/ToolPanel.jsx | 320 px sidebar — wraps all ScoreSlider instances and the Tooltip |
ScoreSlider | components/ScoreSlider.jsx | Single <input type="range"> with label, percentage readout, and description |
DataStatus | components/DataStatus.jsx | Header badge showing dataset freshness — ✅ or ⚠️ |
Tooltip | components/Tooltip.jsx | Census-section detail panel rendered inside the sidebar on feature click |
useMapStyle Hook
hooks/useMapStyle.js — watches the weights object and calls map.setPaintProperty with a freshly built MapLibre GL JS interpolate expression every time any weight changes, translating the React state into a GPU-side color ramp with zero latency.
Key Constants
constants/variables.js exports two objects that drive every part of the scoring UI:
VARIABLES— array of 7 descriptor objects (one per indicator). Each entry carries the normalised property key used in paint expressions (key), the human-readablelabel, a shortdescriptionshown beneath the slider, and the absolute-value metadata (absKey,absLabel,absFormat) used byTooltip.DEFAULT_WEIGHTS— plain object mapping eachkeyto its initial slider position (0–1). Loaded into React state on mount; mutated byonWeightChangeas the user drags sliders.
Development Server
In development the frontend loads
galicia_scouting.geojson directly from the
public/ directory via a fetch() call — no TileServer GL instance is required.
Set VITE_REACT_APP_TILE_URL to an empty string (the default) and place the file
at frontend/public/galicia_scouting.geojson.Next Steps
Scoring Engine
How
useMapStyle builds MapLibre GL JS paint expressions and computes the weighted score on the GPU.Component Reference
Prop tables and behaviour details for all five React components.
Configuration
Environment variables, build command, and Nginx deployment.
Deployment
Docker Compose setup for TileServer GL and Nginx in production.