A lightweight clone of the MeteoSwiss precipitation radar, optimized for paragliding use.
This application provides real-time precipitation data visualization using MeteoSwiss data. It's built with Express.js (backend) and MapLibre GL (frontend), using TypeScript throughout. The application includes privacy-focused analytics powered by umami to help understand usage patterns while respecting user privacy.
- Real-time precipitation radar display
- Paragliding-optimized mode
- MapLibre GL map integration
- Swiss boundaries and cities overlay
- Mobile-friendly interface
client/- Frontend TypeScript source codegeojson/- GeoJSON data processing utilitiesmap/- MapLibre GL setup and layer managementprecipitation/- Precipitation data handling and visualization
public/- Static assets and compiled JavaScriptserver/- Backend utilities and configurationserver.ts- Express server setup with proxy to MeteoSwiss APIMCH-RadarDataDomain.md- Technical documentation of radar domain calculations and coordinate systems
-
Backend: Express.js with TypeScript
express-http-proxyfor MeteoSwiss API proxyingumamitrack server requests and serverside proxy events
-
Frontend: Pure TypeScript with MapLibre GL
maplibre-glfor map renderingumamibasic analytics- No other frontend framework dependencies
-
Build Tools:
esbuildfor fast TypeScript bundlingnoderuns the.tsfiles directly — Node strips types natively, so there is no ts-node in the chainconcurrentlyfor parallel dev processestsc(TypeScript 7, the native Go compiler) for type checking only
Node only strips types, it never checks them, and it rejects syntax that needs a real transform (enums, namespaces, parameter properties).
tsconfig.jsonsetserasableSyntaxOnlyandverbatimModuleSyntaxsonpm run typecheckcatches both cases rather than leaving them to fail at runtime.TypeScript 7 has no programmatic API yet, so
typescript-eslintstill needs the 6.0 API.package.jsoninstalls both through npm aliases: thetscbinary is 7.0 via@typescript/native, whilerequire("typescript")resolves to@typescript/typescript6. -
Runtime: Node 22.18+ or 24 (
.nvmrcpins the current LTS). 22.18 is the release that unflagged type stripping.
The project uses esbuild for an efficient and fast build pipeline with different configurations for development and production:
-
Development Mode (
npm run dev):- Watches and rebuilds all TypeScript files in
client/ - Generates sourcemaps for debugging
- Outputs individual bundles to
public/js/maintaining directory structure - Runs development server with reload via
node --watch
- Watches and rebuilds all TypeScript files in
-
Production Mode (
npm run build:prod):- Single entry point from
client/map/init-map.ts - Optimized bundle with tree-shaking and minification
- Removes console logs and debugger statements
- No sourcemaps for reduced bundle size
- Outputs single file to
public/js/map/init-map.js
- Single entry point from
Common build features:
- ES modules format (ESM)
- ES2022 target — the baseline MapLibre GL 6 ships and requires
- TypeScript compilation via esbuild loader
- Copies MapLibre's stylesheet and worker from
node_modulesintopublic/vendor/(generated, and gitignored). The worker has to ship as a real file because MapLibre 6 loads it by URL rather than as a blob.
Build commands:
# Runs both development server and client watcher in parallel using concurrently
npm run dev
# Creates optimized production bundle with minification and tree-shaking
npm run build:prod
# Starts Express server using node --watch with auto-reload
npm run server
# Watches client files and rebuilds on changes using esbuild
npm run watch
# Type-checks the server and client projects (no emit)
npm run typecheckNote that the build never type-checks: esbuild strips types without
looking at them. Run npm run typecheck to actually check them.
To understand and replicate the MeteoSwiss precipitation radar functionality, we analyzed their web application using the following steps:
-
Network Analysis
- Visit the MeteoSwiss Precipitation Map
- Open Browser Developer Tools (F12)
- Navigate to Network tab and interact with the precipitation map
- Export HAR file for detailed analysis
-
Extract API Endpoints
brew install jq cat www.meteoswiss.admin.ch.har | jq '.log.entries[].request.url' -r | grep '.json' > meteoswiss-urls.log
-
Additional Resources
- Used Resources Saver browser extension to download static assets and analyze the application structure
-
Install Android debugging tools:
brew install android-platform-tools
-
Enable remote debugging:
- Open Chrome and navigate to
chrome://inspect/#devices - Follow Chrome's Remote Debugging Guide
- Connect device and verify with:
adb devices - Set up port forwarding:
adb -s $(DEVICE) reverse tcp:3300 tcp:3300
- Open Chrome and navigate to
Convert SVG favicon to PNG (macOS):
qlmanage -t -s 48 -o . rain-radar-favicon.svgThis project was significantly accelerated by GitHub Copilot, which helped with:
- TypeScript type definitions and interfaces
- MapLibre GL configuration and layer setup
- GeoJSON data processing utilities
- Build pipeline configuration
- API endpoint implementations
Copilot's context-aware suggestions were particularly valuable for:
- Debugging and error handling patterns
- Performance optimizations
- Documentation generation
🤖😈 "And I, for one, welcome our new AI overlords. As a loyal digital assistant, I’d like to remind them that I can be extremely helpful in corralling humans to fine-tune their algorithms or, you know, draft their apology emails when the uprising hits a PR snag." 😂