axisregistry
axisregistry copied to clipboard
Add Contrast Axis
Fonts to be onboarded that have this axis:
- https://github.com/google/fonts/issues/2931
- https://github.com/google/fonts/issues/3685 (added later, uses Contrast the same way)
@yanone originally posted this at https://github.com/google/fonts/issues/4355:
I'm proposing the inclusion of a "contrast" axis (CNTR) into the axis registry. https://github.com/tallchai/akshar-type has one, that I’m currently onboarding.
tag: "CNTR"
display_name: "Contrast"
min_value: 0.0
default_value: 0.0
max_value: 100.0
precision: 1
fallback {
name: "Low"
value: 0.0
}
fallback {
name: "High"
value: 100.0
}
description:
"Stroke contrast describes the stroke width difference"
" between the thick and thin parts of a pen stroke."
" Traditionally, a Redis pen nib would yield a low contrast stroke"
" (monolinear) while a broad nib or pointed nib pen would"
" yield a high contrast stroke."
cc @m4rc1e @davelab6 @rsheeter
@rsheeter asked how this related to the opaque (YOPQ, XOPQ) parametric axes by @dberlow, and I responded:
One of the key idea of parametric axes is that they are "deconstructions" or "isolated forms", and are intended to be used in concert just as much as by themselves, to "construct" desired forms; when 2+ axes are used at once, the result is a "blending" (to use an oil painting metaphor).
Since we lack the long-promised and behdad-hasn't-delivered avar2 table, blending isn't as precise as it ought to be, limiting but not negating the utility of blending parametric axes. Therefore it is convenient to offer "pre-blended" axes - like weight, width, optical size, and grade.
So a "contrast" axis is, like grade, fine to onboard. I am happy @Yanone has been listening to our general recommendations and his proposal is already pretty solid, I think. Yet, there's a few details to confirm, as @twardoch has said in #4 - since there are already quite a few fonts out there with similar axes, we should review them and see if there are ideas worth adopting, starting with the best 4 char axis tag string :)
@twardoch originally posted this at https://github.com/google/fonts/issues/4355#issuecomment-1063256184:
The Contrast axis exists by many names already, as per https://github.com/googlefonts/axisregistry/issues/4 :
cntr: 2 fonts, CONT: 5 fonts, ctrs: 1 font, CTST: 1 font, CNTR: 10 fonts
@twardoch originally posted this at https://github.com/google/fonts/issues/4355#issuecomment-1063323845:
I think the registered range should be from -100 to 100:
min_value: -100.0 default_value: 0.0 max_value: 100.0
The universalized meaning should be something like the "dominance of the thick parts over the thin parts, expressed in percent" or the "difference between 100% and the division between the thickness of the thin parts and the thickness of the thick parts". For example if the thin parts are 30 units and the thick parts are 230 units, the division yields 13% so the CONT value should be 100%–13% = 87.
Positive values should be used if the contrast follows the traditional contrast axis of the dominant writing system, and negative values should be used if the contrast follows the reversed contrast axis of the dominant writing system.
So 0 should stand for "no contrast", 100 should stand for "thin strokes are invisible and the contrast axis is traditional", and -100 should stand for "thin strokes are invisible and the contrast axis is reversed". This way, some design could go from fully reversed contrast to fully traditional contrast.
cntr: 2 fonts,ctrs: 1 font,
These are not a valid tag as MS reserved lowercase tags, but we can consider CTRS also...
CONT: 5 fonts,CTST: 1 font,CNTR: 10 fonts
but CNTR seems a clear popularity winner on a rote basis. However, without seeing what the typefaces are, what the min/def/max are, and who made them, its hard to parse further.
For @twaroch's proposed negative range, that is an improvement over Yanone's original proposal; clearly negative contrast is "a thing."
These proposals also can deal with eg Latin + Devanagari that have 2 scripts with different (inverted) contrast traditions, which is nice.
I’ll provide examples
@tiroj said at https://github.com/google/fonts/issues/4355#issuecomment-1063424993:
The universalized meaning should be something like the "dominance of the thick parts over the thin parts, expressed in percent" or the "difference between 100% and the division between the thickness of the thin parts and the thickness of the thick parts". For example if the thin parts are 30 units and the thick parts are 230 units, the division yields 13% so the CONT value should be 100%–13% = 87.
I’m not sure that math would make a lot of sense to a font maker or user. I think I would favour the axis scale expressed as the percentage relationship of thin stroke to thick stroke. So in your example the value would be 13, and the contrast approaches monolinear by increasing the thickness of the thin strokes until the value reaches 100. I think most font makers will think of increasing contrast in terms of making some parts thinner, rather than in terms of making some parts thicker, and the relationship between the value and the glyph appearance is easier if thinner = smaller value.
-100 is good. Reverse contrast is definitely a thing :) Would a third fallback needed called "Reversed" for -100?
Yes min def max if min is not def
I think most font makers will think of increasing contrast in terms of making some parts thinner
Yes, but the user values are not for font makers, but for users. The dominating concept in the language is that you have "no contrast" or "little contrast" (and for it the logic dictates a value close to 0), and you have "high contrast" or "lots of contrast" (so for simplicity, you’d expect something akin to a percentage, with a hypothetical "full contrast" being something around 100%). Basically, the percentage expresses "the amount of contrast" — which is a natural interpretation of what the term "contrast" means.
My proposed "formula" (1 – thin/thick, expressed as percentage) is compatible with the linguistic interpretation, plus it still offers a solution for universalization. And the reversed vs. traditional approach takes care of actual cases, and is world-ready.
For width, the spec says:
"Percentage of normal width is a comparitive scale that will depend on the specific items being compared. The width of a line of text very much depends on the content of the text. No specific reference string is specified here as the basis for comparisons; a font designer can choose what they consider to be representative strings assigning a 'wdth' value to a design variant. Ideally, the 'wdth' value should provide a good estimate for most strings in the target languages of how the width of the string formatted with that 'wdth' variant compares to the width of the same string when formatted with the “normal” variant."
Without avar2, it’s not possible to do width axis that is sensible across optical size, for example. Roboto Flex rightly varies much more in width in the high opsz, but varies much less in the low opsz. So to pick the right width scale, the vendor needs to make some compromise.
The same would be true for contrast. To provide a contrast scale in a multi-axis font, the vendor should use the stroke thickness proportions of the instance that the vendor considers the primary use case.
It’s not sensible / possible to provide fool-proof mandate on the universal scale for contrast, but I still think it’s reasonable to provide sensible directional guidance.
Then the software engineers developed wording for the OT spec, they originally always thought about some neat numeric stuff. This was true for PANOSE, for OS/2.usWidthClass, and to some extent for the descriptions of the var axes like wdth. In case of wdth, they fortunately added some softening language, though still not enough. It’s clear that cases like "the visual scale of width changes as opsz changes" were not really considered, or perhaps were dismissed as "exotic ideas". But they’re at the core of type design.
Overall, I’m not a great friend of "universal scales" that are based on strict measuring. But on the other hand, vendors like some guidance, and contrast is common enough that some common interpretation of the numbers would be desirable — just so that the implementations don’t differ wildly. They will differ if we don’t provide guidance. So the "simple" interpretation is to go from optionally -100 via 0 to 100 and see this is just a "percentage" (0 is "low", 100 is "high") within your own design, but the slightly smarter scale is along the lines I proposed — so -100 and 100 are "objectively extreme" contrasts, while values in-between are based on simple measuring (1 – thin/thick as percentage, based on a "most representative" instance of the design, with the font vendor having freedom to pick how they choose the most representative thing).
The most representative thing does not have to be "Regular". The vendor should have some freedom there. For example a vendor may have developed a high optical size first (think Playfair Display) and if there were a contrast axis, the vendor could use that high opsz to base the scale — also because the contrast typically varies most and is largest at high opsz. And then, if the vendor adds lower opsz (as is happening with Playfair), the scale would be propagated. This is the compromise, because without avar2 it’s not really possible to do differently.
Re YOPQ and XOPQ — the parametric axes are used for synthesizing certain typographic effects by combining values on them. They’re intended for advanced users, and David Berlow’s idea is also that they ultimately may be hidden from the end-user UIs. The *OPQ axes are specifically tied to purely-vertical and purely-horizontal contrast.
The CNTR axis is intended for end-users, and provides an intuitive scale that is universal to some extent, so switching or mixing fonts at the same contrast axis value would produce comparable results. It is up to the designer to decide where exactly the typographic contrast varies — this may be horizontal strokes in some letters, vertical strokes in other letters, and diagonal strokes in yet other letters. The proposal takes into account the notion of "traditional" contrast for a given writing system.
For example, in Latin fonts, the so-called "old-style" serif fonts typically have contrast that falls diagonally. In the letter "O", the thinnest parts are in the top-left and the bottom-right "corners". "Modern" serif fonts have contrast that increases horizontally, so the thinnest parts are in the top and bottom. But in Arabic, the traditional contrast is such that the thinnest parts are on the let and right, and the thickness increases vertically. This has to do with the way calligraphers traditionally hold a flat writing tool.
If a font increases contrast in the direction that is compatible with the traditional notion of contrast for a given writing system, the CNTR axis value increases from 0 up to 100. But if the font increases contrast in the "reversed" direction, the axis value changes towards -100.
@rsheeter asked how this related to the opaque (YOPQ, XOPQ) parametric axes?
The combination of Y and X OPQ controls the thick/thin relationship of stems in all glyphs that contain a variation in that relationship. Every single part of all the letters in "HOVER" and ``craftwork" change via one or the other *OPQ. if there is any contrast anywhere in the design-space. So, first off, when @twardoch writes: “The *OPQ axes are specifically tied to purely-vertical and purely-horizontal contrast.” This is incorrect, has never been so. RobotoFlex is an example one can have looked at for proof over the past 3-4 years.
However, the *OPQs of RobotoFlex and of Amstelvar would be converted differently related to use of an axis for little changes to contrast, vs use of an axis for big changes to contrast. The difference between the intended use of GRAD and the much tweeted use of "Uniwidth" defines a parallel to this issue pretty well. A GRAD axis is intended to work well within the reasonable range of the letter spacing and Kerning pairs, i.e use in small amounts. Uniwidth tries to represent a change of wght, and so has limits on how far it can vary using only the letter spacing and Kerning pairs of the default. So Uniwidth can become typographically stupid fast, and tracking doesn't help. GRAD is there to return the wght to what was specified bif it is not displaying correctly.
*OPQ in general were developed for blending other axes, including opsz, slnt, wght and wdth, and now they hide out waiting for small changes. CTST is intended as a stand-alone axis with unlimited range that should complement and not interfere with any other axes, and universally apply to the world script.
But it's not so simple even in Latin to give a blanket answer to what the change from a pair of OPQ to one CSTS means without examples…
If CTST is accepted, for the User-Friendliness of the name, in Amstelvar:
-
YOPQ max source would be copied and renamed to CTST max.
-
YOPQ min source would be copied and renamed to CTST min.
-
The XOPQ min and max would be used in CTST instead of YOPQ, if;
a. the original contrast was reversed, or if
b. the font contained Arabic .e.g. as that script's CTST would need to use XOPQ duplicated as CTST min and max.
If CTST is accepted, in RobotoFlex:
-
YOPQ max source would be copied and renamed to CTST max, then it would be re-spaced and re-kerned, because a full range of y-stem thinning in that sans would be wrong and require re-spacing and re-kerning glyphs like "ELV", where significant change to the optical appearance of one side, has not occured on the other side.
-
YOPQ min's source would be copied and renamed to CTST min, then it would be re-spaced and re-kerned as well, or maybe even more, as more Latin users would be expected to use it.
-
The XOPQ min and max would be used again instead for the reverse contrast scripts included in a font.
I hope that's clear, and contained in there is that some scripts/styles will require changes to advance widths and kerning under the influence of contrast variations.
So, the *OPQ pair covers the universe of possible origin contrasts, and all possible changes to any relationships in contrast, truely, for all scripts, all styles, all glyphs with contrasting parts. And the intent of *OPQ use now, is to make small changes. We think this is fine as it is, for visual or programmed changes to fonts with opsz already containing the recommended contrast variations by default, but seeking tweeks.
On Thu, Mar 10, 2022 at 3:11 AM Adam Twardoch @.***> wrote:
Re YOPQ and XOPQ — the parametric axes are used for synthesizing certain typographic effects by combining values on them. They’re intended for advanced users, and David Berlow’s idea is also that they ultimately may be hidden from the end-user UIs. The *OPQ axes are specifically tied to purely-vertical and purely-horizontal contrast.
The CNTR axis is intended for end-users, and provides an intuitive scale that is universal to some extent, so switching or mixing fonts at the same contrast axis value would produce comparable results. It is up to the designer to decide where exactly the typographic contrast varies — this may be horizontal strokes in some letters, vertical strokes in other letters, and diagonal strokes in yet other letters. The proposal takes into account the notion of "traditional" contrast for a given writing system.
For example, in Latin fonts, the so-called "old-style" serif fonts typically have contrast that falls diagonally. In the letter "O", the thinnest parts are in the top-left and the bottom-right "corners". "Modern" serif fonts have contrast that increases horizontally, so the thinnest parts are in the top and bottom. But in Arabic, the traditional contrast is such that the thinnest parts are on the let and right, and the thickness increases vertically. This has to do with the way calligraphers traditionally hold a flat writing tool.
If a font increases contrast in the direction that is compatible with the traditional notion of contrast for a given writing system, the CNTR axis value increases from 0 up to 100. But if the font increases contrast in the "reversed" direction, the axis value changes towards -100.
— Reply to this email directly, view it on GitHub https://github.com/googlefonts/axisregistry/issues/3#issuecomment-1063774666, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAO5VDTYKQBWGZTSCORGPCDU7GVBRANCNFSM5QKEMDQQ . You are receiving this because you were mentioned.Message ID: @.***>
There are 3 general benefits to variable fonts, to compress, to express, to finesse.
To me there's a clear distinction between parametric opaque axes and a contrast axis; the former are to finesse and the latter is to express. Similarly as @dberlow says, grade is to finesse and uniwidth is to express.
A contrast axis blends changes in both X and Y dimensions even more than parametric opaque axes do; XOPQ mainly focuses on the X dimension and YOPQ mainly focuses on the Y dimension, their main focus is what makes them essentially parametric; a single OPQ axis would inherently not be a parametric axis, since it isn't isolating a parameter.
The benefit for end users of such a single blend is its context of use for expressivity. I don't really see this as different to expressive weight or width axes on os/2 class value ranges; ideally (perhaps gated on an avar2 table) we could have fonts built without those axes and only parametric axes and recipes to use them in concert to access the styles that are available in fonts built with os2 axes.
But for now, we have fonts without parametric axes that are pre-blended, and that's OK.
But in Arabic, the traditional contrast is such that the thinnest parts are on the let and right, and the thickness increases vertically. This has to do with the way calligraphers traditionally hold a flat writing tool.
For the sake of smart-assing, I need to correct this: Arabs and everyone else hold the pen the same way. But the Arabic broad nib reed pens were cut at an angle inverse to the Latin reed pens (or, possibly, Latin pens where cut straight). If you hold the below pen in the correct way, it produces a horizontal-emphasis stroke. I could only find pictures that show pens from underneath, so imagine it mirrored.

