A beautiful, glanceable weather app that tells you whether or not you'll need a coat.
Live at: coat-check.vercel.app
- Instant recommendation: "Bring a coat" / "No coat needed" / "Coat recommended but not necessary"
- Logic based on temperature, rain probability, and weather conditions for the 9 to 5 commute
- Separate advice for current hour, today, and tomorrow
- Full-screen interactive map background (MapLibre GL)
- Real-time precipitation overlay from OpenWeatherMap
- Pulsing location marker showing your selected city
- Smooth animated transitions between locations
- Automatically switches based on sunrise/sunset at your location
- Manual override available via theme toggle button
- Smooth fade transitions when switching themes
- Uses
suncalclibrary for accurate sunrise/sunset calculations
- Search any city worldwide with autocomplete suggestions
- Geocoding powered by Open-Meteo API
- Location persisted in localStorage across sessions
A hybrid approach ensures data is always fresh when you need it:
| Mechanism | What It Does |
|---|---|
| Hour-based staleness | Refreshes at the top of each hour (minute 1) |
| Heartbeat detection | Detects browser tab suspension (30s heartbeat, 60s tolerance) |
| Multiple wake events | Listens to visibilitychange, focus, and pageshow events |
| LocalStorage persistence | Survives browser restarts; only refreshes if hour changed |
- Glass-morphism cards with spotlight hover effects
- Smooth fade transitions on all data updates
- Zoom control for map (4 levels, persisted to localStorage)
- Countdown timer showing minutes until next auto-refresh
| API | Purpose | Rate Limit |
|---|---|---|
| Open-Meteo Weather | Weather forecasts (temperature, precipitation, conditions) | Free, unlimited |
| Open-Meteo Geocoding | City search and coordinates lookup | Free, unlimited |
| OpenWeatherMap Tiles | Precipitation radar overlay | Free tier (1M calls/month) |
| CARTO Basemaps | Light/dark map tiles | Free |
| mapcn | MapLibre React component wrapper | N/A |
src/
├── app/
│ ├── page.tsx # Main app component + refresh logic
│ ├── layout.tsx # Root layout with theme provider
│ ├── globals.css # Global styles + glass-panel utilities
│ │
│ ├── components/
│ │ ├── RainViewerBackground.tsx # MapLibre map + rain overlay
│ │ ├── WeatherCard.tsx # Morning/afternoon forecast
│ │ ├── CurrentWeatherCard.tsx # Current hour weather
│ │ ├── Header.tsx # Today/Tomorrow toggle
│ │ ├── LocationSearch.tsx # City search with autocomplete
│ │ ├── ZoomControl.tsx # Map zoom level selector
│ │ ├── ThemeToggle.tsx # Light/dark mode button
│ │ ├── SpotlightCard.tsx # Glass card with hover effect
│ │ ├── SpotlightText.tsx # Text with spotlight effect
│ │ └── LoadingScreen.tsx # Initial loading state
│ │
│ ├── hooks/
│ │ ├── useWeather.ts # Fetches and processes weather data
│ │ ├── useLocation.ts # Location state + localStorage
│ │ ├── useSunCalc.ts # Sunrise/sunset calculations
│ │ └── useCoatAdvice.ts # Coat recommendation logic
│ │
│ └── utils/
│ ├── weatherUtils.ts # Weather code → condition mapping
│ └── mapUtils.ts # Map tile coordinate helpers
│
└── components/ui/
└── map.tsx # MapLibre React wrapper (1200+ lines)
- Framework: Next.js 16 with Turbopack
- UI Library: React 19
- Styling: Tailwind CSS 4
- Maps: MapLibre GL JS
- Theme: next-themes
- Icons: Lucide React
- Sun Calculations: SunCalc
This project is licensed under the GNU General Public License v3.0.
- Weather data by Open-Meteo
- Map component by mapcn
- Map tiles by CARTO
- Precipitation overlay by OpenWeatherMap
- Deployed on Vercel