# LuaLaTeX: Smarter font selection macro for super-families

NOTE: This question is not answered yet. The only "answer" to this question from user Davislor does not answer this question, even though it has up-votes to make it look like. Please feel free to answer if you have a real solution.

Fontspec with LuaLaTeX works well for small font families, but appears cumbersome to use with super-families. A modern super-family can contain tens of fonts in Weight/Width/Slope (WWS) matrix. As an example Avenir Next has 32 fonts in one family.

Opentype font tables contain fields that can be used to accurately select a font in a super family: 1) WWS family name, 2) WWS subfamily name. So ideally, one should be able to set a family by specifying just family name, and optionally select a subfamily by just specifying subfamily name. Is there a LuaLaTeX way to do that?

Note 1): This sub family name is not always a substring of font's "full name", so you cannot do string concatenation trick and use fontspec :)

Note 2) If WWS fields are missing in the font, then the appropriate fields to resolve the font are: 1) font family name, and 2) font subfamily name. So somewhere a if-else statement will be needed.

\fontfamily{Avenir Next LT Pro}
.
.
.
Hello world {\fstyle{Ultra Light Italic} Hello world} Hello world



Here are some relevant screenshots:

• you should be able to set up a .fontspec file for the font, I think especially with the enhansed set of standard font weight names in recent releases. Apr 17 '21 at 10:11
• @DavidCarlisle That's exactly something I want to avoid, when I mention it is cumbersome. The interface proposal I have should make things as simple as selecting a font style in a WYSIWYG application like macOS Pages. The point is there should be no need to do special setup/mapping to use fonts. I would rather use these macros instead of standard \bfseries, \itshape, etc Apr 17 '21 at 10:15
• hmm luatex could presumably pick up the named weights from the font and allow \fontfamily{Avenir Next}\fontseries{Bold Condensed}\selectfont but I don't think it does currently. It probably wouldn't be too hard actually although do you know any free font example with that many variants to test on.... Apr 17 '21 at 10:20
• There are basically two issues: 1. WWS names are terrible when it comes to optical sizes. When a font has different optical sizes, they get classified as different families which makes them a pain to use. 2. Integrating this into NFSS (which is particularly important for such big families since it natively supports the idea of such font matrices) requires to interpret subfamily names which only leads to issues since many fonts mess with these names for "compatibility" with their designers favorite programs. Apr 17 '21 at 10:54
• IMO the STAT table is much more promising, but I don't have any good example families using it to play with in order to implement something there. Apr 17 '21 at 10:54

You would do this with an extensive list of FontFace= options, ideally in a .fontspec or .sty file. I don’t have that specific font to test, so I downloaded this version of Noto Serif into a subdirectory named fonts. Here is a sample:

\documentclass{article}
\usepackage{fontspec}
\usepackage{parskip}
\usepackage[paperwidth=10cm]{geometry}

\pagestyle{empty}

