Logbook · Entry 04Palette design5 min read

The stability ramp, measured

The stability field is the first thing a pilot reads on a Meteogram: one glance at the colour says what kind of day it is, and every line that matters — usable lift, cloud base, the wind barbs, the markers — is drawn on top of it. Its palette therefore holds two jobs at once: loud enough to call the day, quiet enough that everything drawn over it stays legible. Here is how the shipped eight-class ramp resolves that tension, and the one measured defect in its lineage that a validator caught where every reviewing eye had signed off.

Every number here is reproducible: colour difference is ΔE, Euclidean distance in the OKLab colour space scaled by 100, with colour-vision deficiency simulated by the Machado–Oliveira–Fernandes (2009) matrices at full severity — protanopia and deuteranopia, the two axes this article’s validator simulates. Lightness spans are CIE L*. The shipped palette’s figures compute their values from the package export, so the article cannot drift from what renders.

What the field owes the lines above it

Figure-ground contrast comes first. Every point of saturation a field palette spends on itself is taken from the legibility of the content above it, so the whole ramp lives in a pale register — just under twenty points of lightness, all of it near the paper. Salience still works, because salience is relative: with the field quiet, the warm unstable classes are the loudest thing on the chart without spending any ink mass, and the classes that dominate an ordinary summer field — conditional instability, stable air — recede instead of shouting. A field earns attention for its exceptions by being quiet about its rule.

The register has a price, and it is paid openly: 19.6 L* points of lightness across eight classes cannot also carry a grayscale-survivable ordering, so none is claimed. Class identity rides hue; class order rides the channels the chart already has — the key names every cell in plain words, the cursor readouts state the class at any point, and the field’s own geometry orders it (stable air sits where stable air sits). The palest cells stand near 2:1 against the surface because receding into the page is the design, not an accident.

See both palettes below — the shipped ramp and its ancestor — with grayscale rows showing exactly what ordering the register gives up.

A background palette and its lineage

A quiet field spends its lightness budget on the chart content drawn above it; the key and readouts carry class order.

The shipped default strip runs #d95f52, #de8f3a, #c67eb6, #aeaad9, #d7b29b, #768bb9, #9aa19d, #b3b9b6 on its design surface #fffdf8; its luminance-matched grays are #858585, #a1a1a1, #969696, #afafaf, #b9b9b9, #8b8b8b, #9f9f9f, #b8b8b8, which do not darken in class order, so the grayscale row loses the sequence. The canadarasp strip runs #ff3d3d, #ff7800, #ff96ff, #ccbfff, #facab1, #8080e6, #cccccc, #999999 on its design surface #8080e6; its luminance-matched grays are #898989, #9f9f9f, #bcbcbc, #c7c7c7, #d4d4d4, #8b8b8b, #cccccc, #999999, which do not darken in class order, so the grayscale row loses the sequence.

The default stability ramp and the historical canadarasp palette as swatch strips, each above its luminance-matched grayscale row Eight stability classes from very unstable to strong inversion, left to right. The shipped default strip runs #d95f52, #de8f3a, #c67eb6, #aeaad9, #d7b29b, #768bb9, #9aa19d, #b3b9b6 on its design surface #fffdf8; its luminance-matched grays are #858585, #a1a1a1, #969696, #afafaf, #b9b9b9, #8b8b8b, #9f9f9f, #b8b8b8, which do not darken in class order, so the grayscale row loses the sequence. The canadarasp strip runs #ff3d3d, #ff7800, #ff96ff, #ccbfff, #facab1, #8080e6, #cccccc, #999999 on its design surface #8080e6; its luminance-matched grays are #898989, #9f9f9f, #bcbcbc, #c7c7c7, #d4d4d4, #8b8b8b, #cccccc, #999999, which do not darken in class order, so the grayscale row loses the sequence.In the canadarasp strip the stable swatch matches the design surface exactly, in colour and in grayscale.VeryunstableUnstableConditionalstrongConditionalNearneutralStableInversionStronginversionshipped defaultcolourgrayscaleVery unstable: #d95f52 on #fffdf8Unstable: #de8f3a on #fffdf8Conditional · strong: #c67eb6 on #fffdf8Conditional: #aeaad9 on #fffdf8Near neutral: #d7b29b on #fffdf8Stable: #768bb9 on #fffdf8Inversion: #9aa19d on #fffdf8Strong inversion: #b3b9b6 on #fffdf8Very unstable as grayscale: #858585Unstable as grayscale: #a1a1a1Conditional · strong as grayscale: #969696Conditional as grayscale: #afafafNear neutral as grayscale: #b9b9b9Stable as grayscale: #8b8b8bInversion as grayscale: #9f9f9fStrong inversion as grayscale: #b8b8b8#d95f52#de8f3a#c67eb6#aeaad9#d7b29b#768bb9#9aa19d#b3b9b6canadaraspcolourgrayscaleVery unstable: #ff3d3d on #8080e6Unstable: #ff7800 on #8080e6Conditional · strong: #ff96ff on #8080e6Conditional: #ccbfff on #8080e6Near neutral: #facab1 on #8080e6Stable: #8080e6 on #8080e6Inversion: #cccccc on #8080e6Strong inversion: #999999 on #8080e6Very unstable as grayscale: #898989Unstable as grayscale: #9f9f9fConditional · strong as grayscale: #bcbcbcConditional as grayscale: #c7c7c7Near neutral as grayscale: #d4d4d4Stable as grayscale: #8b8b8bInversion as grayscale: #ccccccStrong inversion as grayscale: #999999#ff3d3d#ff7800#ff96ff#ccbfff#facab1#8080e6#cccccc#999999
The shipped ramp comes from the package export; the canadarasp row records its cited lineage. Neither grayscale row preserves class order, so hue, the key, readouts, and field geometry carry that meaning.Units sRGB colours and luminance-matched grayscale