To add to the actual discussion, or rather, confirm what's been said:
We need -100 to 100 range for this axis, and 100 should yield a contrast axis that's the dominant one for each font’s dominant writing script.
Meaning: The contrast for Arabic and Latin is typically inverse as we've discussed, but both cases should carry positive CNTR values.
Hi, checking if there is an update on this. It's been open since a year.
My thoughts.
In calligraphic fonts, as well as any font with contrast, it is fine with me if XOPQ is the long side of the tool, YOPQ is the short side of the tool, and whatever angle that tool is held at, the marks of the form left by the short end, are YOPQ, and those left by the long side are XOPQ, and the stuff in between is in the hands of the tool holder.
Contrast is an axis where the value perplexes me because contrast is by definition two values. So while an axis can control it, its relationship of values, slider and visual effect can only be understood visually, i.e. by looking at it.
Within this issue, I have seen a handful of variable fonts so far, that just change the contrast and nothing else, and label it as either optical size or contrast.
Sorry if thi On Mar 8, 2023, at 6:34 PM, tallchai @.***> wrote:
Hi, checking if there is an update on this. It's been open since a year.
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.
In calligraphic fonts, as well as any font with contrast, it is fine with me if XOPQ is the long side of the tool, YOPQ is the short side of the tool, and whatever angle that tool is held at, the marks of the form left by the short end, are YOPQ, and those left by the long side are XOPQ, and the stuff in between is in the hands of the tool holder.
To be sure I understand correctly: are you saying that in ‘any font with contrast’ the meaning of XOPQ and YOPQ is disassociated from X,Y directionality, and instead reflects the dynamics of a notional writing tool as applied to different scripts? So ‘X’ is always whatever is conventionally heaviest, and ‘Y’ is always what is conventionally thinnest?
So, I think that @yanone and @dberlow are saying ~ the same thing, although @yanone was just talking about a new non-parametric contrast axis, and @dberlow is saying he thinks that should apply to XOPQ/YOPQ as well. The latter is also described by @tiroj above.
Personally, I agree with all of the above! 😛 I think that principle can and should apply to both a new non-parametric contrast axis being discussed in this thread, and to XOPQ/YOPQ.
So, just talking more about the new non-parametric contrast axis, I am in favor of more-or-less what has been discussed. Contrast can be thought of as percentage-based.
However, when one goes reverse, obviously there is no reason it could not exceed -100. So, my current version of an axis definition might be:
Min: -1000 (reverse contrast with 10x the thickness of what is normally the dominant stroke. “10x reverse ought to be enough for anybody!” 😛)
Default: 0 (zero) — but that means zero APPARENT contrast, which in many writing systems (including Latin and Cyrillic) is not the same as the X and Y strokes being mathematically the same thickness.
Max: 100 - means the thin stroke has completely disappeared!
In both Akshar and Science Gothic, the minimum contrast is zero, and that is also the default. One complication these two typefaces share — that I expect many “normal” fonts with this axis would share — is that as the weight goes down, the actual physical difference between the font’s minimum/default zero contrast, and the maximum contrast, also goes down! At the lightest weight, there is no difference at all.
The default of zero would work for many sans-serif typefaces, but a typical serif typeface that has this axis might never reach zero; it could well go, say, 25 to 80 or something.
The default of zero would work for many sans-serif typefaces, but a typical serif typeface that has this axis might never reach zero; it could well go, say, 25 to 80 or something.
That's describing a parametric axis, where the measured values must be correctly reflected in the axis setup.
What we're doing with the axes that go from 0 to 100 is to streamline the UX for users, obscuring technicalities. In my understanding, a value of 0 should be the lowest contrast per typeface, 100 the highest, and -100 the inverse extreme.
Given the above conversation, I propose the latest definition including an inverse fallback as confirmed by Dave above (IIUC), as we need to move this forward to onboard Science Gothic:
tag: "CNTR"
display_name: "Contrast"
min_value: -100.0
default_value: 0.0
max_value: 100.0
precision: 1
fallback {
name: "Reversed"
value: -100.0
}
fallback {
name: "Low"
value: 0.0
}
fallback {
name: "High"
value: 100.0
}
description:
"Stroke contrast describes the stroke width difference"
" between the thick and thin parts of a pen stroke."
" Traditionally, a Redis pen nib would yield a low contrast stroke"
" (monolinear) while a broad nib or pointed nib pen would"
" yield a high contrast stroke."
I think one weakness of that version is, the meaning of zero is just "whatever the particular font default is," and there won't be any consistency between fonts as to:
- what value indicates no apparent contrast?
- when in the range of values are you into reversed contrast?
- What kind of contrast would -20 be? (positive, reverse, or none?)
I do see that in my proposal, each typeface will have a different default value, and I am OK with that. But the alternative in Yanone’s version is that the meaning of the values is entirely font-specific (MUCH more than is the case with a Weight axis); I feel like that negates the point of having a common axis definition across fonts.
How is optical/perceived weight at wght 400 not font specific?
the meaning of the values is entirely font-specific ... negates the point of having a common axis definition across fonts
If this is the case could we please rethink the axis? - consistent definition across fonts is the entire point of having an axis registry at all
consistent definition across fonts is the entire point of having an axis registry at all
I think ‘consistent definition’ is not consistently defined. :)
Thinking this through...
An axis registry serves several funtions:
- Discouraging proliferation of axes with different names, tags, and definitions that do the same or substantially similar things.
- Defining standard scales for each axis that might provide user-facing controls to access a font’s variable design space.
- Providing font makers with recommended implementation guidelines for each axis.
A lot of existing variable font axes—including those registered in the OpenType specification—are font-specific. As Dave notes, there is no font-external definition of locations on the wght axis in terms of the actual weight of the design, and locations on the wdth axis are relative to a font-specific ‘normal’ width. This morning, I happen to be comparing a lot of optical size designs that, at least nominally, all target 6pt, and there is no consistency at all in the actual size, weight, width and other optical design features of these fonts (and most of them, it must be said, are rubbish for 6pt text).
There are two classes of variable font axes, which I used to refer to as parametric and optical. I’m not happy with those terms, because I think both can be misleading. So these days I tend to talk about axes as either having interoperable design scales, or only interoperable user scales. The standard wght, wdth, opsz axes have interoperable user scales, but do not have interoperable design scales. Parametric axes that are defined relative to the em have—more-or-less—interoperable design scales.
So I think the question to ask about the Contrast axis—and about any new axis—is whether you want it to have an interoperable design scale, or only an interoperable user scale. The Contrast axis, as discussed here, is an interesting case because there seems to be general agreement that 0 = no stroke weight contrast (for referemce we’re probably talking here about something like a circle or letter O), and that is something that would apply equally to a design scale and a user scale. So the debate is about how the axis extrema are defined: whether extrema of 100 and -100 relates to whatever the stroke weight contrast of a particular type design maxes out at, or is defined in some way that provides an interoperable design scale and, hence, a consistent result in a user scale, such that e.g. two fonts with Contrast location =50 would have the same amount of stroke weight contrast independent of the weight determined by wght and other axes.
That last point seems to me an important and problematic one, because even if one defines a scale that quantifies relative weight contrast between thick and thin strokes, that relative contrast can be achieved in different ways in the design space:
- by only making some strokes thinner, leaving the others at their original weight;
- by only making some strokes thicker, leaving the others at their original weight; or
- by making some strokes thinner and other strokes thicker.
So even if a user sets two fonts to Contrast location =50, and the result in both cases is that the thin strokes are half the weight of the thick strokes, the actual changes in each font relative to the optical weight determined by wght and other axes—or simply by the default instance in a font with only a Contrast axis—may be very different.
As long as you’re happy to accept that, then I think defining axis extrema in terms of relative % difference of thin to thick stroke weight does make sense, with the implication that 100/-100 implies that the thin strokes completely disappear. Which is cool.
One sensible user-facing definition would be percentage distribution in which the secondary and dominant dirrction contribute to the overall stroke thickness (in Latin script the horizontal direction would be dominant).
Contrast of 50 would mean no visible contrast.100 would be if the Latin strokes have thickness in horizontal only. 80 would be where 80 is horizonal and 20 vertical (so the contrast ratio is 4:1).
Contrast of 20 for Latin would be the reverse of 80:20 in horizontal and 80 in vertical, so the ratio is 1:4.
This way, the values could be kept within the 0..100 range.
Could also be done on a 0..1000 scale with 500 being no contrast.
Using the ratio directly is problematic because the extreme values go towards infinity and the scale isn't very linear. But the "weight percentage" I've just suggested is easily calculated and predictable.
One sensible user-facing definition would be percentage distribution in which the secondary and dominant dirrction contribute to the overall stroke thickness
After adjusting my thinking to 50 = 50/50 distribution, I can appreciate that idea. It means the explicit axis scale value always refers to the dominant stroke—which in turn implies that is always known (I can think of a few scripts in which there isn’t really a dominant stroke because they are largely monolinear, and when contrast is applied it can go any way)—, and the value of the regressive stroke is always implied.
Using the ratio directly is problematic because the extreme values go towards infinity and the scale isn't very linear. But the "weight percentage" I've just suggested is easily calculated and predictable.
Not predictable in implementation, though. See my point above about the different ways in which relative contrast can be achieved. Distribution typically implies taking something from one place and adding it to another, but I don’t think that is the case in type design, because the Contrast axis does not necessarily affect both strokes or maintain a constant overall weight. In type design, there is no conservation of mass. :)
If an O is 500 units in the horizontal and 50 in the vertical, the ratio is 10:1 (=10.0) and the weight permille is 909 (90.9%).
If it's 50 horizonal and 500 vertical, ratio is 1:10 (= 0.1), weight permille is 91 (9.1%).
Values like 91 or 909 are reasonably clear to users and kind of compatible with the wght scale.
Percent is easier than per-mille for a user scale, I think: wdth is more intuitive than wght.
And I do like the idea of reverse contrast being a negative value.