wayfarer-weather/README.md
Cayden Schwechten 6250d23297 init
2026-10-31 21:20:16 -05:00

120 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Wayfarer
A black-and-gold weather station: pixel-art skies, a heart-based comfort meter,
hourly and 14-day forecasts you can switch between, an animated radar map,
official alerts and air quality, and a switchable data source.
Built with Next.js 16 (App Router), TypeScript, Tailwind CSS v4 and Leaflet.
## Run it
```bash
npm install
cp .env.example .env.local # add whichever keys you have
npm run dev # http://localhost:3000
```
With no keys at all, everything except the OpenWeather map layers still works,
on Open-Meteo.
## What it shows
| Section | What's in it |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Alerts | Official NWS watches and warnings for US places; provider alerts elsewhere (WeatherAPI only). Each opens to show the full text. |
| Hero | Temperature, conditions, today's high/low, a precipitation outlook for the next 24 h, comfort hearts. |
| Conditions | Feels like, dew point, humidity, wind with direction and gusts, UV index, air quality (US AQI + PM2.5), pressure, visibility, cloud cover, precipitation, sun times, moon phase. |
| Hourly | 24 h / 48 h / 7-day chart (temperature, feels like, chance of precipitation) with a crosshair readout of any hour, or a full table. |
| Daily | Up to 14 days with a range bar per day. Tap a day for precipitation, wind, UV, humidity, sunrise, sunset and daylight. |
| Radar and maps | Animated radar (worldwide or high-detail US), plus OpenWeather precipitation, cloud, temperature, wind and pressure maps. |
A reading a provider doesn't offer is simply hidden. Nothing shows a fake zero.
## Providers and what each delivers
| Provider | Env vars | Hourly | Daily | Notes |
| ----------- | ---------------------------------------- | ----------------- | ----------------- | ------------------------------------------------------------------- |
| Open-Meteo | none | 7 days, 1 h steps | **14 days** | Free, no key. The deepest data here. |
| OpenWeather | `OPENWEATHER_API_KEY`, `OPENWEATHER_PLAN`| 5 days, 3 h steps | 5 days | `free` plan. No dew point or UV. |
| | | 48 h, 1 h steps | 8+ days | `onecall` plan (One Call 4.0). Separate subscription, 1,000 calls/day free. |
| WeatherAPI | `WEATHERAPI_API_KEY`, `WEATHERAPI_PLAN` | up to 3 days | 3 days (14 paid) | Includes its own alerts. |
| Tomorrow.io | `TOMORROW_API_KEY` | 5 days | 6 days | Free plan: 25 calls/hour. Responses are cached for 10 minutes. |
Every provider also gets these, from free sources:
- **Air quality and time zone:** Open-Meteo's air-quality API (CAMS data), so the AQI scale is the same whichever provider you pick.
- **US alerts:** the National Weather Service. Set `NWS_CONTACT` to an email or URL, because NWS asks apps to identify themselves.
- **Moon phase:** calculated locally.
## Radar sources
| Layer | Source | Coverage | Frames | Limits |
| ------------- | ------------------------------ | --------- | ----------------------- | ------------------------------------------------------------------------- |
| Radar | RainViewer | Worldwide | Last hour, 10-min steps | Max zoom 7, past frames only, **personal/educational use only** (since Jan 2026) |
| US radar | NWS NEXRAD via Iowa State IEM | US only | Last 50 min, 5-min steps | Shared academic service: fine for personal use, not for thousands of users |
| OpenWeather × 5 | OpenWeather map tiles | Worldwide | Current only | Needs `OPENWEATHER_API_KEY`; tiles are proxied by `/api/tiles` so the key stays secret |
US places open on the US radar layer automatically. The basemap is CARTO's dark style;
set `CARTO_API_KEY` (free at `carto.com/basemaps/apikey`) so `/api/tiles` can strip CARTO's
watermark while keeping the key server-side.
## How it fits together
```
Browser Server (Next.js route handlers) Outside
─────── ─────────────────────────────── ───────
WeatherApp ── /api/providers ──▶ which keys exist + each plan's limits
── /api/geocode ──▶ lib/weather/geocode.ts ─────────────────────▶ OpenWeather / Open-Meteo
── /api/weather ──▶ in parallel:
providers/<name> (required) ──────────▶ chosen provider
extras/air-quality (optional) ──────────▶ Open-Meteo AQ
extras/nws-alerts (optional) ──────────▶ api.weather.gov
RadarPanel ── /api/radar ──▶ RainViewer frame index ─────────────────────▶ RainViewer
── /api/tiles/… ──▶ OpenWeather + CARTO tile proxy ─────────────▶ OpenWeather / CARTO CDN
── NEXRAD + RainViewer tiles load straight from their servers (no keys involved)
```
If an optional source fails, its section just disappears; only a failed forecast shows an error.
- `lib/weather/types.ts`: the one normalized shape. Units are metric, times are UTC, and missing readings are `null`.
- `lib/weather/providers/`: one adapter per provider. OpenWeather has a folder with `free.ts` and `onecall.ts`.
- `lib/weather/extras/`: air quality and NWS alerts.
- `lib/radar/layers.ts`: every map layer and how to load its frames.
- `lib/display.ts`: unit conversion, time-zone-aware formatting, UV/AQI labels, moon phase, precipitation outlook.
- `components/forecast/`: `ForecastPanel` (the switch), `HourlyView` + `HourlyChart`, `DailyView`.
- `components/radar/`: `RadarPanel` (controls) and `RadarMap` (Leaflet, browser-only).
- `components/ui/ChoiceChips.tsx`: the chip group used for providers, views, ranges and map layers.
### Adding a provider
1. Write `lib/weather/providers/foo.ts` exporting a `WeatherProvider`, with `getForecast()` and `limits()`.
2. Add `"foo"` to `ProviderId` in `types.ts`.
3. Register it in `providers/index.ts`, then add its key to `.env.example`.
## Styling (Tailwind v4)
There is no `tailwind.config.js`; v4 is configured in CSS.
- `app/globals.css` holds the theme tokens in `@theme`. Colors like `--color-gold` become `bg-gold`, `text-gold` and so on, and the fonts become `font-display`, `font-pixel` and `font-sans`. It also holds one custom utility, `chamfer` (the cut corners), Leaflet control overrides, and a few base rules.
- Every other style is a utility class in the component that uses it. Layout is mobile-first, with `sm:` (640px and up) for the desktop arrangement.
- `lib/styles.ts` holds the class strings used by more than one component.
- To resize a frame's corners, add `[--cut:22px]` to that `Slot`'s `className`. Put fixed heights on the `Slot` itself, not its inner element, which is already `h-full`.
- The Leaflet overrides sit outside any `@layer` and are prefixed with `.leaflet-container`. Leaflet's own CSS is unlayered and loads later, so anything weaker loses.
- The hourly chart is hand-written SVG with no chart library. Temperature and chance of precipitation sit in separate bands on one time axis rather than sharing two y-axes.
## Mobile
- Uses `viewport-fit=cover` with safe-area insets, 44px tap targets and 16px inputs (so iOS doesn't zoom on focus).
- Chips, the hourly chart and the forecast strip scroll sideways; the page itself never does.
- The map ignores the scroll wheel, so scrolling the page doesn't zoom it; use pinch or the +/− buttons.
- "Use my location" requires HTTPS on phones. To test on your Android over LAN, use a Vercel preview deploy.
- Radar autoplay and the floating icon stop when the OS asks for reduced motion.
## Deploy & Legal Compliance
- **Vercel**: import the repo and add your environment variables (`OPENWEATHER_API_KEY`, `CARTO_API_KEY`, `NWS_CONTACT`, plus any optional provider keys) in Project Settings.
- **PM2**: `npm run build && pm2 start npm --name wayfarer -- start`.
- **CARTO domain lock**: once deployed, restrict `CARTO_API_KEY` to your production domain at `dashboard.basemaps.carto.com`. All `/api/*` routes also reject cross-site `Sec-Fetch-Site: cross-site` hotlinking automatically.
- **Built-in attributions**: `SiteFooter`, `PlaceSearch`, `AlertsBanner`, and `RadarMap` render the required live backlinks and license credits for OpenWeather (`CC BY-SA 4.0` / `ODbL`), Open-Meteo (`CC BY 4.0`), Copernicus Atmosphere Monitoring Service (`CAMS`), GeoNames (`CC BY 4.0`), WeatherAPI.com, Tomorrow.io, OpenStreetMap, CARTO, RainViewer, Iowa State IEM, and NOAA/NWS.
- **Non-commercial vs. commercial publishing**:
- **Free, ad-free personal / portfolio site**: compliant across every source out of the box.
- **Commercial site (ads, paid tiers, or business use)**: OpenWeather, WeatherAPI.com, NWS, and CARTO (`CARTO_API_KEY` includes 1M commercial tiles/month) permit commercial use within plan quotas, whereas **Open-Meteo** (forecast, geocoding, air quality), **RainViewer**, and **Tomorrow.io** free tiers are **non-commercial only** and require paid commercial plans or disabling before monetizing.