SkySight
Moved from vulture-web/docs/api/skysight.md
The catalogue of SkySight’s forecast regions and layers, kept by hand.
Why this exists
Section titled “Why this exists”SkySight publishes no machine-readable catalogue. Its own site keeps the regions
compiled into its JavaScript and the layers in a global on the authenticated
page, and the /api/layers endpoint the app has always called answers with a
list frozen years ago: twenty-five entries for Central Europe where the site
offers around thirty, and nine of those twenty-five are vector components rather
than forecasts anyone would pick.
So the catalogue is maintained here instead. It is hand-written — there is nothing upstream to proxy — and it carries three things SkySight’s own API leaves out: which model backs each region, how a layer is served, and a legend for every layer.
GET /api/skysight
Section titled “GET /api/skysight”Answers with the sections, the regions and the layers together. A client needs them at once: a layer is only forecast where its model runs, the region says which model that is, and the sections say where each layer belongs.
Request headers
Section titled “Request headers”| Header | Value |
|---|---|
Accept | application/json |
Authorization | Your API token |
Accept-Language | Optional. Language for layer names and descriptions |
Accept-Language takes a normal weighted list — nl-BE,nl;q=0.9,en;q=0.8 gets
Dutch. Supported: en, nl, de, fr, es, it, cs, pl. Anything else,
or no header at all, answers in English. Region names are not translated;
SkySight does not translate them either.
Response
Section titled “Response”{ "groups": [ { "id": "thermals", "name": "Thermals" }, { "id": "clouds", "name": "Clouds" } ], "regions": [ { "id": "EUROPE", "name": "Central Europe", "tz": "Europe/Warsaw", "model": "ss", "interval": 1800, "sw": [-9.5, 35.7], "ne": [31.5, 64.2] } ], "layers": [ { "id": "cape", "group": "clouds", "name": "CAPE / Storms", "description": "Convective available potential energy. Higher values indicate greater instability and larger updraughts within deep convective cloud.", "aircraft": ["glider", "paraglider", "hangglider"], "models": ["ss", "noaa", "hrrr", "dwd"], "tiles": "vector", "composite_models": [], "tile": "cape", "legend": { "unit_type": "", "unit": "J", "colors": [ { "name": "100", "value": "100", "color": [0, 0, 143] }, { "name": "400", "value": "400", "color": [0, 50, 255] } ] } } ]}Group fields
Section titled “Group fields”| Field | Type | Description |
|---|---|---|
id | string | The identifier layers are filed under |
name | string | Section header, in the requested language |
Sections are served as data, in the order to show them, so adding one here is
enough — a client files each layer under the group it names and lists the
sections in this order without having heard of them beforehand. Every layer’s
group is one of these ids.
Region fields
Section titled “Region fields”| Field | Type | Description |
|---|---|---|
id | string | SkySight’s region identifier, as used in tile URLs |
name | string | Display name |
tz | string | IANA time zone the region’s forecast hours are expressed in |
model | string | Model family: ss, dwd, hrrr or noaa |
interval | integer | Seconds between forecasts — 3600 hourly, 1800 twice an hour |
sw | [number] | South-west corner, [lon, lat]. Absent on the global model |
ne | [number] | North-east corner, [lon, lat]. Absent on the global model |
The corners let a client offer the right region for wherever its map is looking, rather than asking. They overlap on purpose — the Alps sit inside Central Europe — so a client wanting one region should take the smallest that contains the point. The global model is deliberately uncornered: its box covers one continent’s worth of the world and would swallow guesses that belong elsewhere.
Which regions an account may actually browse is between the account and SkySight; this lists them all and lets the client take the intersection.
interval matters: asking a dwd or hrrr region for a half past the hour
requests a forecast that was never produced, and the map comes back blank.
Layer fields
Section titled “Layer fields”| Field | Type | Description |
|---|---|---|
id | string | SkySight’s layer identifier, as used in tile URLs |
group | string | The id of one of the groups above |
name | string | Display name, in the requested language |
description | string | One sentence on what the layer shows, in the requested language |
aircraft | [string] | Aircraft the layer is meant for — see below |
models | [string] | Model families that forecast this layer |
tiles | string | vector or composite — see below |
composite_models | [string] | Model families serving a vector layer as a composite one instead |
tile | string | The tile to fetch — its own id unless it is drawn from another’s |
legend | object | Unit and colour stops |
A layer is available in a region when models includes the region’s model.
Aircraft
Section titled “Aircraft”aircraft is how a client narrows the catalogue to the pilot in front of it. Four
values appear:
| Value | Meaning |
|---|---|
glider | Sailplanes |
paraglider | Paragliders |
hangglider | Hang gliders |
plane | Powered aircraft — only the Lowest Cloud Layer (cceil) |
Most layers list all three soaring wings. The ones that do not are deliberate:
SkySight scales flight distance and cross-country speed to the wing and publishes
a separate layer for each, so pfdtot and potfd (950 km, 160 kph) carry
glider while pfdtothg and potfd_hg (330 km, 50 kph) carry paraglider and
hangglider. Both pairs share the names Potential Flight Distance and XC Speed,
which is correct — filtered to one aircraft, no pilot is ever shown both. A client
that ignores aircraft will show two identically named rows.
Filtering can leave a section empty, so a client must be ready to drop one rather than draw a bare header. Wave is the case that bites: SkySight means the middle altitudes (2000-4000 m) for paragliders as well, but no wave layer at all for hang gliders, so a hang glider pilot’s Wave section has nothing in it. In the other direction, Star Rating is for paragliders and hang gliders only, and a glider pilot never sees it.
Vector and composite tiles
Section titled “Vector and composite tiles”tiles decides whether a client can draw the layer at all.
vector— a vector tile of coloured polygons. Every stop inlegend.colorsis one index into the tile’sidxattribute.composite— a raster tile carrying the forecast value in the pixel’s red channel, scaled across the legend’s range, for a shader to colour. Drawing one needs a raster colour ramp. Mapbox v6 has no way to express that, so the iOS app skips these until its map engine can; they are listed so a client that can draw them may.
composite_models covers the layers that are vector tiles in most regions but
composite ones on the DWD and HRRR models — most of the thermal and cloud layers
are, which is why those regions are mostly undrawable on a vector map.
Layers drawn from another layer’s tile
Section titled “Layers drawn from another layer’s tile”tile is usually the layer’s own id, but SkySight packs some forecasts into a
neighbour’s tile, and a client must fetch what tile says rather than what id
says:
- Cloud cover (
tcc) rides in the low-cloud tile (CFRACL). It is painted as three translucent sheets out of that one tile — low from the period source layer, middle fromCFRACM, high fromCFRACH— each in a flat colour with the opacity carrying how much cloud there is,(idx + 1) / 9. Its legend is the three colours rather than a scale, which is why it is pinned rather than generated. - Significant weather (
sigwx) is drawn over the thermal-depth tile (dwcrit): the depth of thermals underneath, with cumulus and storm symbols from thesigwxtile on top as a repeating pattern, indexed by itsidx.
The legend
Section titled “The legend”legend.colors matches the shape SkySight’s own layers request answers with, so
a client already reading those needs no second decoder.
Colours are not stored. They are generated from the layer’s range against SkySight’s master ramp — 179 colours from deep blue through cyan, green, yellow and red to violet — sampled at even positions, one stop per step, interpolating between neighbouring entries. Changing a layer’s range therefore changes its legend, and nothing else has to be edited.
The rule was read off SkySight’s own rendering and is checked in the specs
against two legends captured from its live map: pfdtot reproduces exactly,
hwcrit in Central Europe to within one unit on a single channel of one stop.
One caveat for clients: SkySight uses this array for the legend it draws and clamps the fill to the last colour beyond it. A client using one array for both will leave the most extreme values unpainted unless it clamps the index itself.
Errors
Section titled “Errors”| Status | Reason |
|---|---|
403 | Missing or invalid Authorization header |
406 | Missing or invalid Accept header |
Language
Section titled “Language”Names and descriptions are SkySight’s own words, not a re-translation: they were
taken from the translation files SkySight publishes for its own site, so a pilot
reading Vulture sees the same terms as on skysight.io. That matters for soaring
vocabulary, where a literal translation often is not what pilots say —
hwcrit is “Hoogte van thermiek” in Dutch and “Thermik Obergrenze (MSL)” in
German, neither of which is a translation of “Height of Thermals”.
They live in locales/*.yml under skysight.layers, alongside the rest of the
site’s copy.
A handful of strings are English in every language, because SkySight has not translated them either — the potential-flight-distance description, the Cu coverage and surface wind descriptions, and Thermal Wave, which is new on their site. They fall back to English rather than to a missing-translation marker: an English sentence is readable, and “translation missing” is not.
