Live earthquake & flood radar built with Next.js (App Router), React, Leaflet, Tailwind.
This guide explains how to set up, develop, and contribute effectively.
- Project Goals
- Tech Stack
- Quick Start
- Directory Structure
- App Architecture
- Data Sources & API Usage
- Caching, Rate Limiting & Resilience
- UI Components Overview
- Styling & UX
- Coding Standards
- Git Workflow & PR Process
- Issue Labels
- Performance Notes
- Accessibility
- Local Troubleshooting
- Release & Deployment
- Roadmap Ideas
- License
- Realtime map of recent earthquakes (USGS) with pulse markers and time-based playback.
- Flood events overlay (GDACS) with drawers, legends, and simple presets (World, Nigeria, UK/Europe, Pacific Ring).
- Smooth tour mode, date range playback, and historical day pick.
- Framework: Next.js (App Router)
- Runtime: React 18
- Maps: Leaflet + react-leaflet
- Styling: Tailwind CSS + PostCSS + Autoprefixer
- Utilities: classnames
- Build/Start Scripts:
npm run dev,npm run build,npm run start
- Requirements
- Node.js 20+ recommended
- npm 10+
- Install
npm install
- Run Dev Server
Visit http://localhost:3000
npm run dev
- Build & Start
npm run build npm start
Environment variables: None required for basic usage. The app fetches public APIs (USGS, GDACS).
.
├─ next.config.mjs
├─ tailwind.config.js
├─ postcss.config.js
├─ eslint.config.mjs
├─ package.json
├─ src/
│ ├─ app/
│ │ ├─ layout.jsx # Global CSS, <html> shell
│ │ └─ page.jsx # Main UI: map, controls, drawers, timeline/tour
│ ├─ components/
│ │ ├─ QuakeMap.jsx # Leaflet map & markers, flyTo logic
│ │ ├─ Controls.jsx # Presets, hazard toggles, date range, tour
│ │ ├─ FloodDrawer.jsx # Floods list/details UI
│ │ ├─ Drawer.jsx # Generic panel/drawer shell
│ │ ├─ Legend.jsx # Map legend
│ │ ├─ FXOverlay.jsx # Effects overlay hooks/portals
│ │ └─ RainPortal.jsx # Rain animation portal
│ └─ lib/
│ ├─ net.js # fetchJsonLimited + in-memory & localStorage cache
│ ├─ time.js # formatting, KPI helpers, default windows
│ ├─ usgs.js # USGS earthquake feeds & range queries
│ └─ floods.js # GDACS flood list queries
└─ public/ # Static assets
- App router entry:
src/app/page.jsxhosts the main interactive experience. - Map isolation:
QuakeMapis imported vianext/dynamicwithssr:falseto avoid Leaflet SSR issues. - State shape (conceptual):
hazard:"quakes" | "floods"mode: live vs. history (date range)flyTo:{ center: [lat, lng], zoom }for quick preset navigationstartISO,endISO: ISO strings for USGS range queries (history mode)historyDate: specific day picker (for floods)now: timestamp refresh anchortour: play/stop and step timing
- Effects & portals: visual effects like rain are rendered via portals to avoid map layering conflicts.
- USGS Earthquakes
- Recent windows:
hour:https://earthquake.usgs.gov/.../summary/all_hour.geojsonday:https://earthquake.usgs.gov/.../summary/all_day.geojson
- Range query (history):
https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&orderby=time&starttime=...&endtime=...
- Recent windows:
- GDACS Floods
- Search:
https://www.gdacs.org/gdacsapi/api/events/geteventlist/SEARCH?eventlist=FL&fromdate=YYYY-MM-DD&todate=YYYY-MM-DD&pagesize=...
- Search:
All remote calls go through
lib/net.js→fetchJsonLimitedto add:
- Host-level min gap between requests
- In-flight de-duplication
- In-memory cache and localStorage TTL cache
- Content-type aware body reading & safe JSON parsing
- Memory Cache: short-lived cache per-URL to avoid refetch storms.
- localStorage Cache: persisted TTL for browser reloads (
cache:${url}keys). - Host Throttling:
minGapMsper host to be polite to public APIs. - Retries: limited retries on transient failures.
- 204 / non-JSON handling: gracefully returns empty/typed responses.
When changing fetch behavior:
- Prefer raising TTL before adding complex queues.
- Keep USGS and GDACS within public rate expectations.
- Never block UI: show last cached data while fetching.
- QuakeMap
- Uses
CircleMarkermarkers with severity coloring. - Smooth
map.flyTotransitions for presets. - Keep marker count reasonable for performance (cluster in future).
- Uses
- Controls
- Hazard switch, preset buttons, date range inputs, history-day picker, tour controls.
canTourguards tour availability based on data state.
- FloodDrawer
- Lists GDACS events with level coloring (
green,orange,red).
- Lists GDACS events with level coloring (
- Legend
- Explains colors/sizes and hazard types.
- RainPortal / FXOverlay
- Encapsulate visual effects so the map remains interactive.
- Tailwind with a dark theme (
bg-neutral-950 text-neutral-100). - Keep panels simple (
.panelclasses) with soft shadows (shadow-glow). - Leaflet CSS: loaded once, attribution hidden (ensure compliance when publishing).
- Use motion sparingly: flyTo duration ~1.4s, pulse animations for events.
- Language: JavaScript (ES Modules) with React 18.
- Linting:
eslint.config.mjsextendsnext/core-web-vitals. - Formatting: follow existing Tailwind/JS style; avoid inline comments in commits; keep code self-explanatory.
- Imports: Use
@/alias forsrc/(via project config). - State: Prefer React state/hooks. If app grows, consider a small state library (only when necessary).
- Network: Always fetch via
lib/net.jshelpers; do notfetchdirectly in components.
main: always deployable.- Feature branches:
feat/<short-scope>(e.g.,feat/tour-loop). - Fix branches:
fix/<short-scope>(e.g.,fix/marker-flicker).
feat: add tour autoplay with step delay
fix: handle 204 responses in fetchJsonLimited
chore: bump tailwind content globs for src/*
refactor: extract draw panel into Drawer
docs: add contributor guide
perf: cache USGS range responses by URL+window
test: add net.js retry tests
ci: add build check on PR
- ✅ Scope is small and focused.
- ✅ Includes screenshots/gifs for UI changes.
- ✅ No direct network calls in components; uses
lib/net.js. - ✅ No console noise; errors handled and surfaced to UI where helpful.
- ✅ Lints cleanly (
next lintif configured) and builds locally. - ✅ Descriptive title & body (what/why/how, tradeoffs).
- ✅ Mentions rate-limit impact if touching fetch cadence.
Merging: Squash & merge, keep the PR title in Conventional Commit format.
type:bug,type:feature,type:perf,type:design,type:docsstatus:help-wanted,status:blockedpriority:p0(hotfix),priority:p1,priority:p2
- Leaflet rendering: large marker sets can stutter; consider:
- Filtering by magnitude or time window.
- Future: clustering or WebGL layers if needed.
- Memoization: memo heavy lists and computed ranges.
- Network cadence: respect
minGapMsto avoid UI stalls & API bans. - Animations: keep durations modest to avoid jank on low-end GPUs.
- Color contrast: ensure green/orange/red markers and legends meet contrast targets on dark background.
- Keyboard: drawers, buttons, and controls should be reachable & focus-styled.
- Motion: keep reduced-motion users in mind (future enhancement: honor
prefers-reduced-motion).
- Leaflet “window / document” SSR errors: ensure map code stays client-side (
dynamicwithssr:false). - CORS / Rate limits: rely on cache to avoid hammering endpoints; back off on failures.
- Everything is red / empty lists:
- Confirm
from/todates are valid and within data coverage. - Check network tab for 4xx/5xx; if 204/empty, UI should degrade gracefully.
- Confirm
- Dev server stuck:
- Kill previous process on port 3000 or
npx kill-port 3000. - Clear
.next/and restart:rm -rf .next && npm run dev.
- Kill previous process on port 3000 or
- Build:
npm run build→ Next.js production build. - Start:
npm start→ Node server (or serve via hosting provider). - Static assets: under
public/. - Env: none required for public APIs; for production, set
NEXT_PUBLIC_*only when adding optional keys/features.
CI (suggested):
- Lint & build on PR.
- Enforce Conventional Commit titles on PRs.
- Preview deploy per-PR if hosting allows.
- Earthquake clustering and magnitude filters.
- Playback timeline scrubber with keyframes.
- Offline cache & stale-while-revalidate UX.
- prefers-reduced-motion support.
- Tests: unit tests for
lib/net.js, integration snapshot for map layers.
MIT (unless specified otherwise). Include attribution where required by map tile providers and data sources (USGS/GDACS).