The lineage, and the pivot that does not transfer

The hues descend from canadarasp, the project these Meteograms gratefully descend from: warm reds and oranges for instability, pink and lavender for the conditional middle, a tan pivot, blue for stable, greys for inversion. Two details from its source are worth keeping on the record. It fills nine lapse-rate bands where this project draws eight classes — but the extra −0.5 °C per 1,000 ft boundary paints the same colour on both sides, so there were eight visible bands all along, and their boundaries are exactly the classes these charts draw. And its colormap file states its design’s pivot in six words: “matching the background is stable” — stable air disappears into canadarasp’s blue page, and everything painted is signal. That pivot is brilliant on its own page and does not transfer: these charts sit on paper, so this palette keeps stable air pale rather than invisible, and owes no debt to a background it does not have.

Measured, not eyeballed

The ramp’s direct ancestor is the canadarasp palette itself — the eight fills its lapse-rate panel paints, straight from windgram-continental-colormap.ncl — and it carried a defect nobody saw: its two conditional purples (#ff96ff, #ccbfff) sat at adjacent ΔE 11.8 to a normal eye, and 1.8 under deuteranopia, where roughly 6 is the floor for telling adjacent fills apart and 1.8 is one colour. The most common form of colour-vision deficiency erased the boundary between conditional-strong and conditional instability — a boundary the chart exists to draw. The defect lived below the threshold of design-by-eye and above the threshold of measurement, which is the process lesson: once a palette is measurable, “looks right” stops being the acceptance test.

The shipped default, STABILITY_TOKEN_DEFAULTS, is that ancestry re-set into the pale register — the hue architecture kept, every one of the eight values moved (per-class ΔE 6.8 to 14.8 from its ancestor). The failing purples are pulled apart (ΔE 1.8 to 7.0 under deuteranopia), the grey tail is internally light-ordered from stable through strong inversion, and every adjacent pair now clears the 6.0 colour-vision floor under both simulated deficiencies — adjacent-pair ΔE minima of 7.8 normal, 7.8 protanopic, 7.0 deuteranopic. The repairs were found the same way the defect was — a validator over OKLab with CVD simulation — and every number above re-runs from the two named sources with the same math the figures build with.

Ancestor provenance: canadarasp’s windgram-continental.ncl paints its lapse panel with colormap indices 11, 10, 7, 8, 3, 2, 13, 14 of windgram-continental-colormap.ncl — most unstable first, the index-2 purple-blue repeated across the invisible −0.5 boundary.

Check the boundaries yourself below — bars for a normal eye, dots for simulated deuteranopia, both palettes side by side.

Adjacent boundaries in the pale register

The shipped field stays pale behind chart content while each adjacent class clears the colour-vision floor.

shipped default: adjacent pairs 12.2, 17.9, 11.1, 11.2, 19.5, 10.0, 7.8 (worst 7.8 normal, 7.0 deuteranopia, 7.8 protanopia). canadarasp: adjacent pairs 11.3, 26.4, 11.8, 13.6, 30.1, 24.9, 16.2 (worst 11.3 normal, 1.8 deuteranopia, 7.3 protanopia).

Adjacent-pair colour difference of the default stability ramp and the historical canadarasp palette, under normal vision and simulated deuteranopia Seven adjacent class pairs, from very unstable through strong inversion, left to right.shipped default: adjacent pairs 12.2, 17.9, 11.1, 11.2, 19.5, 10.0, 7.8 (worst 7.8 normal, 7.0 deuteranopia, 7.8 protanopia). canadarasp: adjacent pairs 11.3, 26.4, 11.8, 13.6, 30.1, 24.9, 16.2 (worst 11.3 normal, 1.8 deuteranopia, 7.3 protanopia). The validator's normal-vision adjacent-pair target of 8 is marked; its floor under simulated colour-vision deficiency is 6.adjacent ΔEshipped defaultcanadaraspdeuteranopia shipped default — Very unstable to Unstable: ΔE 12.2 normal, 9.0 deuteranopia, 12.8 protanopia shipped default — Very unstable to Unstable under deuteranopia: ΔE 9.0 shipped default — Unstable to Conditional · strong: ΔE 17.9 normal, 17.3 deuteranopia, 18.6 protanopia shipped default — Unstable to Conditional · strong under deuteranopia: ΔE 17.3 shipped default — Conditional · strong to Conditional: ΔE 11.1 normal, 7.0 deuteranopia, 10.6 protanopia shipped default — Conditional · strong to Conditional under deuteranopia: ΔE 7.0 shipped default — Conditional to Near neutral: ΔE 11.2 normal, 11.7 deuteranopia, 10.4 protanopia shipped default — Conditional to Near neutral under deuteranopia: ΔE 11.7 shipped default — Near neutral to Stable: ΔE 19.5 normal, 20.4 deuteranopia, 16.3 protanopia shipped default — Near neutral to Stable under deuteranopia: ΔE 20.4 shipped default — Stable to Inversion: ΔE 10.0 normal, 10.5 deuteranopia, 9.3 protanopia shipped default — Stable to Inversion under deuteranopia: ΔE 10.5 shipped default — Inversion to Strong inversion: ΔE 7.8 normal, 7.8 deuteranopia, 7.8 protanopia shipped default — Inversion to Strong inversion under deuteranopia: ΔE 7.8 7.8 canadarasp — Very unstable to Unstable: ΔE 11.3 normal, 7.0 deuteranopia, 11.8 protanopia canadarasp — Very unstable to Unstable under deuteranopia: ΔE 7.0 11.3 canadarasp — Unstable to Conditional · strong: ΔE 26.4 normal, 25.1 deuteranopia, 28.0 protanopia canadarasp — Unstable to Conditional · strong under deuteranopia: ΔE 25.1 canadarasp — Conditional · strong to Conditional: ΔE 11.8 normal, 1.8 deuteranopia, 7.3 protanopia canadarasp — Conditional · strong to Conditional under deuteranopia: ΔE 1.8 1.8 canadarasp — Conditional to Near neutral: ΔE 13.6 normal, 14.2 deuteranopia, 12.5 protanopia canadarasp — Conditional to Near neutral under deuteranopia: ΔE 14.2 canadarasp — Near neutral to Stable: ΔE 30.1 normal, 32.0 deuteranopia, 27.4 protanopia canadarasp — Near neutral to Stable under deuteranopia: ΔE 32.0 canadarasp — Stable to Inversion: ΔE 24.9 normal, 26.2 deuteranopia, 24.3 protanopia canadarasp — Stable to Inversion under deuteranopia: ΔE 26.2 canadarasp — Inversion to Strong inversion: ΔE 16.2 normal, 16.2 deuteranopia, 16.2 protanopia canadarasp — Inversion to Strong inversion under deuteranopia: ΔE 16.2 ΔE 8 · adjacent-pair target (normal vision; CVD floor 6)VeryunstableUnstableConditionalstrongConditionalNearneutralStableInversionStronginversion
The shipped default repairs its ancestor's deuteranopia-blind purple boundary while staying in a pale background register. Bars show normal-vision ΔE; dots show simulated deuteranopia.Units OKLab ΔE ×100

One look

The package ships this palette and no theme catalogue. Anything a consumer legitimately wants different is a token: the eight --meteo-gram-stab-* custom properties restyle the field without forking the renderer, which is precisely how the palette’s own ancestor was built and tuned. Defaults are argued on claims anyone can re-run — figure-ground first, worst-reader floors on the boundaries the register can hold, and the residue documented rather than pretended away.