Skip to content

Latest commit

ย 

History

46 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ‚ PowderCast v2.1

PowderCast Logo

Mountain weather for snowboarders and skiers, worldwide.
Because "70% chance of snow" doesn't tell you whether to call in sick.

๐Ÿš€ Try it live โ†’

Next.js 15 React 19 TypeScript 5 Tailwind 3 Zero API keys


โ„๏ธ What is this?

PowderCast is a hyper-local forecast for 722 ski resorts in the US, the Alps, the Dolomites, the Pyrenees and Japan. It answers the only question that matters at 6am:

Where should I ride, and which day?

It knows your ski pass, so it won't recommend a mountain you'd need a second mortgage to get into. It knows whether it's raining at the base, so you won't drive three hours to ski on a Slurpee. And it's a fully static site with no backend, no API keys and no database. Nothing to page anyone about.

Where Resorts What the locals call good snow
๐Ÿ‡จ๐Ÿ‡ญ Alps (FR ยท CH ยท AT ยท DE ยท IT) 387 Pulverschnee
๐Ÿ”๏ธ US Rockies 79 Champagne powder
๐Ÿ US East & Midwest 68 "Loud powder" (ice)
๐Ÿ‡ฎ๐Ÿ‡น Dolomites 53 Whatever's under the espresso
๐Ÿ‡ฏ๐Ÿ‡ต Japan 50 JaPow
๐ŸŒฒ US West 46 Sierra Cement (with love)
๐Ÿ‡ฆ๐Ÿ‡ฉ Pyrenees 39 Pols / polvo

โœจ Features

๐Ÿ—บ๏ธ Four ways to look at the mountains

View What it's for
โ›ฐ๏ธ Single Mountain Everything about one resort, with the verdict on a phone's first screen
๐Ÿ“Š Compare Regions Every resort in a region side by side, ranked by Ride Score, plus a map
๐Ÿ—“๏ธ 7-Day Planner Resorts ร— days in one grid, so the best mountain and the best day stand out
โญ Compare Favorites Your shortlist, head to head

๐ŸŽฏ The Ride Score

One number from 0 to 100 built from new snow, snow quality, wind, visibility and temperature. It's shared by every view, so the same day can't score 55 in one tab and 43 in another. (That happened once. It's in the commit history. We don't talk about it.)

Score Verdict
๐Ÿ’Ž Epic Conditions: send the "I'm sick" email now
๐Ÿ‚ Great: worth the drive
๐Ÿ”๏ธ Fair Groomers: corduroy and coffee
โš ๏ธ Marginal: good day to wax your board
๐ŸงŠ Poor: good day to sit in the lodge

๐ŸŒก๏ธ Conditions that actually matter

  • Today at a glance: the Ride Score plus the four numbers that decide the day (new snow, temperature, gusts, snow line), all above the fold on a phone
  • Snow line: where the freezing level sits between base and summit. If it's in the middle, the top gets powder and the bottom gets a car wash. This is the most important number in the Alps and the maritime US ranges.
  • Snow forecast: 24h and 7-day totals with hourly detail, plus a ๐Ÿšจ Powder Alert at 6"+
  • Base depth: settled snow already on the ground
  • Wind & aspect: which slopes are wind-loaded (deep) and which are scoured (firm enough to hear coming)
  • Firn window: spots the overnight-freeze, daytime-thaw spring corn cycle and tells you when to be on it. Too early is ball bearings, too late is mashed potatoes.
  • Base โ†” summit toggle: real elevation-corrected numbers, not the same forecast twice
  • ๐Ÿฅถ wind chill and frostbite warnings, ๐Ÿ’จ wind-hold risk, โ˜€๏ธ bluebird detector
  • ๐Ÿ”ฌ Pro View: every raw number, for people who read avalanche bulletins for fun

๐ŸŽซ Pass-aware

Tag your Ikon (68 resorts), Epic (43) or Mountain Collective (16) pass and the whole app narrows to mountains you can ride without buying another lift ticket.

๐Ÿ“ Near me

One tap ranks resorts by distance. "Nearby" also works as a region in the planner and comparison, and there's a map with pins coloured by Ride Score. Your location stays in memory and never goes into the URL, so a shared link doesn't tell your friends where you live.

๐Ÿงฐ Everything else

  • ๐Ÿ“ Metric or imperial, defaulting to what the resort's locals use. Every view follows the setting, including the ones that used to forget.
  • ๐Ÿ”— Shareable links: resort, elevation, view and region all live in the URL, so back/forward, refresh, bookmarks and the share button just work
  • โญ Favourites and auto-refresh that pauses when the tab is hidden
  • ๐Ÿ“น Live webcams for 25 major resorts, and website links for the other 669

๐ŸŒ Where the data comes from

Region Provider Model
United States National Weather Service NDFD gridpoints
French Alps, Pyrenees Open-Meteo Mรฉtรฉo-France AROME HD (1.5km)
Switzerland, Austria, Bavaria, Dolomites Open-Meteo DWD ICON-D2 (2km)
Japan Open-Meteo JMA Seamless (5km)
Scandinavia (forecast-ready, no resorts yet) Open-Meteo MET Norway Nordic (1km)

The provider is picked automatically from the coordinates. Open-Meteo steps in if NWS is having a day. Neither needs an API key.

Resort data comes from OpenSkiMap, an open dataset built from OpenStreetMap that includes real piste elevations.

๐Ÿš€ Quick start

nvm use            # Node 22 (see .nvmrc)
yarn install
yarn dev           # โ†’ http://localhost:3000

