I Built a Weather Engine That Tells You When to Ride, Play, or Water

I Built a Weather Engine That Tells You When to Ride, Play, or Water

March 12, 2026 · by Michael Morrison

One decision engine, three audiences: a yes/maybe/no verdict for riders, rec league players, and gardeners.

Every mountain biker knows the ritual. It rained last night. You check the radar, clear now. You check the trail association’s Facebook page, nobody’s posted. You text your riding buddy: “Think the trails are good?” They don’t know either. So you either stay home and miss a perfectly rideable day, or show up and chew through muddy trails that needed another six hours to dry.

I got tired of guessing so I built a weather decision engine that answers the question directly: is it too wet to ride?

Then I realized the same engine could answer two more questions: is this field playable? and does my garden need watering?

This is the story of the Groundwise engine, a single Swift package that powers three iOS apps by asking the same underlying question from different perspectives.

The Problem With “Did It Rain?”

Weather apps mostly tell you what will happen, and to a lesser degree they can tell you what happened. What they don’t tell you is what it means for the specific thing you want to do.

Half an inch of rain means completely different things depending on context:

  • On a concrete skatepark, it sheds in a couple hours. You’re probably fine by afternoon.
  • On a dirt trail, it might need 24 hours with good sun and wind. Or 48 hours or more if it’s overcast and cold.
  • On a clay tennis court, you might be waiting even longer, clay holds moisture and damages easily when wet.
  • In a container garden on a sunny patio, that half inch drained through the potting mix hours ago and your herbs might need water again tomorrow.

The answer isn’t just “how much rain,” it’s how much rain, on what surface, how long ago, and what the drying conditions have been since.

From Weather Data to a Verdict

So I built a weather analysis engine that takes in a handful of weather observations and produces a single categorical verdict regarding an action on a specific surface: Yes, Maybe, or No.

The inputs are straightforward, stuff you’d get from any weather API:

  • Precipitation totals (last 24, 48, and 72 hours)
  • How long since rain ended
  • Whether it was light, steady, or a downpour
  • Current temperature, wind speed, humidity, and cloud cover
  • Whether it’s actively raining right now

Plus one critical piece of context: what surface are you asking about?

The engine defines 17 surface types across three categories. Each has a drying multiplier that controls how fast moisture clears, for example:

SurfaceDrying SpeedNotes
Metal skateboard ramps2.8xFastest, sheds water, heats up quickly
Artificial turf2.5xEngineered to drain
Asphalt2.2xDark surface, absorbs heat
Concrete2.0xDrains well, slower to heat than asphalt
Potting mix2.0xLoose, fast-draining soil
Compost1.2xActive decomposition generates some heat
Dirt/ground1.0xBaseline, absorbs and holds water
Natural grass1.0xRoot systems retain moisture
Amended soil (mulched)0.7xMulch deliberately slows evaporation
Clay0.7xDense, holds water, slow to release

That 4x difference between metal and clay isn’t just a number, it’s the difference between “rideable in an hour” and “unplayable until tomorrow.”

The Decision Pipeline

The engine runs checks in a specific order, with the most critical conditions evaluated first:

1. Is the ground frozen? If there’s an ice or snow hazard, the verdict is No regardless of moisture. This check alone is about 360 lines of code, freeze/thaw cycles are surprisingly complex. A concrete skatepark clears ice in 6 hours at 55°F, but a dirt trail might need 72 hours at 45°F to fully thaw and dry.

2. Is it actively raining? Straightforward gate. If precipitation is falling, the answer is No (or Maybe for very light drizzle on a fast-draining surface with strong drying conditions).

3. Calculate a wetness score. This is where the real modeling happens. The engine combines:

  • A rain score weighted toward recent precipitation (70% from last 24h, 20% from 24-48h, 10% from 48-72h)
  • A timing score that decays linearly over 24 hours since rain ended
  • A drying strength composite that factors in temperature, wind, humidity, and cloud cover
  • Residual wetness for absorbent surfaces, heavy rain on dirt or clay retains moisture well beyond what the timing score captures

