Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type Network proposal for a system of parametric and optical axes has been submitted. #22

Open
PeterCon opened this issue Dec 18, 2017 · 60 comments

Comments

@PeterCon
Copy link

Type Network has submitted a proposal for a system of 8 parametric axes, along with three optical axes. Use this thread for general discussion of the proposal overall. Please create separate issues for specific details or discussion of specific axes within this proposal.

The parametric axes are:

  • X Opaque, X Transparent, Y Opaque, Y Transparent
  • Y Transparent Ascender, Y Transparent Descender, Y Transparent Uppercase, Y Transparent Lowercase

The optical axes are:

  • Grade
  • Per-Mille Weight
  • Per-Mille Width

See the proposal overview here:
Type Network Parametric Axes Proposal Overview

@tiroj
Copy link
Collaborator

tiroj commented Dec 18, 2017

I am confused about the meaning of transparent/opaque in these proposals. I had initially presumed that opaque referred to glyph stems, bowls, terminals, etc. — i.e. 'black' in a conventional b/w text display — and transparent referred to the space around and within the glyphs — i.e. 'white'.

So I was confused to see an axis illustrated with a variation in the height of the ascender stem labeled as 'Y Transparent Ascender', because I would expect that to be 'Y Opaque Ascender', based on the observation that it is the opaque/black feature of the glyph that is changing. The illustration does indicate, using arrows, that the scale of the axis is relative to the baseline, and hence is measurable across adjacent transparent/white space, rather than as a relative distance from the default ascender height, but it still seems confusing to me when, elsewhere in the proposals, transparent axes are affecting e.g. advance width independent of x stem weight. Indeed, it seems to me that having an actual Y Transparent Ascender axis that affects vertical ascent space independent of the height of the glyph ascender, might be a useful thing at some point, and reserving the term Opaque for axes that adjust stems, bowls, etc. would be a good thing.


Erratum: in Y Transparent proposal the overview line reads

Overview: This describes a proposed X Transparent Ascender axis to vary the height of ascenders.

Should be Y Transparent Ascender
[Not checked other proposals for similar.]

@PeterCon
Copy link
Author

I fixed the "X Transparent Ascender" typo.

@PeterCon
Copy link
Author

The use of "opaque" and "transparent" for xopq, yopq, xtra and ytra are new, but once explained the meaning seems clear. And I don't have any better alternative terms to offer.

But wrt the other 4 parametric axes (ytas, ytde, ytuc, ytlc)... While there's a terminological pattern, the use of "transparent" is less clear, as John points out. It's not clear to me that "Y Transparent Ascender", etc. are better than the existing conventional terms, "Ascender", "Descender", "Cap Height", "X Height".

@davelab6
Copy link
Contributor

davelab6 commented Dec 19, 2017

The 'Y Transparent Lower Case' is not a 'true' x-height axis; to have one of those, you would need to combine changes in YTLC and other axes.

By loading Axis Praxis in 2 windows, you can compare eg Dunbar's x-height axis with Amstelvar's YTLC; clearly in Dunbar there are changes in X and Y, opaque and transparent shapes:

kapture 2017-12-18 at 21 42 15

Similarly for the all the others; eg, a YTAS axis is not the only thing you may want to adjust in a 'true Ascender' axis.

@davelab6
Copy link
Contributor

I was confused to see an axis illustrated with a variation in the height of the ascender stem labeled as 'Y Transparent Ascender', because I would expect that to be 'Y Opaque Ascender', based on the observation that it is the opaque/black feature of the glyph that is changing.

For me, the label as proposed makes sense, because I'm thinking from the perspective of a user who is adjusting blocks of text. When I change the YTAS axis, the amount of transparent area in the text block increases.

@tiroj
Copy link
Collaborator

tiroj commented Dec 19, 2017

When I change the YTAS axis, the amount of transparent area in the text block increases.

I'm having trouble unpicking that. What the YTAS axis is illustrated as doing is increasing or decreasing the ascender height. So yes, when this is applied to a block of text one visible effect of that will be a decrease or increase in white space between the lines, but only as a consequence of the adjustment of the opaque ascender strokes. That's what the axis is actually affecting, and I think it makes way more sense for names of parametric axes for glyph manipulation to reflect what the axes do to glyphs, not what secondary effect they have at a higher level where, remember, they may interact with other higher level layout functions (for example, the axis that adjusts ascender height could be linked to a linespacing function, such that changes to the leading would allow ascenders to grow or make them shrink such that the amount of white space relative to ascender height in a block of text actually stayed constant).

Further, the illustration of YTAS provided with the proposal clearly labels the tallest ascender height as maximum, and the shortest as minimum, meaning that what is being measured on the axis scale is the ascender height and not a secondary amount of visual white space around that ascender, which would actually be inverse to the ascender min/max height, i.e. shorter ascender = greater white space.

