JavaScript, webdev

Building PowderCast: The Ultimate Open Source Weather App for Snowboarders 🏂

If you know me, you know I love two things: writing code that solves real problems, and shredding fresh powder.

For years, I’ve been frustrated with generic weather apps. You know the struggle – the app says “partly cloudy and 30°F” for the town near the resort, but when you get to the summit, it’s a whiteout with 50mph gusts and wind-hold on every lift.

The delta between “base village weather” and “summit weather” can be the difference between the best day of your season and a frostbitten disaster.

So, I did what any engineer would do:

I built my own solution: PowderCast.

The “Why”: Hyper-Local is Hard

Most free weather APIs give you general area forecasts. But for snowboarding, we need micro-climate data.

  • Wind Gusts: Average wind speed is useless. We need to know gusts to predict lift holds.
  • Snow Quality: “3 inches of snow” tells me nothing. Is it light, fluffy “Champagne Powder” (great!) or heavy, wet “Sierra Cement” (workout time)?
  • Elevation Matters: The weather at 6,000ft (base) is radically different from 10,000ft (summit).

PowderCast solves this by tapping into the National Weather Service (NWS) API, which allows for grid-based forecasting. This means we can pinpoint the exact lat/long of a resort’s summit and get a forecast specifically for that coordinate, not just the nearest zip code.

The Tech Stack

I wanted this to be fast, modern, and easy to maintain. Here’s the stack:

  • Next.js 15 (App Router): For the React framework. It’s blazing fast and the new routing paradigm is growing on me.
  • TypeScript: Because I value my sanity.
  • Tailwind CSS: For styling. I went with a “Glassmorphism” aesthetic – lots of transparency and blur effects to mimic looking through icy goggles.
  • NWS API: The unsung hero. It’s free, public domain, and incredibly detailed (if a bit quirky to parse).

The “Secret Sauce”: Calculating Snow Quality ❄️

This is my favorite part of the codebase. How do we programmatically determine if the snow will be epic? It turns out, temperature during precipitation is a strong proxy for snow water equivalent (SWE).

I wrote a utility in lib/snowLogic.ts that categorizes snow based on the temperature when it falls:

export function determineSnowQuality(tempF: number): SnowQuality {
if (tempF < 15) {
// Ultra light/dry. The dream.
return 'Champagne Powder';
} else if (tempF >= 15 && tempF <= 26) {
// Standard good winter snow.
return 'Premium Packed';
} else if (tempF >= 27 && tempF <= 34) {
// Heavy, wet, good for building kickers.
return 'Sierra Cement';
} else {
// Spring riding conditions.
return 'Mashtatoes/Slush';
}
}

We also track “Ice Coast” conditions – detecting freeze-thaw cycles where the temp drops below 32°F after being above it.

Feature Spotlight: The “Big Three” Dashboard

When you open PowderCast, you don’t get a generic 7-day list. You get the Big Three:

  1. Snow Accumulation: 24-hour and 7-day totals. If it’s over 6 inches in 24h, you get a glowing POWDER ALERT.
  2. Wind Gusts: We analyze gust data to predict lift status.
    • < 30mph: Green light.
    • 30-40mph: “Gusty – delays possible.”
    • 40-50mph: “High Winds – expect closures.”
    • 50mph+: “Extreme – stay home.”
  3. Visibility: Uses cloud cover and precip probability to tell you if you need low-light lenses.

Plus, I added a Bluebird Indicator. If cloud cover is < 25% and wind is low, it flags the day as a “Bluebird Day” – the holy grail of riding.

Under the Hood

The NWS API is powerful but requires a specific “dance.”
You first query a points endpoint with your lat/long to get the grid URLs, and then you query the forecast and grid data.

To make this snappy, I implemented a custom hook useNWSWeather that handles this chain and caches the result in localStorage. This keeps the app feeling instant when you switch between resorts or reload, and respects the API’s polite-use guidelines.

// Simplified hook logic
const fetchWeather = useCallback(async () => {
// 1. Get grid points
const pointResponse = await fetch(`${NWS_API_BASE}/points/${lat},${lon}`);
const pointData = await pointResponse.json();
// 2. Parallel fetch forecast + grid data
const [forecast, gridData] = await Promise.all([
fetch(pointData.properties.forecast),
fetch(pointData.properties.forecastGridData)
]);
// ... process and cache ...
}, [lat, lon]);

It’s a PWA

The best part? It’s a Progressive Web App. You can add it to your home screen on iOS or Android, and it behaves just like a native app. No App Store approval needed, no 30% cut, just pure web goodness.

Try It

I’ve open-sourced the project, and it currently supports 22+ major US resorts including Tahoe, Colorado, Utah, and the East Coast.

If you’re a dev, check out the code and maybe add your local hill. If you’re a rider, bookmark it for your next trip.

Code: https://github.com/greenido/PowderCast

Live Demo

See you on the mountain! 🏂


Discover more from Ido Green

Subscribe to get the latest posts sent to your email.

Standard

Leave a comment