March 2026 – Present · Solo developer
CloudDeck
Weather, runway, and route planning for VFR flights
- Java 21
- JavaFX
- Maven
- REST APIs
- PDFBox
- JUnit 5
- lines of Java
- 7,500+
- METAR and TAF
- Live
- alternate airport search
- 120 NM
Highlights
- Built a 7,500-line Java 21 and JavaFX flight-planning app that combines live FAA METAR and TAF data with runway, fuel, and route analysis.
- Wrote a route planner that applies the wind triangle for wind correction and groundspeed, then checks trip fuel against the aircraft's required reserve.
- Evaluates current and forecast weather at the planned departure and arrival times for a GO, CAUTION, or NO-GO decision, and suggests alternates when needed.
- Implemented JSON parsing, a file-based cache with stale-data fallback, HTTP error handling, and text and PDF briefing export.
The problem
A raw METAR is a dense string of codes:
KDAL 141953Z 18012G20KT 10SM FEW045 SCT250 33/19 A2991
Every pilot learns to read one, but a single observation only answers part of the question. Before a cross-country flight, a student pilot has to check the weather at both ends of the route, both now and at the times they will actually be there. They also have to work out which runway the wind favors and confirm the airplane will land with a legal fuel reserve. That usually means several websites, a flight computer, and a notepad.
What I built
CloudDeck puts those steps in one desktop app, organized into four workspaces: weather, route planning, aircraft profiles, and settings.
Airport weather. Enter any ICAO identifier and CloudDeck fetches the current METAR and TAF from the FAA Aviation Weather API. Each airport shows its flight category, a check against VFR minimums, a 12-hour trend (improving, steady, or deteriorating), sunrise and sunset, density altitude, and a preview of the FAA airport diagram.
Runway analysis. Runway headings come from the OurAirports dataset. For each runway end, CloudDeck splits the reported wind into headwind and crosswind components:
crosswind = windSpeed × sin(θ)
headwind = windSpeed × cos(θ)
Here θ is the angle between the wind and the runway heading. A negative headwind is a tailwind, and CloudDeck labels it as one. Runways are ranked by crosswind, and any that exceed the selected aircraft's crosswind limit are flagged.
Route planning. Given a departure, destination, aircraft profile, and forecast winds, the planner computes great-circle distance and true course, then solves the wind triangle for wind correction angle and groundspeed:
WCA = asin(crosswind / trueAirspeed)
groundspeed = trueAirspeed × cos(WCA) − headwind
From groundspeed it estimates flight time and fuel burn, adds taxi and climb fuel, and checks the total against the aircraft's usable fuel and required reserve.
Go/no-go. The route decision combines current conditions with the TAF period in effect at the planned departure time at one end and the planned arrival time at the other. The result is GO, CAUTION, or NO-GO, with the reason written out. When the destination is not a clear GO, CloudDeck searches airports within 120 nautical miles and ranks them as alternates by weather, usable runways, and distance.
Alerts and briefings. An alerts panel collects anything that needs attention, such as a fuel reserve shortfall, a departure or arrival at night, or a best runway that still exceeds the aircraft's crosswind limit. The finished plan can be exported as a text file and a PDF.
Engineering notes
Layered structure. The code is split into data clients, immutable domain models, a service layer, local storage, and the JavaFX interface. All of the flight logic lives in the services and has no dependency on JavaFX, so it can be unit-tested directly and could sit behind a web or mobile client later.
Caching with a fallback. Every network response goes through a small file-based cache with its own expiry: five minutes for METARs, thirty for TAFs, and a day for the OurAirports data. If a request fails and an older copy exists, CloudDeck shows the older copy instead of an error. On a ramp with poor Wi-Fi, a slightly stale observation that still shows its time is more useful than nothing.
Matching reference frames. Runway numbers are based on magnetic headings, but METAR winds are reported relative to true north. CloudDeck uses the true headings published in the OurAirports data, so the wind and the runway share a reference and no magnetic variation correction is needed.
Ceilings. A ceiling is the lowest broken, overcast, or obscured layer, not simply the lowest cloud. Few and scattered layers are ignored when checking VFR minimums, which matches how the FAA defines a ceiling.
Configurable minimums. The VFR thresholds are settings rather than constants, so a student can plan against personal minimums that are stricter than the regulations.
Tests. JUnit tests cover the configurable VFR thresholds, the forecast check at the planned arrival time, the route planning math, trend detection, briefing generation, and the FAA chart links, which depend on calculating the current 28-day AIRAC cycle.
What I would change next
Both ends of a runway have the same crosswind magnitude, so ranking by crosswind alone cannot tell them apart. I would break ties on headwind so the recommended end is never the tailwind end.
The NOTAM service is still a placeholder. Connecting it to the FAA NOTAM API would let closed runways drop out of the analysis automatically.
I would also add tests for the METAR and TAF parsers, especially the TAF change groups (FM, TEMPO, BECMG, and PROB), which is where most of the edge cases live, and package signed installers so a pilot can run CloudDeck without Maven.