public/resorts.json is committed, so you only need yarn build:resorts if you want to regenerate it from OpenSkiMap.

Pushing to main runs the unit tests, builds the static export and deploys to GitHub Pages (deploy.yml).

๐Ÿ—๏ธ Architecture

app/                     Next.js App Router (static export)
components/              UI: cards, views, map, planner grid
hooks/
  useForecast.ts         Single + multi-resort fetching, caching, fallback
  usePlanner.ts          Resort ร— day outlook grid
  useGeolocation.tsx     "Near me", held in memory only
  useUrlState.ts         View state โ‡„ URL
  useUnits.tsx           Metric/imperial preference
  usePassFilter.ts       "My pass" preference
lib/
  providers/             WeatherProvider implementations + routing
    nws.ts               US National Weather Service
    openMeteo.ts         Global, with regional high-res model selection
  types.ts               Resort + the normalized SI forecast model
  conditions.ts          Normalized SI โ†’ rider-facing display model
  scoring.ts             The one and only Ride Score
  series.ts              Window reductions over the hourly series
  planner.ts             Multi-day outlook
  lapseRate.ts           Elevation correction for providers that need it
  nearby.ts              Great-circle distance ranking
  urlState.ts            URL parse/serialize
  units.ts               Unit-system-aware formatting
  snowVocabulary.ts      Region-specific snow terminology
  passes.ts              Ski pass metadata and filtering
data/passes.json         Ikon / Epic / Mountain Collective rosters
data/webcams.json        Curated webcam overlay
scripts/build-resorts.js Regenerates public/resorts.json from OpenSkiMap

๐Ÿ“ The normalization rule (learned the hard way)

Every provider's data is converted to SI as soon as it arrives (ยฐC, mm, km/h, m) and converted to display units exactly once, at the edge.

This matters because the providers disagree in ways that fail silently. NWS reports snowfall in millimetres, Open-Meteo in centimetres, and snow depth in metres. An earlier version ran NWS millimetres through a centimetre conversion, overstated every snow total by 10ร—, and fired Powder Alerts on 0.6" of snow. Some people probably drove to a mountain over that. Normalizing once, inside the provider, keeps that class of bug out of the components.

๐Ÿ”๏ธ Elevation

A resort's base and summit coordinates are usually a few hundred metres apart, well inside a single 2.5km NWS grid cell. Palisades Tahoe's base and summit both resolve to grid REV 28,94, so a coordinate-only "dual point" forecast gives you the same forecast twice.

What actually separates them is elevation. Open-Meteo accepts an elevation parameter and downscales properly. NWS can't, so PowderCast applies a lapse-rate correction and labels that view as modelled.

๐ŸŽซ Ski passes

data/passes.json holds the Ikon, Epic and Mountain Collective rosters with access tiers (unlimited / N days / partner).

โš ๏ธ Pass affiliations change every season. Resorts join, leave and swap tiers every year. The file records which season it was verified against, so re-check it against ikonpass.com and epicpass.com before each winter.

yarn verify:passes   # exits non-zero if any roster entry matches no resort

An unmatched entry usually means the resort is below the size threshold (most Midwest Epic hills are), its upstream name changed, or it left the pass.

๐Ÿ“ Scripts

Command Description
yarn dev Development server
yarn build Static export to ./out
yarn lint ESLint
yarn test Unit tests (no network)
yarn test:providers Live provider contract tests (hits the network)
yarn build:resorts Regenerate public/resorts.json from OpenSkiMap
yarn build:resorts --refresh Re-download the source dataset first
yarn verify:passes Check every pass entry still matches a resort
yarn generate:icons Rebuild the favicon and app icons

๐Ÿงช Testing

yarn test              # 126 assertions across 7 suites, no network, ~15s
yarn test:providers    # live contract tests against NWS + Open-Meteo

The unit suite runs on synthetic data and a captured NWS gridpoint fixture (tests/fixtures/nws-gridpoint-REV-28-94.json). It covers NWS processing, scoring, units and the planner, elevation, the resort schema, URL state and nearby ranking.

Every case corresponds to a bug that actually shipped. If a test fails, add a case rather than loosening the existing one.

๐Ÿ—บ๏ธ Adding a country

The forecast layer is already global. Adding a country (say, Norway, whose weather model is already wired up) takes two lines in scripts/build-resorts.js:

const COUNTRIES = {
  // ...
  NO: { regionCode: 'scandinavia', timezone: 'Europe/Oslo' },
};

Then run yarn build:resorts. If the country needs a new tab, add it to REGIONS in lib/regions.ts (scandinavia and canada are already there), and add a high-resolution model to REGIONAL_MODELS in lib/providers/openMeteo.ts if one covers the area.

๐Ÿ“š More docs

Deeper notes are in docs/, including the Pro View, debugging tips and the snow accumulation bug post-mortem.

๐Ÿ“„ License & fine print

Educational project. Weather data: NOAA/NWS (public domain) and Open-Meteo (CC BY 4.0). Resort data: OpenSkiMap / OpenStreetMap contributors (ODbL). Map tiles: OpenStreetMap contributors.

๐Ÿ”๏ธ Not a substitute for official avalanche bulletins or resort snow reports. PowderCast can tell you it's a powder day. It can't tell you a slope is safe. Check the avalanche forecast, carry the gear and ride with friends.


Made with โ„๏ธ and too much coffee by @greenido
If PowderCast finds you a powder day, the first chair is on you.

About

A high-performance web application for Snowboarders that leverages the National Weather Service (NWS) API to deliver hyper-local mountain weather data.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages