# Nuvolari Precipitation radar for Piedmont, Italy. Android first, iOS later, one Flutter codebase. Radar imagery comes from the public **Radar-DPC** platform and weather alerts from the **ARPA Piemonte** XML-CAP bulletin, drawn over an OpenStreetMap base map. The app is free, with no advertising and no accounts. **Scope**: radar, official alerts, rain notifications. No forecasts, no lightning, no home-screen widget. See [CLAUDE.md](CLAUDE.md). Nuvolari is an independent app. It is not affiliated with, endorsed by, or operated by ARPA Piemonte or the Dipartimento della Protezione Civile. For civil-protection purposes the official channels always prevail. ## Layout ``` app/ Flutter application (Dart package "nuvolari") backend/ Python worker: fetches DPC rasters, crops, reprojects, renders PNG frames docs/ architecture, data sources, licenses, stack decisions, roadmap, privacy tool/ verification scripts ``` Start with [docs/architecture.md](docs/architecture.md), then [docs/roadmap.md](docs/roadmap.md) for what is built and what is next. ## Toolchain | Tool | Version | |---|---| | Flutter | 3.47.3 stable (Dart 3.13.3) | | Android SDK | platform 36, build-tools 36.0.0, platform-tools | | JDK | 21 | | Python | 3.12+ (3.14 works; rasterio ships wheels for it) | | Android NDK | 28.2.13676358 — pinned by `maplibre_gl`, not by this project | A full toolchain plus a warm Gradle cache needs roughly **14 GB** of disk: Flutter 3 GB, Android SDK 2.5 GB (2 GB of which is the NDK the map plugin pins), the Gradle cache 5 GB, and build output around 2 GB. `flutter clean` reclaims the last of those. ## Configuration Secrets never enter the repository. Copy the template and fill it in: ```bash cp env.example.json env.json # env.json is git-ignored ``` | Key | Purpose | |---|---| | `MAP_STYLE_URL` | MapLibre style URL. Empty uses the free OpenFreeMap style; `offline` forces the bundled no-network style. | | `RADAR_MANIFEST_URL` | Base URL of the published `manifest.json`. | | `RADAR_SOURCE` | `mock` (offline demo), `dpc` (live), `arpa` (disabled stub). | | `REGION_ID` | Which region config to load. Defaults to `piemonte`. | ## Running ```bash cd app flutter run --dart-define-from-file=../env.json ``` With no `env.json` the app starts in demo mode: mock radar frames from assets on the free OpenFreeMap base map. **No credentials are needed for anything** — OpenFreeMap has no API key and no signup. The radar frames work with no network at all. The base map needs one; run with `--dart-define=MAP_STYLE_URL=offline` to drop it too and work entirely offline. ## Debugging in VS Code Open the **`Nuvolari` folder** as the workspace root — the configurations in `.vscode/` are relative to it. Then pick one in Run and Debug and press **F5**: | Configuration | Use it for | |---|---| | **Nuvolari — debug (emulatore)** | Everyday work. Demo mode, no `env.json` needed, hot reload on save. | | **Nuvolari — profile** | Judging animation smoothness. Debug builds run the Dart VM unoptimised, so the radar timeline always looks worse than it is — never assess it in debug. | | **Nuvolari — debug con env.json** | Pointing the app at a live radar manifest or a different base map style. | | **Nuvolari — debug su Windows** | Fast UI iteration with no emulator. The native map does not render here. | | **Test — tutti** / **Test — file corrente** | Debugging tests with breakpoints. | Every emulator configuration runs `tool/start_emulator.ps1` first, so F5 works from a cold machine. The script exits immediately when a device is already attached, so pressing F5 twice does not start two emulators. `Ctrl+Shift+B` runs the full verification. Other tasks live under **Terminal → Run Task**: quick verification, regenerating the demo radar frames, and shutting the emulator down. ## Verifying ```powershell .\tool\verify.ps1 # format, analyze, test, build, lint, pytest .\tool\verify.ps1 -SkipBuild # fast inner loop ``` Stages whose target does not exist yet are skipped, so this runs from day one. ## Attribution Radar-DPC (CC BY-SA) · Arpa Piemonte · © OpenStreetMap contributors (ODbL) · © OpenMapTiles · OpenFreeMap. The credits are on the **Sources screen**, reached from the settings button over the map. There is no permanent credit line on the map itself: the OSMF attribution guidelines allow the licence information to sit behind an "About option in a menu" so long as it stays findable, and a test asserts that route still exists. See [docs/licenses.md](docs/licenses.md) for the obligations these carry — in particular, the rendered radar frames are a derived product of CC BY-SA data and inherit share-alike, and the OpenFreeMap style ships no `attribution` field, so the app has to render the map credits itself.