An iOS weather app designed for cyclists, showing a multi-day hourly forecast with color-coded metrics at a glance.
- 7-Day Forecast: Current conditions plus hourly forecast cards through day 7
- 6 Cycling-Specific Metrics per card, each color-coded:
- Temperature (3-state: Shade / Sun / Real), precipitation, wind speed & direction, air quality, UV index, Solar Heat Gain Index (SHGI)
- Saved Locations & Carousel: Save up to 10 favorite locations; swipe horizontally between full weather pages. Page 0 is always your device's GPS location; starred pages follow in user-defined order; searched cities appear as a temporary page
- Star to Save: Tap the star next to the city name to save/unsave locations. Starring a temporary search page converts it in-place with no reload
- Location Picker: Auto-detects GPS location; tap the city name to search for any city or address
- Location Permission Handling: Actionable prompt with "Open Settings" and "Search Location" when location access is denied
- Recent Locations: Quick access to up to 8 recently viewed cities, swipe to remove
- Reorderable Saved Locations: Drag to reorder saved locations in the search sheet; order is reflected in the carousel
- Sunrise/Sunset Indicators: Interleaved between forecast cards with per-day times
- Timezone-Aware: Shows local time and timezone abbreviation when viewing a remote location
- Day/Night Cards: Visual distinction between daytime and nighttime hours
- Unit Toggle: Switch between metric (°C, m/s) and imperial (°F, mph); button shows active units (e.g. °C | m/s); defaults match device preferences and persist across launches
- Pull to Refresh: Swipe down to refresh; auto-refreshes when returning to the app after 15 minutes; silently retries location and weather requests on startup when iOS location service or network stack is not yet ready (common after device reboot)
- Three-State Temperature Column: Tap the column header to cycle through three modes — Shade (apparent/feels-like temperature,
thermometer.variable.and.figureicon), Sun (feels-like + SHGI solar heat offset,thermometer.sunicon), and Real (actual air temperature,thermometer.mediumicon); preference persists across launches - Smarter Precipitation Colors: Precipitation column color-coded by cycling impact — solid precipitation (snow, sleet, hail) always red; rain graded by probability and expected amount (green → yellow → orange → red)
- Minute Forecast Pane: Tap the Now row to expand a minute-by-minute precipitation intensity bar chart for the next 60 minutes. Auto-expands when rain is imminent. Shows "Clear for the next hour" when dry, or a regional unavailability note where Apple WeatherKit doesn't provide minute data
- Precipitation Radar: Live NEXRAD radar map shown in the expanded Now pane for US locations (CONUS, Alaska, Hawaii). Sourced from NOAA/NWS via Iowa Environmental Mesonet tile service — no API key required. Includes scale bar and attribution. Two location dots on all pages: grey dot at the forecast location (map centre, repositions when forecast city changes); pulsing blue dot at the live device GPS position, updated every 30 s while the pane is open. On the GPS page this shows where you are relative to the forecast location that was originally pulled; on saved/searched pages it shows your current position relative to that saved city. MapKit annotation projection ensures correct placement regardless of Mercator distortion or aspect ratio.
- Tactical Weather Alerts: Conditional alert pane surfacing safety-critical conditions (thunderstorms, freezing rain, dangerous gusts, government severe weather alerts) and ride-altering conditions (imminent rain, fog, extreme temps, black ice risk). Safety alerts always visible; lower-tier alerts collapsed behind an expandable chevron to reduce noise. Black ice model based on Jang (2025) physical formation principles.
- Splash Screen: Animated launch screen with slide-up transition
- Adaptive Layout: Responds to Dynamic Type settings with clamped scaling to prevent layout breakage
- Dark Mode: Full support for both light and dark appearance
- Solar Heat Gain Index (SHGI): 0–10 index of solar radiation impact on the cyclist, derived from Open-Meteo direct and diffuse radiation data. Color-coded green → yellow → orange → red → purple. The Sun temperature mode adds the SHGI offset (0–8°C) to apparent temperature to reflect how hot it actually feels on a bike in direct sun
- Unknown AQI State: When Open-Meteo AQI data is unavailable, AQI shows as 🫥 (gray) rather than defaulting to "Good"
- Zero API Keys: Uses Apple WeatherKit (native), Open-Meteo (public), and NOAA/NWS via IEM (public) — no API keys in source code
- iOS 17.0+
- Xcode 26.0+
- Apple Developer account (for WeatherKit capability)
- Apple Developer Portal: Go to Certificates, Identifiers & Profiles → select your App ID (
com.cycleweather.app) → enable "WeatherKit" on both the Capabilities tab and the App Services tab → Save- Note: capability propagation may take up to 30 minutes
- Xcode: Open the project, select the CycleWeather target → Signing & Capabilities → click "+ Capability" → add "WeatherKit"
- Open the project:
open CycleWeather.xcodeproj
- Select your target device (iOS 17.0+ — WeatherKit requires a real device with provisioning)
- Press Cmd+R to build and run
- Allow location access when prompted
CycleWeather/
├── CycleWeather/
│ ├── CycleWeatherApp.swift # App entry point, splash screen, URL scheme handler
│ ├── ContentView.swift # Main UI, forecast cards, metrics, attribution
│ ├── Models.swift # HourlyForecast model, color-coding, TacticalAlert model & engine
│ ├── WeatherService.swift # WeatherKit + Open-Meteo AQI, timezone handling
│ ├── LocationManager.swift # GPS location, custom location support
│ ├── SavedLocations.swift # Saved locations persistence & manager
│ ├── LocationSearchView.swift # City search with MKLocalSearchCompleter
│ ├── Info.plist # Permissions, URL scheme, app configuration
│ ├── CycleWeather.entitlements # WeatherKit entitlement
│ └── Assets.xcassets/ # Colors and launch assets
├── CycleWeather.xcodeproj/
├── CLAUDE.md
└── README.md
The app uses four free APIs with zero API keys:
- Current Weather — real-time temperature, wind, UV index for the "Now" card
- Hourly Forecast — temperature, wind, precipitation chance, UV index per hour
- Daily Forecast — sunrise/sunset times per day
- Minute Forecast — precipitation intensity for imminent rain detection (select regions)
- Weather Alerts — government-issued severe weather warnings
- Additional fields — visibility, dew point, humidity, apparent temperature, wind gusts, conditions (for tactical alerts)
Requires WeatherKit capability enabled on the App ID (see Setup above).
- Air Quality API (
/v1/air-quality) — hourly European AQI values- Mapped to 0-5 scale: unavailable → 0 (Unknown/gray), 0-20 → 1 (Good), 20-40 → 2 (Fair), 40-60 → 3 (Moderate), 60-80 → 4 (Poor), 80+ → 5 (Very Poor)
- Forecast API (
api.open-meteo.com/v1/forecast) — hourly direct and diffuse radiation for SHGIdirect_radiation(W/m²) — direct beam on horizontal surfacediffuse_radiation(W/m²) — scattered/sky radiation- SHGI formula:
min(10, (direct × 0.7 + diffuse × 0.5) × 0.8 / 80.0)
- Radar tile service — live NEXRAD composite reflectivity tiles in XYZ/Web Mercator format
- URL:
mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/{z}/{x}/{y}.png - Updates every ~5 minutes; transparent PNG overlaid on Apple Maps base layer
- Coverage: CONUS (lat 24–50°N, lon 125–66°W), Alaska (51–72°N), Hawaii (18–23°N)
- Displayed only within coverage bounds; absent for non-US locations
- URL:
- Every hour throughout the entire 7-day range
- Green: 15-25°C (ideal cycling range)
- Teal: 10-15°C (cool)
- Blue: Below 10°C (cold)
- Yellow: 25-30°C (warm)
- Red: Above 30°C (hot)
- Green: 0-4 m/s (calm)
- Yellow: 4-8 m/s (moderate)
- Red: Above 8 m/s (strong)
- Green: 0% probability or type
.none - Yellow: Rain 1–15% probability and amount < 0.3 mm (light drizzle risk)
- Orange: Rain 16–40% probability or amount 0.3–2.0 mm
- Red: Rain > 40% probability or amount > 2.0 mm; or any solid precipitation (snow, sleet, hail, mixed)
- Gray: 0 (Unknown — data unavailable)
- Green: 1 (Good)
- Teal: 2 (Fair)
- Yellow: 3 (Moderate)
- Red: 4 (Poor)
- Purple: 5 (Very Poor)
- Green: 0-2 (Low)
- Light orange: 3-5 (Moderate)
- Yellow: 6-7 (High)
- Red: 8-10 (Very High)
- Purple: 11+ (Extreme)
- Green: 0-3.5 (Low)
- Yellow: 3.5-5.5 (Moderate)
- Orange: 5.5-7.5 (High)
- Red: 7.5-9.0 (Very High)
- Purple: 9.0-10.0 (Extreme)
The app requests "When In Use" location permission to fetch weather for your current location. If denied, the app provides an "Open Settings" button and the option to search for a location manually.
CycleWeather is open source under the MIT License.
Note that while the source code is MIT licensed, this app integrates third-party services — including Apple WeatherKit and Open-Meteo — that carry their own attribution requirements and terms of service. See NOTICE for details. These obligations apply to anyone who builds and distributes the app.
This app was built as an experiment in agentic AI-assisted development, with no prior iOS/Xcode experience. See DEVELOPMENT.md for the full story.
0 comments
log in to comment.