\defaultfontfeatures[NotoSerif]{
Path=fonts/,
Extension=.ttf,
FontFace={ul}{n}{Font={*-Thin}},
FontFace={ul}{it}{Font={*-ThinItalic}},
FontFace={el}{n}{Font={*-ExtraLight}},
FontFace={el}{it}{Font={*-ExtraLightItalic}},
FontFace={l}{n}{Font={*-Light}},
FontFace={l}{it}{Font={*-LightItalic}},
UprightFont=*-Regular,
ItalicFont=*-Italic,
FontFace={mb}{n}{Font={*-Medium}},
FontFace={mb}{it}{Font={*-MediumItalic}},
FontFace={sb}{n}{Font={*-SemiBold}},
FontFace={sb}{it}{Font={*-SemiBoldItalic}},
BoldFont=*-Bold,
BoldItalicFont=*-BoldItalic,
FontFace={eb}{n}{Font={*-ExtraBold}},
FontFace={eb}{it}{Font={*-ExtraBoldItalic}},
FontFace={ub}{n}{Font={*-Black}},
FontFace={ub}{it}{Font={*-BlackItalic}},
FontFace={uluc}{n}{Font={*-ExtraCondensedThin}},
FontFace={uluc}{it}{Font={*-ExtraCondensedThinItalic}},
FontFace={eluc}{n}{Font={*-ExtraCondensedExtraLight}},
FontFace={eluc}{it}{Font={*-ExtraCondensedExtraLightItalic}},
FontFace={luc}{n}{Font={*-ExtraCondensedLight}},
FontFace={luc}{it}{Font={*-ExtraCondensedLightItalic}},
FontFace={uc}{n}{Font={*-ExtraCondensed}},
FontFace={uc}{it}{Font={*-ExtraCondensedItalic}},
FontFace={mbuc}{n}{Font={*-ExtraCondensedMedium}},
FontFace={mbuc}{it}{Font={*-ExtraCondensedMediumItalic}},
FontFace={sbuc}{n}{Font={*-ExtraCondensedSemiBold}},
FontFace={sbuc}{it}{Font={*-ExtraCondensedSemiBoldItalic}},
FontFace={buc}{n}{Font={*-ExtraCondensedBold}},
FontFace={buc}{it}{Font={*-ExtraCondensedBoldItalic}},
FontFace={ebuc}{n}{Font={*-ExtraCondensedExtraBold}},
FontFace={ebuc}{it}{Font={*-ExtraCondensedExtraBoldItalic}},
FontFace={ubuc}{n}{Font={*-ExtraCondensedBlack}},
FontFace={ubuc}{it}{Font={*-ExtraCondensedBlackItalic}},
FontFace={ulec}{n}{Font={*-CondensedThin}},
FontFace={ulec}{it}{Font={*-CondensedThinItalic}},
FontFace={elec}{n}{Font={*-CondensedExtraLight}},
FontFace={elec}{it}{Font={*-CondensedExtraLightItalic}},
FontFace={lec}{n}{Font={*-CondensedLight}},
FontFace={lec}{it}{Font={*-CondensedLightItalic}},
FontFace={ec}{n}{Font={*-Condensed}},
FontFace={ec}{it}{Font={*-CondensedItalic}},
FontFace={mbec}{n}{Font={*-CondensedMedium}},
FontFace={mbec}{it}{Font={*-CondensedMediumItalic}},
FontFace={sbec}{n}{Font={*-CondensedSemiBold}},
FontFace={sbec}{it}{Font={*-CondensedSemiBoldItalic}},
FontFace={bec}{n}{Font={*-CondensedBold}},
FontFace={bec}{it}{Font={*-CondensedBoldItalic}},
FontFace={ebec}{n}{Font={*-CondensedExtraBold}},
FontFace={ebec}{it}{Font={*-CondensedExtraBoldItalic}},
FontFace={ubec}{n}{Font={*-CondensedBlack}},
FontFace={ubec}{it}{Font={*-CondensedBlackItalic}},
FontFace={ulc}{n}{Font={*-SemiCondensedThin}},
FontFace={ulc}{it}{Font={*-SemiCondensedThinItalic}},
FontFace={elc}{n}{Font={*-SemiCondensedExtraLight}},
FontFace={elc}{it}{Font={*-SemiCondensedExtraLightItalic}},
FontFace={lc}{n}{Font={*-SemiCondensedLight}},
FontFace={lc}{it}{Font={*-SemiCondensedLightItalic}},
FontFace={c}{n}{Font={*-SemiCondensed}},
FontFace={c}{it}{Font={*-SemiCondensedItalic}},
FontFace={mbc}{n}{Font={*-SemiCondensedMedium}},
FontFace={mbc}{it}{Font={*-SemiCondensedMediumItalic}},
FontFace={sbc}{n}{Font={*-SemiCondensedSemiBold}},
FontFace={sbc}{it}{Font={*-SemiCondensedSemiBoldItalic}},
FontFace={bc}{n}{Font={*-SemiCondensedBold}},
FontFace={bc}{it}{Font={*-SemiCondensedBoldItalic}},
FontFace={ebc}{n}{Font={*-SemiCondensedExtraBold}},
FontFace={ebc}{it}{Font={*-SemiCondensedExtraBoldItalic}},
FontFace={ubc}{n}{Font={*-SemiCondensedBlack}},
FontFace={ubc}{it}{Font={*-SemiCondensedBlackItalic}}
}

\setmainfont{NotoSerif}

\makeatletter
\edef\current@weight{m}
\edef\current@extent{}

\DeclareRobustCommand\fontweight[1]{%
\edef\current@weight{#1}%
\update@series%
}

\DeclareRobustCommand\fontextent[1]{%
\edef\current@extent{#1}%
\update@series%
}

\DeclareRobustCommand\update@series{%
\expandafter\ifx\current@extent\relax%
\fontseries{\current@weight}%
\else%
\ifx\current@weight m%
\fontseries{\current@extent}%
\else%
\fontseries{\current@weight\current@extent}%
\fi%
\fi%
}
\makeatother

\newcommand\ulweight{\fontweight{ul}\selectfont}
\newcommand\elweight{\fontweight{el}\selectfont}
\newcommand\ltweight{\fontweight{l}\selectfont}
\newcommand\mdweight{\fontweight{m}\selectfont}
\newcommand\mbweight{\fontweight{mb}\selectfont}
\newcommand\sbweight{\fontweight{sb}\selectfont}
\newcommand\bfweight{\fontweight{b}\selectfont}
\newcommand\ebweight{\fontweight{eb}\selectfont}
\newcommand\ubweight{\fontweight{ub}\selectfont}
\newcommand\ucwidth{\fontextent{uc}\selectfont}
\newcommand\ecwidth{\fontextent{ec}\selectfont}
\newcommand\cdwidth{\fontextent{c}\selectfont}

\begin{document}
\mdweight Noto Serif \textit{Italic}
\ulweight Thin \textit{Italic}
\elweight ExtraLight \textit{Italic}
\ltweight Light \textit{Italic}
\mbweight Medium \textit{Italic}
\sbweight Semibold \textit{Italic}
\bfweight Bold \textit{Italic}
\ebweight Extra-Bold \textit{Italic}
\ubweight Heavy \textit{Italic}

\ucwidth
\mdweight Noto Serif Extra-Condensed \textit{Italic}
\ulweight Thin \textit{Italic}
\elweight ExtraLight \textit{Italic}
\ltweight Light \textit{Italic}
\mbweight Medium \textit{Italic}
\sbweight Semibold \textit{Italic}
\bfweight Bold \textit{Italic}
\ebweight Extra-Bold \textit{Italic}
\ubweight Heavy \textit{Italic}

\ecwidth
\mdweight Noto Serif Condensed \textit{Italic}
\ulweight Thin \textit{Italic}
\elweight ExtraLight \textit{Italic}
\ltweight Light \textit{Italic}
\mbweight Medium \textit{Italic}
\sbweight Semibold \textit{Italic}
\bfweight Bold \textit{Italic}
\ebweight Extra-Bold \textit{Italic}
\ubweight Heavy \textit{Italic}

\cdwidth
\mdweight Noto Serif Semi-Condensed \textit{Italic}
\ulweight Thin \textit{Italic}
\elweight ExtraLight \textit{Italic}
\ltweight Light \textit{Italic}
\mbweight Medium \textit{Italic}
\sbweight Semibold \textit{Italic}
\bfweight Bold \textit{Italic}
\ebweight Extra-Bold \textit{Italic}
\ubweight Heavy \textit{Italic}
\end{document}


I re-invented the wheel there: the nfssext-cfr package by @cfr also defines commands to set weight and width separately, and I used similar names. If you also want commands corresponding to \textit, \textup, and so on, you would define them with \DeclareTextFontCommand\textul{\ulwidth}, etc.

You might instead want to redefine the standard \bfseries, \mdseries and so on, so that bold condensed would be \bfseries\cdseries instead of \bfweight\cdwidth. This is how fontaxes and fontspec handle \itshape\scshape for italic small caps. I avoided overriding the standard commands here, but that means they aren’t compatible with the new ones.

Like most packages, I used the official LaTeX series names from The LaTeX Font Installation Guide, but note that fontspec allows you to give your series and shapes arbitrary names. There is no reason you couldn’t set up \fontweight{Semibold}\fontextent{Condensed}\selectfont to work, or \fontseries{SemiboldCondensed}\selectfont. Just declare FontFace{SemiboldCondensed}{n} instead of FontFace{sbc}{n}.

To enable options such as support for optical sizes or variable fonts, add them inside the braces after Font=, such as FontFace{ebc}{n}{ Font={*-ExtraBoldCondensed}, SizeFeatures={...} }. See the fontspec manual for the features you need.

LuaTeX 1.13 and up now supports variable fonts as well.

If you just want to use the human-readable names in your code, you could attempt something like \fontspec{Avenir Next LT Pro Medium Condensed}. Loading fonts by display name is deprecated, however.

• it is better to stick to the official series names of latex, as a number of internal setups, e.g. for series fallbacks, relies on them. May 1 '21 at 12:25
• This is exact kind of stuff I want to avoid. Sorry voting down for this. As I mention in bounty, and comments to the description, there should be no "setup" necessary for any new font installed on the system. And your \defaultfontfeatures[NotoSerif]{... breaks that. May 1 '21 at 19:52
• @reportaman I respectfully, but strongly, disagree. For one thing, different font super-families use different naming schemes, such as Heavy or Black, Semibold or Demibold, etc. If you tried to implement the Noto example with no set-up, using other display names, it would break even on a system with the OpenType version of the font installed. May 1 '21 at 20:36
• @reportaman Authors are much better off loading a package that does the necessary set-up for semanting markup to work. May 1 '21 at 20:38
• @reportaman That said, I’m guessing you want a Lua hook or wrapper for \font` that remembers the family name and adds the subfamily to load the font. May 1 '21 at 20:44