@tiroj
Copy link
Collaborator

tiroj commented Dec 20, 2017

Giving this some more thought during the ten hours in which the power was out today, I can now understand the logic in defining the topographical height parameters as transparent rather than opaque. In the same way that the 'Y Transparent' axis is to height what the 'X transparent' axis is to width, so the four topographical axes are dealing with adjustment across transparent distance. Got it.

@dberlow
Copy link

dberlow commented Dec 20, 2017

Great point. If you can suggest a better way to illustrate or explain further in text, let us know.

@Lorp
Copy link

Lorp commented Dec 20, 2017

For YTAS, anglocentric thinking and the literal meaning of ‘ascender’ point us to topologically degenerate glyphs. βδζθξ and ß are much more useful!

@PeterCon
Copy link
Author

John said,

I can now understand the logic in defining the topographical height parameters as transparent rather than opaque.

I'm still puzzled. I see Dave C's comment wrt ytas:

When I change the YTAS axis, the amount of transparent area in the text block increases.

OK, I get that. But what about ytuc and ytlc? When you increase either of those, the transparent area in a text block will decrease, no?

@tiroj
Copy link
Collaborator

tiroj commented Dec 20, 2017

Ignore Dave C's comment. :)

The key to understanding the transparent aspect of these axes is to compare them with the 'X Transparent' axis: they involve changes to the position of features across transparent distance. As @Lorp suggested, our Latin perspective is confused because most of our ascenders and descenders are straight, and hence we tend to think in terms of the stem getting longer, whereas what's actually happening conceptually in these axes is that the ends of the stems are moving up and down across transparent space. It is easier to visualise the comparison of these axes to 'X Transparent' if one considers ascenders/descenders with bowls, or in the case of YTUC a letter like O or for YTLC the o. What we're dealing with is topographical height adjustments of common glyph features categorised by vertical alignment zones, comparable to width adjustments and, hence, transparent not opaque.


Something I'm still unsure of:

If a font has separate parametric axes for the height of topographical features: cap height, ascender height, x-height*, descender depth, what is the expected interaction with the overall 'Y Transparent' axis?

  • I'm leaving aside, for now, Dave C's previous observation about x-height optical axis independent of YTLC.

@PeterCon
Copy link
Author

If that's how I should think of "transparent", then is that just a synonym for the design grid itself? That seems different from the usage in the case of the xtra and ytra axes, in which it really is the size of the white space that is changing.

So, that kind of brings me back to why "Y Transparent Ascender" instead of just "Ascender" --- though Dave gave a reasonable reply to that. But what about 'pasc' / "Parametric Ascender", etc.?

@sberlow
Copy link
Contributor

sberlow commented Dec 20, 2017

The size of the transparent space is changing, regardless of white or black. :)

It may be easier to conceptualize with a two story g, but the same holds true for, all ascenders and descenders as the transparent space is being changed in the y direction.

ytlc
ytlc

ytde
ytde

ytra
ytra

@dberlow
Copy link

dberlow commented Dec 20, 2017 via email

@dberlow
Copy link

dberlow commented Dec 20, 2017 via email

@tiroj
Copy link
Collaborator

tiroj commented Dec 20, 2017

Peter, I'm finding it helpful to think of the transparent axes as involving distance and the opaque axes as involving thickness. I agree that when talking about a straight stem ascender it is initially confusing, because the opaque stem is increasing or descreasing in height, but this is a secondary effect of what is actually happening in the axis, which is that the terminal of the ascender is travelling across a transparent distance. As Sam illustrates, it is easier to visualise the generalised model of the axes using a glyph with counter space (for ascender, ß would be a good Latin example).

@PeterCon
Copy link
Author

OK. But consider that it's taken you 10 hours of power outage after having months to ponder these axes generally for it to make sense to you, and taken 5 people and a bunch of discussion and demo animations to explain it to me. How readily will the average person reading the descriptions of these tags in the registry wrap their head around what "Y Transparent Ascender" means?

@be5invis
Copy link
Contributor

@Lorp Interesting. However a better and more elegant solution would be a new table (or fvar extension) that "adds another level of indirection. I've sent my ideas to @PeterCon, it is mainly a further extension of Rob's XVAR.

@be5invis
Copy link
Contributor

image

@dberlow
Copy link

dberlow commented Jan 13, 2018

Right now this thread has a lot of different “issues”, so I am going to have to skip some, which does not mean I don’t like them.

Where is xvar documented, please? I “Searched” this whole site’s comments and couldn’t even find the reference existing in this thread.

Lorp
I am rewriting the Amstelvar Alpha documentation to make some things more clear.

be5invis
Reducing both "width" and "X-opaque" to the minimum in Amstelvar Alpha, is, first of all what I would call an “extra-preferential” setting for any known user in our market today. It essentially applies all of two axes wdth and xopq x deltas twice, Itself is not inherently bad, just extra-preferential for this var.

