Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ripple

Watch how a natural event on one side of the world ripples out to the prices and products in your everyday life.

🌐 Live demo → ripple-taupe.vercel.app

Ripple plots live natural events on a dark world map and animates the supply-chain ripples from each event out to the production regions, commodities, and market prices it affects — then makes it personal with a price-watch basket and a near-term cost-pressure forecast for your location.

⏳ The API runs on a free tier that sleeps when idle, so the first load after a quiet period can take ~30–50s to wake up. Subsequent loads are instant.


Features

  • Live global events merged from three feeds (NASA EONET · USGS · GDACS), with magnitude-sized markers
  • Ripple arcs — event → nearest affected production regions → at-risk commodities, with an animated "comet" on the selected event
  • Live commodity prices (Yahoo Finance) rendered as hard-edged brutalist sparklines
  • Commodity lens — "show everything affecting coffee"
  • Today's Biggest Ripple hero + downloadable share card
  • My Basket + Ripple Forecast — pick everyday goods, get a personal near-term cost-pressure signal (RISING / WATCH / STABLE / EASING) from price momentum + active event threats, tied to your auto-detected location
  • Impact explainer — template baseline, optional Gemini overlay, cached per event
  • Neo-brutalist UI, fully responsive (mobile → desktop)

Tech stack

Layer Choice
Frontend React + TypeScript, Vite, deck.gl (ArcLayer/ScatterplotLayer), MapLibre GL (react-map-gl), Tailwind CSS v4, Framer Motion, TanStack Query, Zustand, lucide-react, html-to-image
Backend Go — chi router, database/sql, go:embed; concurrent multi-source ingester with on-demand caching
Database SQLite locally (pure-Go modernc.org/sqlite) · Supabase Postgres (pgx/v5) in production — driver chosen by DATABASE_URL
Hosting Vercel (frontend) · Render (backend) · Supabase (DB) — all free tier

The frontend talks to the Go API for all core data; a few keyless client-side lookups (map tiles, geolocation) are noted below.


APIs & data sources

Runs entirely on free, open data sources — no paid API keys required (Gemini is the only optional key, and it falls back to templates without one).

Backend (server-side):

API Use
NASA EONET v3 Wildfires, storms, volcanoes, floods, etc.
USGS Earthquakes M4.5+ weekly GeoJSON feed
GDACS Global disaster alerts
Yahoo Finance chart API Commodity price series + % change
Google Gemini (optional) Impact-explainer text (falls back to templates)

Frontend (client-side):

API Use
CARTO dark raster tiles Map basemap
Browser Geolocation Exact location (opt-in)
BigDataCloud Reverse-geocode coords → city name
ipwho.is · geojs.io · ipapi.co IP-based location fallback chain

Architecture

NASA EONET ┐
USGS       ├─▶ Go ingester (concurrent, on-demand cache) ─▶ Postgres/SQLite
GDACS      ┘                                                     │
                                                                 ▼
Browser ◀── React + deck.gl/MapLibre ◀────────── Go API (chi) ──┘
   (map, ripples, forecast, basket)          /api/events · /api/ripples
                                             /api/prices · /api/events/{id}

Events are cached in the DB and refreshed on demand (default TTL 15 min) — no background worker, so it behaves correctly on free hosts that sleep when idle.


API

Method Path Description
GET /health Liveness check
GET /api/events?status=&category=&limit= Events as a GeoJSON FeatureCollection
GET /api/events/{id} One event's detail (lazily generates + caches the impact explainer)
GET /api/ripples?status= Ripple arcs: event → affected regions + at-risk commodities
GET /api/prices?tickers=KC=F,CL=F Recent price trend per ticker
POST /api/ingest Force a refetch from all sources

Run locally

Requires Go 1.25+ and Node 20+. No database setup needed (defaults to a local SQLite file).

# Terminal 1 — backend
cd backend
cp .env.example .env      # optional; defaults are fine
go run ./cmd/server       # http://localhost:8080

# Terminal 2 — frontend
cd frontend
npm install
npm run dev               # http://localhost:5173

Vite proxies /api:8080 in dev, so there's no CORS setup locally.


Configuration

Backend env (see backend/.env.example):

Var Default Notes
PORT 8080 Set automatically by Render
DATABASE_URL sqlite://ripple.db Use a postgres://… URL for Supabase
CORS_ORIGINS http://localhost:5173,… Comma-separated allowed origins
EVENTS_CACHE_TTL_MINUTES 15 How long before a refetch
AI_PROVIDER template template | gemini | groq

Frontend env (frontend/.env.example): VITE_API_BASE — empty in dev; set to the deployed API URL in production.


Deployment

  • Backend → Render via the render.yaml blueprint (set DATABASE_URL, CORS_ORIGINS)
  • Database → Supabase (Session pooler connection string; the backend auto-creates its table on first boot — no migrations to run)
  • Frontend → Vercel (root directory frontend, env VITE_API_BASE = the Render URL)

Project structure

Ripple/
├─ render.yaml              # Render blueprint (backend)
├─ PROJECT_PLAN.md          # concept, data sources, roadmap
├─ backend/                 # Go API
│  ├─ cmd/server/           # entrypoint
│  └─ internal/
│     ├─ config/ db/ api/   # config, store+migration, chi handlers
│     ├─ eonet/ usgs/ gdacs/# data-source clients
│     ├─ ingest/            # concurrent on-demand cache
│     ├─ ripple/ prices/ impact/  # ripple engine, price client, explainer
│     └─ models/
└─ frontend/                # React + deck.gl
   └─ src/
      ├─ components/        # MapView, EventPanel, MyBasket, FilterBar, ui/*
      ├─ lib/               # api client, forecast, location, categories
      └─ store.ts           # zustand UI state

About

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages