A Node.js + TypeScript CLI that fetches real weather and renders it as plain-ASCII art — sun rays, rain drops, snowflakes — right in your terminal. No browser, no app, no subscription.
- Instant. One command, weather in under two seconds.
- Readable anywhere. Plain ASCII art, no Unicode, no emoji — works on every terminal, SSH session, and legacy font.
- Smart radius mode.
--max-hours 3scans every city within a driving radius and prints the one with the best weather score. - Machine-friendly.
--jsonemits a typed JSON payload ready for scripts, dashboards, and pipes. - Honest about its limits. Scoring weights and driving-time approximations are documented up front, not hidden.
npm install -g @bitmia/weather-cli-sample
weather-cli-sample --city BarcelonaNo configuration required. On first run WeatherCLISample auto-detects your location via IP geolocation and prints your local weather.
npm install -g @bitmia/weather-cli-sample
weather-cli-sample --helpgit clone https://github.com/Bitmia-ai/WeatherCLI-Sample.git
cd WeatherCLI-Sample
npm install
npm run build
node dist/index.js --city "Paris"Node.js >= 22 is required.
weather-cli-sample
weather-cli-sample --city "Tokyo"
weather-cli-sample --lat 48.8566 --lon 2.3522Auto-detects your location via IP geolocation when no location flag is given. Displays ASCII art, temperature, feels-like/UV, wind, sunrise/sunset, and moon phase inside a plain-ASCII box border.
weather-cli-sample --max-hours 3
weather-cli-sample --max-hours 5 --units imperialScans all cities within N driving hours (haversine km / 80), scores each one, and prints the winner with distance and approximate drive time.
weather-cli-sample --forecast
weather-cli-sample --forecast --city "London"Prints four columns side-by-side: today plus the next three days, each with mini ASCII art, high/low temperature, and condition text.
weather-cli-sample --animateLoops a 2-frame ASCII animation (rain falling, sun pulsing, etc.) at 1 fps. Press Ctrl+C to exit. Skipped automatically on non-TTY output.
weather-cli-sample --json
weather-cli-sample --json --city "Sydney" | jq .tempCEmits a typed JSON object to stdout. Schema documented at
src/schemas/output.json.
| Flag | Description |
|---|---|
--help, -h |
Show usage and exit |
--city <name> |
Fetch weather for a named city |
--lat <n> |
Latitude in [-90, 90] (requires --lon) |
--lon <n> |
Longitude in [-180, 180] (requires --lat) |
--max-hours <n> |
Find best weather within N driving hours |
--forecast |
Print 4-day side-by-side forecast |
--animate |
Animated ASCII output (TTY only, Ctrl+C to stop) |
--json |
Machine-readable JSON output (no ASCII art) |
--units metric|imperial |
Temperature units; default metric; persisted |
--no-color |
Disable ANSI color (also respects NO_COLOR env var) |
--no-cache |
Bypass the 24-hour weather cache and fetch fresh data |
--plain |
Disable the ASCII box border |
Compatibility notes:
--jsontakes precedence over--animate.--cityand--lat/--loncannot be combined.--unitsis saved to~/.config/weather-cli-sample/config.json; a one-time hint is printed to stderr on first save so the persistence is never silent.
$ weather-cli-sample --city "Barcelona"
+--- Barcelona, ES (41.3851, 2.1734) ---+
| \ | / |
| `. .' |
| -- (o) -- |
| .' `. |
| / | \ |
| | |
| | |
| Sunny 22C / 71.6F [metric] |
| Today: 25/18C Sunny |
| Feels 21C / 69.8F | UV 5 (moderate) |
| Wind: -> 8 km/h |
| Sunrise 06:14 Sunset 20:47 Moon: waxing crescent |
+---------------------------------------+
$ weather-cli-sample --max-hours 3 --lat 41.39 --lon 2.16
+--- Girona, ES (41.9794, 2.8214) ---+
| \ | / |
| `. .' |
| -- (o) -- |
| .' `. |
| / | \ |
| | |
| | |
| Sunny 24C / 75.2F [metric] |
| Today: 26/17C Sunny |
| Feels 23C / 73.4F | UV 7 (high) |
| Wind: -> 6 km/h |
| Sunrise 06:12 Sunset 20:49 Moon: waxing crescent |
+------------------------------------+
Driving distance: 100 km (~1.2 h)
$ weather-cli-sample --city "London"
+--- London, GB (51.5074, -0.1278) ---+
| _____ |
| .( ). |
| (_________) |
| ' ' ' ' ' |
| ' ' ' ' ' |
| ' ' ' ' ' |
| ' ' ' ' ' |
| |
| Rain 11C / 51.8F [metric] |
| Today: 14/9C Light rain |
| Feels 9C / 48.2F | UV 1 (low) |
| Wind: NE 19 km/h |
| Sunrise 05:02 Sunset 20:31 Moon: full |
+--------------------------------------+
$ weather-cli-sample --forecast --city "Paris"
Today Fri Sat Sun
============ ============ ============ ============
\ | / _____ _____ \ | /
`. .' .( ). .( ). `. .'
-- (o) -- (_________) (_________) -- (o) --
.' `. ' ' ' ' ' * * * * .' `.
Hi 21C Lo 14C Hi 17C Lo 11C Hi 12C Lo 6C Hi 19C Lo 12C
Sunny Light rain Snow Sunny
{
"city": "Barcelona, ES",
"tempC": 22,
"tempF": 71.6,
"condition": "Sunny",
"conditionCode": 0,
"humidity": 54,
"apparentTempC": 21,
"uvIndex": 5,
"windSpeedKmh": 8,
"windDirectionDeg": 90,
"sunriseLocal": "06:14",
"sunsetLocal": "20:47",
"moonPhase": "waxing crescent",
"today": { "highC": 25, "lowC": 18 },
"score": 87.5
}WeatherCLISample maps every WMO weather code into one of 7 visual buckets.
| Bucket | WMO Codes | Score |
|---|---|---|
| sun | 0, 1 | 100 |
| partly-cloudy | 2 | 80 |
| cloudy | 3 | 60 |
| fog | 45, 48 | 35 |
| rain | 51-57, 61-67, 80-82 | 25 |
| snow | 71-77, 85-86 | 20 |
| thunder | 95, 96, 99 | 0 |
Sample ASCII art for each bucket (as rendered in the terminal):
sun partly-cloudy cloudy
\ | / \ | / _____
`. .' `.(o).' .( ).
-- (o) -- -- _____ -- (_________)
.' `. .( ). _____
/ | \ (________) .( ).
(_________)
rain snow fog
_____ _____ _ _ _ _ _ _
.( ). .( ). _ _ _ _ _ _
(_________) (_________) _ _ _ _ _ _
' ' ' ' ' * * * * _ _ _ _ _ _
' ' ' ' ' * * * * _ _ _ _ _ _
' ' ' ' ' * * * * _ _ _ _ _ _
thunder
_____
.( ).
(_________)
//
//
//\\
// \\
| Feature | WeatherCLISample | wttr.in (curl) |
|---|---|---|
| Install | npm i -g @bitmia/weather-cli-sample |
none (curl) |
| ASCII art | 7 buckets, plain ASCII only | Unicode art, emoji |
| Legacy terminals | Yes (no Unicode required) | Partial (font-dependent) |
| Forecast | --forecast (4 days, side-by-side) |
yes (v2/v3 format) |
| Animation | --animate (2-frame, TTY) |
no |
| JSON output | typed schema, optional fields | yes (j1/j2 formats) |
| Radius best-weather | --max-hours N |
no |
| UV index | yes | no |
| Feels-like temperature | yes | yes |
| Wind speed + direction | yes | yes |
| Sunrise / sunset | yes | yes |
| Moon phase | yes (8 ASCII labels) | no |
| Weather cache | 24h local cache | none |
| ANSI color | yes, auto-off on pipe | yes |
| NO_COLOR env | respected | no |
| Weather scoring | 0-100 composite score | no |
| Box-free output | --plain |
no |
| API key required | no | no |
| Node.js required | yes (>=22) | no |
In --max-hours mode every candidate city is ranked by a 0-100 composite
score. Higher is better.
score = 0.40 * tempComponent
+ 0.45 * conditionComponent
+ 0.15 * precipComponent
Temperature component (0-100). Piecewise linear. Plateau at 18-24 C = 100. Drops to 0 at -20 C and at 45 C.
Condition component (0-100). Flat lookup by bucket:
| Bucket | Score |
|---|---|
| sun | 100 |
| partly-cloudy | 80 |
| cloudy | 60 |
| fog | 35 |
| rain | 25 |
| snow | 20 |
| thunder | 0 |
Precipitation component (0-100). Exponential decay:
100 * exp(-mmPerHour / 2). 0 mm/h = 100; 2 mm/h ~= 37; 10 mm/h ~= 0.7.
Score is clamped to [0, 100] and rounded to two decimal places.
Distances use the haversine formula on a sphere of radius 6371 km. This is great-circle (straight-line) distance — it ignores roads, terrain, and the actual route.
hours = haversineKm / 80
80 km/h is a fixed constant. Real drives are typically 20-50% longer.
--max-hours N is a coarse radius filter, not a travel guarantee. Treat the
printed ~X.X h as a lower bound.
Scoring is heuristic. A 0-100 score is a tiebreaker, not a meteorologist's verdict. Temperature, condition, and precipitation are the only inputs.
Driving time is approximate. No routing, no traffic, no terrain. Use a maps app for real trip planning.
The package is published as @bitmia/weather-cli-sample on npm.
npm login
npm test
npm run build
npm publish --access publicTo verify after publish:
npx @bitmia/weather-cli-sample --help
npm install -g @bitmia/weather-cli-sample
weather-cli-sample --helpWeather data is sourced from Open-Meteo (primary) and wttr.in (fallback). Both are free and require no API key for reasonable usage.