This particular ugly may not seem valuable, but there are a couple of typographic treatments that can’t be accomplished today at all, without the combined or repeated application of deltas. The space to control them in has been long included in our proposal. Becoming infra-preferential could mean, e.g. multiple deltas become a perfectly normal typographic treatment for dealing with “user distance from a virtual page”, a treatment that the width and weight axes are not able to provide entirely.

So whether parametric axes co-exist with “Optical” (or any blended axes), is in my opinion a question of how. We could start a proposal about "Dependent Axes", but I’m in favor of a more comprehensive collection of axes, their values and relationships, and how these relate across scripts, classes of styles, and the typography they are intended to effect. But, before any of that, I put a clear and unambiguous per script, definition, via parametric axes, of the registered axes, wdth and wght, ahead of it all.

Without that I’m afraid, any sort of objective organization of dependencies ends up subjective.

@be5invis
Copy link
Contributor

@dberlow The XVAR proposal is written by @robmck-ms. You could ask a copy from him. Currently he is reviewing my ZVAR draft, which is a further extension of XVAR and solves two more questions:

  1. Co-existence of Optical and Parametric Axes;
  2. Language-dependent axes re-mapping (which is related to Proposal for a "height" axis ('hght') has been submitted. Please discuss in this thread. #14).

@dberlow
Copy link

dberlow commented Jan 13, 2018 via email

@tiroj
Copy link
Collaborator

tiroj commented Jan 15, 2018

@dberlow The axis registration proposal process is public. Proposals for new OT tables or other aspects of the format architecture are not public unless the contributors choose to make them so.

@davelab6
Copy link
Contributor

davelab6 commented Jan 15, 2018 via email

@dberlow
Copy link

dberlow commented Jan 15, 2018 via email

@dberlow
Copy link

dberlow commented May 22, 2018

John Hudson has made assertions here and there, over a period of a year or more, that use of the base and mvar tables can somehow replace significant chunks of functionity of axes in our proposed framework. With the future of independent interoperable alignments of world scripts hanging in the balance, he is invited to provide demonstrations or something concrete, unless that is secretly being developed, patented or something else, elsewhere.

Thanks.

@tiroj
Copy link
Collaborator

tiroj commented May 22, 2018

I'm not sure I have made such assertions, at least with regard to 'functionality of axes in your proposed framework'.

With regard to the BASE table, I've noted that there's been discussion of extending the table to allow for script and language-specific vertical metrics since at least April 2014, and that there seems to be some more serious interest in the idea recently.

With regard to the mvar table, I've not said much of anything about it at all, other than to point out in my recent TYPO Labs talk that the 'masc' and 'mdsc' prototyped axes that I demonstrated — something concrete? — would rely on software doing the opposite of what the mvar table would typically involve, i.e. the software environment telling the font how much space is available rather than the font telling the software environment what its metrics are.

I'm not sure how either of these observations relate to your proposed framework, except in the sense that OT variations axes in general have implications for software beyond the fonts themselves, and no one I've talked to seems to have a good sense of how to move from spec'ing and demo'ing axes in fonts and describing possible frameworks to getting buy-in from software makers.

@dberlow
Copy link

dberlow commented May 28, 2018

Really.
http://typedrawers.com/discussion/2583/mvar-fonts

"I'm not sure how either of these observations relate to your proposed framework"

I am. Good luck;)

@davelab6
Copy link
Contributor

davelab6 commented Jun 29, 2018

The idea of the parametric axes as proposed here is that there are 2 kinds of axes - Parametric and Blended - that work together as a system.

In the most simple case, a Blended axis has 2 min and max instances that form a straight line axis, and each are design space locations that can be found by dialing in a set of several Parametric axes.

In a more complex case, there are 3 or more instance locations that form a path for the axis to travel along, rather than a straight line - using the 'avar' table.

As I understand it, currently, to create a Blended axis, those instance locations must be 'instantiated' as new sets of gvar deltas, so that they can be arranged as axes in the fvar table.

If these instantiated locations are unmodified, this just bloats the font filesize because excess gvar data is stored in the font, which could be calculated by the variable font interpolator in the rendering system. I have considered that a filesize optimization.

However, there is another aspect to this, that as a user travels along a Blended axis, they are in effect adjusting the "parent" Parametric axes' values.

Concretely, in Amstelvar, if you compare the Default design and the Blended "Optical Size" axis' "min" instance design, you can see that the "x transparency" is smaller in the default than in the opsz-min; that the design gets wider because its counterforms get wider.

Is it possible to make a OpenType 1.8.2 font, where that relationship between axes is expressed?

I believe it is not.

I would be grateful if those familiar with the spec could confirm this :)

(There seem to be two TypeDrawers threads where this was discussed: http://typedrawers.com/discussion/comment/35915/#Comment_35915 and http://typedrawers.com/discussion/comment/35915/#Comment_35915)

@tiroj
Copy link
Collaborator

tiroj commented Jun 30, 2018

Is it possible to make a OpenType 1.8.2 font, where that relationship between axes is expressed?
I believe it is not.

I believe you're right.

This is what the various synthetic/virtual axis concepts such as XVAR seek to address, and why I think the delay in selecting, defining, and standardising one of those concepts it is a bottleneck for development of interesting approaches to building variable fonts, and one of the reasons we seem to be in a holding position on registering new axes.

@davelab6
Copy link
Contributor

davelab6 commented Jun 30, 2018 via email

@behdad
Copy link
Collaborator

behdad commented Jun 30, 2018

@be5invis can you send me your ZVAR proposal please?

@behdad
Copy link
Collaborator

behdad commented Jun 30, 2018

It is a great pity that no one is engaging on this

That's not how progress is made (pity). :)

@davelab6
Copy link
Contributor

davelab6 commented Jun 30, 2018 via email

@behdad
Copy link
Collaborator

behdad commented Jun 30, 2018

Correct.

@dberlow
Copy link

dberlow commented Jul 1, 2018

I feel that it is something short of ideal when a variable font is permitted to have wrong values and precludes permitting having the right values. That may be the right solution for tech politicians, but not for users.

@dberlow
Copy link

dberlow commented Jul 2, 2018 via email

@be5invis
Copy link
Contributor

be5invis commented Jul 2, 2018

@davelab6

This is an early draft that only describes the mapping merhcnism and purposed STAT extension.


OpenType Extension: ZVAR table

Microsoft, January 2018

This document describes a proposed new Axes Variations (ZVAR) table that provides variation data to allow non-linear variation across a font’s variation space with inter-axis effects, and hiding parametric axes behind the optical axes, and provide language-dependent and layout-dependent axes mappings for multiple-language fonts.

Background

Optical versus Parametric

Type Networks has purposed a set of parametric axes, however how should they interact with existing optical axes, is still unknown. In their current implementation, their example font is provided with both parametric and optical axes provided, however manipulating them simultaneously would result a broken result.

Layout-dependent axes remapping

The current fvar definition could have problems when dealing with fonts covering multiple, unrelated scripts, like a typical Japanese font, which convers Latin glyphs and Ideographic glyphs. When a Japanese font is used in vertical layout, the Latin characters should be rotated by 90° clockwise, while ideographs are kept upright. Therefore, if the font provides width variation (wdth axes), then the following situation would took place:

WDTH problem

The wdth axis affects the Latins on their height (since they are rotated), and ideographs on their width. Such variation would lead to inconsistency when the text is layout vertically.

Therefore we need some mechanism that "swaps" the width and height axis for a certain scope of glyphs (like ideographs, if the "width" is defined by the dimension on the line direction) only in vertical writing direction.

Non-linear axes mapping

-- TBD --

Overview

The main idea of ZVAR table is "another layer of indirection". A ZVAR table links the User Axes defined in STAT table, to fvar design axes set, using various functions called Mappers. In a ZVAR table there could be multiple Mappers, and every one of them are limited to one specific layout mode.

A ZVAR table should always co-exist with a STAT table, and should never co-exist with avar tables. A proper implementation should handle these cases.

STAT table modifications

Style attributes header:

Type Name Description
UINT16 majorVersion Major version number of the style attributes table — set to 1.
uint16 minorVersion Minor version number of the style attributes table — set to 3.
uint16 designAxisSize The size in bytes of each axis record.
uint16 designAxisCount The number of design axis records. In a font with an fvar table and without a ZVAR table, this value must be greater than or equal to the axisCount value in the fvar table. In all fonts, must be greater than zero if axisValueCount is greater than zero.
Offset32 designAxesOffset Offset in bytes from the beginning of the STAT table to the start of the design axes array. If designAxisCount is zero, set to zero; if designAxisCount is greater than zero, must be greater than zero.
uint16 axisValueCount The number of axis value tables.
Offset32 offsetToAxisValueOffsets Offset in bytes from the beginning of the STAT table to the start of the design axes value offsets array. If axisValueCount is zero, set to zero; if axisValueCount is greater than zero, must be greater than zero.
uint16 elidedFallbackNameID Name ID used as fallback when projection of names into a particular font model produces a subfamily name containing only elidable elements.

AxisRecord:

Type Name Description
Tag axisTag A tag identifying the axis of design variation.
UINT16 axisNameID The name ID for entries in the 'name' table that provide a display string for this axis.
UINT16 axisOrdering A value that applications can use to determine primary sorting of face names, or for ordering of descriptors when composing family or face names.
------ ------------ The following fields must be present if ZVAR table presents.
UINT16 flags Axis qualifiers — see fvar.

Table Format

Terminology

  • User Axis (pl. User Axes): An axis exposed to users and STAT table. The tag, name, range of User Axes is defined in STAT table.

  • Design Axis (pl. Design Axes): The existing axes set defined in fvar table. In a font containing a ZVAR table, all the design axes should be marked as hidden.

  • Mapper: A mathematical function defined in ZVAR table to map User Axes values to Design Axes values. It is defined by multiple Formulae, and each Formula is used to produce the value for one Design Axis.

  • Formula: A mathematical function defined in ZVAR table to map User Axes values to one Fixed number, which would be used by one Design Axis.

    The output of all forumlae are not normalized. They should be further normalized using the min/default/max values defined in fvar table.

Root Structure — ZVAR table

The ZVAR table as the following format.

ZVAR Table (ZVARTable)

Type Name Description
UINT16 majorVersion Table major version - set to 1.
UINT16 minorVersion Table minor version - set to 0.
UINT16 numberOfFvarAxes Number of design axes. Must equal to designAxisCount in fvar table.
UINT16 numberOfUserAxes Number of user axes. Must equal to designAxisCount in STAT table.
UINT16 numberOfMappers Number of mappers. Must greater than zero.
Offset32<Mapper> mappers[numberOfMappers] The mapper array.

Mappers

A mapper defines a function that maps the value array of user axes (typed as Fixed[numberOfUserAxes]) to the value array of design axes (typed as Fixed[numberOfFvarAxes]), used in a specific layout mode (like horizontal / vertical layout).

A mapper contains an array of formulae, each formula maps the non-normalized user axes value array to one Fixed value, representing the non-normalized value of each design axis. The format of each formula is specified by a formulaType field.

Mapper Record (Mapper)

V2 Notes: The scriptTag and languageTag is unnecessary since we could use locl features to being axes re-mapping by using different glyphs. Therefore these fields are removed. layoutModeTag is kept to handle layout-dependent axes remapping.

Type Name Description
Tag layoutModeTag Currently only DFLT, hori and vert are valid.
Offset32<Formula> formulae[numberOfFvarAxes] List of mapping formulae.
int scoreMapper (const Tag layout, const mapper* mapper) {
    int result = 0;
    if (mapper->layoutModeTag == layout) {
        result += 2;
    } else if(mapper->layoutModeTag == 'DFLT') {
        result += 1;
    }
    return result;
}

Fixed* evalZvar (const ZVARTable* zvar, const FVARTable* fvar, const Fixed* vals,
                 const Tag layout) {
    Fixed *results = new Fixed[zvar->numberOfFvarAxes];
    for (UINT16 j = 0; j < fvar->axisCount; j++) {
        results[j] = fvar->axes[j].defaultValue;
    }
    int optimalMapperScore = 0;
    Mapper* optimalMapper = &zvar->mappers[0];
    for (UINT16 j = 0; j < zvar->numberOfMappers; j++) {
        int mapperScore = scoreMapper(layout, &zvar->mappers[j]);
        if(mapperScore > optimalMapperScore) {
            optimalMapperScore = mapperScore;
            optimalMapper = &zvar->mappers[j];
        }
    }
    if (optimalMapperScore > 0) {
        for (UINT16 j = 0; j < fvar->axisCount; j++) {
            results[j] = evalFormula(vals, &optimalMapper->formulae[j]);
        }
    }
    return results;
}

Formula (Formula)

Type Name Description
UINT8 formulaType Type of this forumla.
Formula<formulaType> formulaBody Contents of this formula.

Evaluating one formula providing a user is value list is defined as:

Fixed evalFormula (const Fixed* vals, const Formula* form) {
    return evalFormula[form->formulaType](vals, &form->body);
}

Formula type 0 (Copy mapping, Formula<0>)

This type of formula copys a non-normalized user axis value to a design axis, as its non-normalized value.

Type Name Description
UINT16 axisIndex Index of user axis.

Evaluating one formula providing a user is value list is defined as:

Fixed evalFormula[0](const Fixed* vals, const Formula<0>* form) {
    return result[form->axisIndex];
}

Formula type 1 (Formula<1>)

Formula Type 1 contains a constant term and multiple non-constant terms. Each non-constant term is a product of tent-shaped functions, applied to various User Axes. The values of user axes are also non-normalized.

Type Name Description
Fixed constantTerm Constant term of the formula.
UINT16 termCount Number of non-constant terms.
Formula1Term terms[termCount] Non-constant terms.

Evaluating one formula providing a user is value list is defined as:

Fixed evalFormula[1](const Fixed* vals, const Formula<1>* form) {
    Fixed result = form->constantTerm;
    for (UINT16 j = 0; j < form->termCount; j++) {
        result += weightTerm(vals, &form->terms[j]);
    }
    return result;
}

Format type 1 -- Term (Formula1Term)

Type Name Description
UINT16 factorCount Quantity of factors.
Formula1Factor factors[factorCount] Factors

Evaluating one term providing a user axis value list is defined as:

Fixed evalTerm (const Fixed* vals, const Formula1Term* term) {
    Fixed result = 1;
    for (UINT16 j = 0; j < term->factorCount; j++) {
        const Formula1Factor *factor = &term->factors[j]
        result *= weightFactor(vals[factor->axisIndex], factor);
    }
    return result;
}

Format type 1 -- Factor (Formula1Factor)

Type Name Description
UINT16 axisIndex Tag of the axis for this factor.
Fixed coefficient Coefficient.
Fixed minValue Min parameter of the Tent function.
Fixed peakValue Peak parameter of the Tent function.
Fixed maxValue Max parameter of the Tent function.

The factor function is defined as:

Fixed weightFactor (const Fixed val, const Formula1Factor* factor) {
    if (!factor->power) return factor->coefficient;
    const Fixed tentVal = tent(val, factor->min, factor->peak, factor->max);
    return factor->coefficient * pow(tentVal, factor.power);
}

Fixed tent (const Fixed val,
            const Fixed min, const Fixed peak, const Fixed max) {
    if (min > peak || peak > max || min >= max) { return 1; } // ignore this factor
    if (val == peak) { return 1; }                            // weight being 1
    if (val <= min || val >= max) { return 0; }
    if (val < peak) { return (val - min) / (peak - min); }
    if (val > peak) { return (max - val) / (max - peak); }
    return return 1;
}

@davelab6
Copy link
Contributor

@be5invis, thanks for posting that! I believe this does exactly what @dberlow wants, in terms of allowing his "blended" and your "user" axes to map to a set of his "parametric" or your "design" axes.

So please accept my apologies for erasing your contribution, when I earlier said no one had engaged on this - clearly you have! :)

But, to @behdad's point, I am not sure how progress can actually be made, in advancing your proposal any further... Perhaps a demonstration implementation could be done in freetype?

@dberlow wrote,

I feel that it is something short of ideal when a variable font is permitted to have wrong values and precludes permitting having the right values. That may be the right solution for tech politicians, but not for users.

I agree that the current spec is coming up short for type designers who want to offer users the full power that variation technology promises, and looking over www.v-fonts.com I see almost all the designs are woefully limited in their number and range of axes. @jensimmons had a great tweet about this:

Typesetting using variable fonts for the last few weeks… interesting. I haven’t yet been able to create the kind of work I imagined I would. The fonts aren’t flexible enough yet. It’s as if the font makers are still too afraid to hand over control. I’m stuck inside their limits.

However, Amstelvar Alpha has been publicly available for some 18 months now, and the way it has always worked is what the current spec allows.

Clearly there are two ways to deal with this: Change the spec, or, accept the spec - and work around those limitations. It seems clearly to me that the latter must come before the former.

So, perhaps the first step in finding acceptance with the current spec is to have the parametric axes expressly understood by end users, as "override" or "booster" or "turbo" axes; seeing their axis values as "relative" values to the "actual" values - the true measures - of the type attributes which the axes modify.

@dberlow also wrote,

Last question. A stat table may be included in the Type styles of a family that is not a variable font. So, if Amstelvar was not a variable font, and it only had 3,650,128 font styles, each in its own font file, instead of one variable font, could each one have a stat table with valid parametric and blended axes values, or do the stat tables of discrete styles need to be maimed by the same incorrect parametric values as variable font is?

My understanding of the spec is that no, each one could not have a stat table with parametric and blended axes values David considers valid - because the parametric axes are "turbo" axes.

With that understanding, something similar to the Angular/React "shadow DOM" can be implemented (above the font rendering library layer, at the UI layer) which tracks when any axis changes what the "actual" values of each attribute become. It can then do the arithmetic to get the right answer to the sums that @dberlow envisions as programming to create superior typography.

For example, if there is a "bank of sliders" UI, as in the current axis-praxis website on the right, then this "shadow mutation engine" can regulate the sliders into a "safe space". What I mean by that is, as the value of the (blended/user) "Optical Size" axis increases, thus increasing "Y Transparency (YTRA)," the travel of the YTRA axis slider is reduced, preventing users from increasing YTRA so much that the stroke disappears or even becomes negated. On the other hand, as "Optical Size" reduces down to 6pt, and "Y Transparency (YTRA)" is reduced to decrease stroke contrast, the travel of the YTRA axis slider is lengthened, so that users who have a reason to can increase the YTRA; perhaps they are programming a responsive rule for hi-dpi displays where 6pt text can retain more contrast while remaining as readable.

It seems to me that, for the web, a parametricAxes.js will be needed to provide a convenience API "shadow mutation engine," and each typeface will need its own amstelvar.js file with the Formulas described in the ZVAR proposal, which are the "fuel" to rev that engine and arrive at the parametric typography destination.