4. Apply the verdict thresholds. A wetness score below 0.3 means Yes (dry enough). Between 0.3 and 0.6 means Maybe (borderline). Above 0.6 means No (too wet).

5. Sensitivity veto. High-sensitivity surfaces (like newly seeded lawns or natural grass athletic fields) get pushed from Maybe toward a more protective verdict. The engine would rather tell you to wait than let you damage a surface that’s expensive to repair.

One Engine, Two Perspectives

If you’re wondering how the above, which is described in terms of using a surface, could possibly apply to a container garden, it’s a fair question. And this is where the engine morphed into serving a series of apps instead of just one:

The engine calculates a wetness score. For riders and athletes, high wetness is bad, you want dry conditions. For gardeners, high wetness is good, it means you can skip watering.

Same math, opposite interpretation:

Wetness ScoreRider/Athlete ViewGardener View
Low (< 0.3)Yes, go ride!Yes, water today
Medium (0.3-0.6)Maybe, check conditionsMaybe, check soil
High (> 0.6)No, too wetNo, skip watering

The engine calls this EngineMode, either wetnessConcern or drynessConcern. A single enum that flips the entire interpretation layer while keeping the underlying moisture model identical.

Yardwise (the gardening app) uses slightly shifted thresholds, 0.15 and 0.45 instead of 0.3 and 0.6, because the stakes of getting it wrong are lower. Missing a watering day is a mild inconvenience. Riding a muddy trail damages the trail. Playing softball on a muddy clay infield isn’t great. You get the idea.

Why Not Just Show a Percentage?

Early versions of the apps showed a moisture percentage, and it wasn’t good. I didn’t know what to do with “the trail is at 47% moisture.” Is that rideable? It depends on the surface, on your own risk/comfort tolerance, on whether you care about trail damage, etc. A percentage pushes the decision back onto the user, which is exactly the problem the app was supposed to solve.

The solution was to simplify down to three states: Yes/Maybe/No, with an explanation of why. The Maybe state exists specifically for conditions where reasonable people would disagree. I have near me both public and private mountain bike trails, and the tolerance for mud varies widely based on level of traffic, so Maybe is when deferring to rider’s judgement is actually correct. The engine shows you the contributing factors (temperature is helping, but humidity is holding things back, for example) so you can make the final call.

Each verdict also carries a confidence level (Low, Medium, High). Confidence drops when timing data is missing, when rain has been patchy and unpredictable, or when the wetness score lands right on a threshold boundary.

What’s Coming in This Series

If you find talk of drying multipliers and residual wetness scores riveting, then hold on to your butts! This is merely the first article in a series about building the Groundwise engine. Coming up:

  • Turning Raw Weather Into a Drying Model - The math behind drying strength, residual wetness, and why rain intensity matters as much as total accumulation
  • One Engine, Three Apps - How to structure a Swift package that serves multiple products with different surface libraries and threshold calibrations
  • Edge Cases That Break Your Weather Model - Freeze/thaw cycles, cold-weather plant dormancy, the surprising complexity of “is snow melting?”, and dispatches from the great Nashville ice storm of 2026
  • Flipping the Question - How the Yardwise inversion works, including manual watering tracking and evaporative demand suppression
  • Building Confidence Into Uncertain Verdicts - Why three states beat a percentage, and how to communicate uncertainty without creating anxiety

The Apps

The Groundwise engine powers three apps, all available for iOS:

  • Ridewise, ride conditions for trails, skateparks, bike parks, and pump tracks
  • Fieldwise, field conditions for rec league sports on grass, turf, clay, and hard courts
  • Yardwise, watering guidance for casual gardeners with lawns, beds, and containers

All three are built by Stalefish Labs, a small indie studio focused on simple tools for getting outside and doing things together.


If you’ve built something that turns raw data into human decisions, I’d love to hear how you approached the threshold and confidence problem. Drop a comment or find us on Bluesky.

Want more like this?

Subscribe to get new posts from The Lab delivered to your inbox.

or grab the RSS feed