Since InDesign is scripted with js these days, perhaps that JS can run there too.

My understanding of PageBot is that it may be ideally suited to prototyping this kind of thing.

@Lorp
Copy link

Lorp commented Jul 11, 2018

It would be really nice to play with a web demo of Amstelvar where useful manipulation of the 4 Blended axes and 11 Parametric axes is possible. In the current spec, axes cannot be linked in this way, so these relationships must be supplied separately: I would suggest a JSON file supplied in parallel with each font. (This is effectively how Axis-Praxis works for its built-in fonts, a JSON version of fvar is supplied to the code that builds the slider UI.)

So, well in advance of any coding in FreeType, font makers would supply JSON versions of the ZVAR table, the TN parametric-blended relationships, Underware Superslider/HOI and other experimental axis relationships, publish how their spec works (ideally with a model JS implemetation), then the fonts will very soon be playable in web testers. As I mentioned in my talk at TYPO Labs 2017, an AXES table might be used to store the same JSON, which might also be handy.

In respect of Amstelvar under such a scheme, it would best be supplied with 11 functional parametric axes and 4 non-functional blended axes (i.e. the latter do nothing in a current VF implementation). This would effectively be the Amstelvar-Roman-parametric-VF.ttf (currently on GitHub) with some trivial additions for the dummy blended axes.

Regarding @davelab6’s conception of the parametric axes as "boosters", this would allow the current Amstelvar-Roman-VF.ttf (with functional Parametric and Blended axes) to be used. BTW it is helpful in this context that all of Amstelvar’s parametric axes have min < default < max, so that the axes can be used as "attenuators" as well as boosters. Of course the values on those boosted axes will be confusing, e.g. XOPQ = 50 is better thought of as “XOPQ boost” = -38 (since XOPQ default is 88). Perhaps the scales for the booster axes should be recalibrated with 0 as default. Note that after any adjustment of the Blended axes, the Parametric booster axes should immediately reset to default, as Parametric adjustment only makes sense after Blended adjustment. Yet such a “reset” mechanism is already beyond the spec, so already needs something like the JSON file already mentioned for users not to be confounded.

The idea of regulating sliders into a safe space is cool, but it seems to assume that safe spaces are cuboids. In general, as with the 2 axes of Univers, they are not.

@sannorozco
Copy link

sannorozco commented Jul 11, 2018

My two cents:

After looking at all tables, I couldn’t find any place where the VF can store the relationship between axis, without these, programmers have no idea if there’s any.
So I think if there’s a table/structure where programmers can see these relationships will be helpful to make better UIs.

I think if it’s possible to define an axis with its “children” to look at, could work. Also, to consider that Axis can have different number of children. Like any database 1:1, 1:N, N:N

`

<!-- Optical Size -->
<Axis>
  <AxisTag>opsz</AxisTag>
  <Flags>0x0</Flags>
  <MinValue>8.0</MinValue>
  <DefaultValue>12.0</DefaultValue>
  <MaxValue>144.0</MaxValue>
  <AxisNameID>256</AxisNameID>
  <Children>
  	<default>
  	<dimension name="opsz" xvalue="8" />
        <dimension name="XOPQ" xvalue="88" />
        <dimension name="XTRA" xvalue="402" />
        <dimension name="YOPQ" xvalue="62" />
        <dimension name="YTLC" xvalue="500" />
        <dimension name="YTUC" xvalue="750" />
        <dimension name="YTFG" xvalue="750" />
        <dimension name="YTDE" xvalue="-240" />
        <dimension name="YTAS" xvalue="750" />
        <dimension name="YTSE" xvalue="18" />
        <dimension name="PWHT" xvalue="88" />
        <dimension name="PWTH" xvalue="490" />
  	</default>
  	<min>
      	<dimension name="opsz" xvalue="8" />
        <dimension name="XOPQ" xvalue="88" />
        <dimension name="XTRA" xvalue="402" />
        <dimension name="YOPQ" xvalue="62" />
        <dimension name="YTLC" xvalue="500" />
        <dimension name="YTUC" xvalue="750" />
        <dimension name="YTFG" xvalue="750" />
        <dimension name="YTDE" xvalue="-240" />
        <dimension name="YTAS" xvalue="750" />
        <dimension name="YTSE" xvalue="18" />
        <dimension name="PWHT" xvalue="88" />
        <dimension name="PWTH" xvalue="490" />
    </min>
    <max>
    	<dimension name="opsz" xvalue="144" />
        <dimension name="XOPQ" xvalue="82" />
        <dimension name="XTRA" xvalue="307" />
        <dimension name="YOPQ" xvalue="14" />
        <dimension name="YTLC" xvalue="460" />
        <dimension name="YTUC" xvalue="750" />
        <dimension name="YTFG" xvalue="750" />
        <dimension name="YTDE" xvalue="-230" />
        <dimension name="YTAS" xvalue="750" />
        <dimension name="YTSE" xvalue="18" />
        <dimension name="PWHT" xvalue="82" />
        <dimension name="PWTH" xvalue="389" />
    </max>
  </Children>
</Axis>

<!-- x opaque -->
<Axis>
  <AxisTag>XOPQ</AxisTag>
  <Flags>0x0</Flags>
  <MinValue>18.0</MinValue>
  <DefaultValue>88.0</DefaultValue>
  <MaxValue>287.0</MaxValue>
  <AxisNameID>257</AxisNameID>
  <Children>
  	<default>
        <dimension name="XOPQ" xvalue="110" />
        <dimension name="XTRA" xvalue="803" />
    </default>
    <min>
        <dimension name="XOPQ" xvalue="18" />
        <dimension name="XTRA" xvalue="796" />
    </min>
    <max>
        <dimension name="XOPQ" xvalue="287" />
        <dimension name="XTRA" xvalue="807" />
    </max>
  </Children>
</Axis>`

Then when programmers get this array, they can use whatever normalization between these ranges to make proper changes to all children axis at once.

One final thought, “Blended” are like the presets on an equalizer, where by switching between “Electronic”, “Acoustic”, “Rock”, all parameters adapt so users don’t have to each one of the sliders.

@davelab6
Copy link
Contributor

I happened to have lunch with @tiroj today in NYC.

Something John asked me, which I was indeed unable to explain adequately to our mutual satisfaction, was what parametric axes values/scales are actually measuring & representing.

As I understand it, one of the primary purposes for axes registration is interoperability; the ability to exchange one typeface for another and have each axis value remain usefully where it was.

However, if one typeface has a default xopq of 125 and another has a default of 90, because their cap H stem widths are those values when their upms are scaled/normalized to 1000 ("per mille of em"), and the first is loaded and adjusted up to be 107, then the second is swapped in, and thus adjusted down to 107, is this actually useful?

It seems that it might be, or might not be, depending on the actual typefaces involved, and since it won't always be, I'm not sure if interoperability - and thus registration - makes sense.

Moreover, given the current spec has axis orthogonality, if the first typeface is loaded and opsz is set to 48pt, and the mutation shadow engine calculates that therefore real xopq is reduced to 115, and applies an xopq axis value of -10, then the user optimizes this by making the axis value -5 and the shadow value 120, then swaps to the second typeface - what happens?

Should the shadow engine calculate the xopq of the second fonts opsz 48pt shadow value of 74, actual value -16, then "replay" the xopq operation relatively and proportionally (50% between unadjusted and adjusted values) or absolutely (to shadow value 120, thus axis value 46?)

The reason I am considering these scenarios is that, while it's clear the xopq value measures the width of stem of cap H in scale of per mille of em, it isn't clear what that actually means for perceived typographic color, because that property is an emergent one that arises out of the combined effect all of vars for a run and all runs in a text box (dtp) or element (html) and seems to be what xopq is actually representing.

Maybe I'm overthinking this 🤣

I will follow up with comments to Laurence and Santiago shortly.

@tiroj
Copy link
Collaborator

tiroj commented Jul 20, 2018

The reason I am considering these scenarios is that, while it's clear the xopq value measures the width of stem of cap H in scale of per mille of em, it isn't clear what that actually means for perceived typographic color...

Right. Presuming that control of typographic colour is a goal, which I think it should be, I'm concerned that referring to the width of vertical stem in cap H produces too many scenarios in which the referent is something that doesn't actually occur on the page or even in the script. The problem is similar to that presented by the CSS font-size-adjust property, and as in that case the only solution concept I've been able to come up with is defining an external standard for typographic colour that isn't dependent on conventional features of a particular script.

@be5invis
Copy link
Contributor

be5invis commented Jul 20, 2018

@sannorozco
The ZVAR draft does exactly what you want: parametric axes are hidden in fvar, and optic axes are in STAT. A ZVAR is used to link them.
You can create a TTC that includes another subfont which uses a different STAT and ZVAR to expose the parametric axes directly.

@dberlow
Copy link

dberlow commented Jul 20, 2018 via email

@dberlow
Copy link

dberlow commented Jul 20, 2018 via email

@Lorp
Copy link

Lorp commented Jul 25, 2018

w3c/csswg-drafts#528 (comment)

Here’s a reminder (from earlier today) that font makers are not alone in wanting to set up relationships between user-friendly axes and those already in fonts. The CSS Working Group here discusses ways that a CSS author might write (as yet unspecified) CSS, such that an author-friendly range of weights maps to a different range on the wght axis. This behaviour will help them feel in control of setting up families, like they did pre-variable, for example setting up arbitrary instances for font-weight=400 and font-weight=700.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment