Start to make a buildup-based variant system

This commit is contained in:
be5invis 2023-05-23 02:01:33 -07:00
parent cfac045755
commit 618ef2702d
4 changed files with 362 additions and 367 deletions

View file

@ -1,6 +1,6 @@
$$include '../../../meta/macros.ptl'
import [mix linreg clamp fallback] from"../../../support/utils.mjs"
import [mix fallback weaveSuffix] from"../../../support/utils.mjs"
import [Dotless CvDecompose MathSansSerif] from"../../../support/gr.mjs"
glyph-module
@ -168,44 +168,25 @@ glyph-block Letter-Latin-Lower-M : begin
flat df.rightSB [Math.max (top - [SmallMSmooth df]) (rbot + 0.1)]
curl df.rightSB rbot [heading Downward]
define BodyConfig : object
"" { SmallMArches 0 }
"earlessCornerDoubleArch" { EarlessCornerDoubleArchSmallMShape 1 }
"earlessRoundedDoubleArch" { EarlessRoundedDoubleArchSmallMShape 1 }
"earlessSingleArch" { EarlessSingleArchSmallMShape 1 }
define SmallMConfig : weaveSuffix
object
"" { SmallMArches 0 }
"earlessCornerDoubleArch" { EarlessCornerDoubleArchSmallMShape 1 }
"earlessRoundedDoubleArch" { EarlessRoundedDoubleArchSmallMShape 1 }
"earlessSingleArch" { EarlessSingleArchSmallMShape 1 }
object
"" { 0 }
"shortLeg" { 1 }
object
"" { 0 }
"tailed" { 1 }
object
"serifless" { no-shape }
"serifed" { FullSerifs }
"topLeftSerifed" { LtSerifs }
"topLeftAndBottomRightSerifed" { LtRbSerifs }
define TailConfig : object
"" { 0 }
"tailed" { 1 }
define LegConfig : object
"" { 0 }
"shortLeg" { 1 }
define SerifConfig : object
"" { AutoSerifs }
"serifless" { no-shape }
"serifed" { FullSerifs }
"topLeftSerifed" { LtSerifs }
"topLeftAndBottomRightSerifed" { LtRbSerifs }
define [join-suffix parts] : begin
local suffix ""
foreach part [items-of parts] : do
if part : begin
local toAppend : if suffix ([part.charAt 0 :.toUpperCase] + [part.slice 1]) part
set suffix : suffix + toAppend
return suffix
define SmallMConfig {.}
foreach { suffixBody { Body earless } } [Object.entries BodyConfig]
foreach { suffixLeg { shortLeg } } [Object.entries LegConfig]
foreach { suffixTail { tailed } } [Object.entries TailConfig]
foreach { suffixSerifs { Serifs } } [Object.entries SerifConfig] : begin
local suffix : join-suffix { suffixBody suffixLeg suffixTail suffixSerifs }
set SmallMConfig.(suffix) { Body Serifs tailed shortLeg earless }
foreach { suffix { Body Serifs tailed shortLeg earless } } [Object.entries SmallMConfig] : do
foreach { suffix { {Body earless} {tailed} {shortLeg} {Serifs} } } [pairs-of SmallMConfig] : do
define [mShapeBody df height] : glyph-proc
include : Body height 0 [if shortLeg [SmallMShortLegHeight height df] 0] [if tailed ([SmallMSmoothHeight height df] + O) 0] df
if tailed : include : RightwardTailedBar df.rightSB 0 [SmallMSmoothHeight height df] (sw -- df.mvs)

View file

@ -25,3 +25,30 @@ export function bez3(a, b, c, d, t) {
t * t * t * d
);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
export function joinCamel(a, b) {
if (!a) return b;
if (!b) return a;
return a + b[0].toUpperCase() + b.slice(1);
}
export function weaveSuffix(...configs) {
let ans = {};
joinSuffixListImpl(ans, "", [], configs);
return ans;
}
function joinSuffixListImpl(sink, k, v, configs) {
if (!configs.length) {
sink[k] = v;
return;
}
for (const [keySuffix, valueSuffix] of Object.entries(configs[0])) {
const k1 = joinCamel(k, keySuffix);
const v1 = [...v, valueSuffix];
joinSuffixListImpl(sink, k1, v1, configs.slice(1));
}
}

View file

@ -1,3 +1,5 @@
import { joinCamel } from "./utils.mjs";
export function apply(data, para, argv) {
const parsed = parse(data, argv);
let tagSet = new Set();
@ -67,7 +69,6 @@ class SelectorTree {
class Prime {
constructor(key, cfg) {
if (!cfg.variants) throw new Error(`Missing variants in ${key}`);
this.key = key;
this.sampler = cfg.sampler;
this.samplerExplain = cfg.samplerExplain;
@ -79,10 +80,18 @@ class Prime {
: [...(cfg.sampler || "")];
this.tag = cfg.tag;
this.slopeDependent = !!cfg.slopeDependent;
this.variants = new Map();
this.hotChars = cfg.hotChars ? [...cfg.hotChars] : this.descSampleText;
for (const varKey in cfg.variants) {
const variant = cfg.variants[varKey];
this.variants = new Map();
let variantConfig = cfg.variants;
if (!variantConfig && cfg["variants-buildup"]) {
const vb = new VariantBuilder(cfg["variants-buildup"]);
variantConfig = vb.process();
}
if (!variantConfig) throw new Error(`Missing variants in ${key}`);
for (const varKey in variantConfig) {
const variant = variantConfig[varKey];
this.variants.set(varKey, new PrimeVariant(varKey, cfg.tag, variant));
}
}
@ -190,3 +199,191 @@ class Composite {
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Systematic Variant Building
///
class VariantBuilder {
constructor(cfg) {
this.entry = cfg.entry;
this.descriptionLeader = cfg.descriptionLeader;
this.stages = new Map();
for (const [key, stage] of Object.entries(cfg.stages)) {
this.stages.set(key, new VbStage(key, stage));
}
}
process() {
const globalState = new VbGlobalState(this.stages);
const localState = new VbLocalState();
localState.descriptionLeader = this.descriptionLeader;
globalState.stages.get(this.entry).accept(globalState, localState);
let ans = {};
for (const item of globalState.sink) {
let cfg = item.createPrimeVariant();
ans[cfg.key] = cfg;
}
return ans;
}
}
class VbStage {
constructor(stage, raw) {
this.stage = stage;
this.defaultAlternative = new VbStageAlternative(this.stage, "*", {});
this.alternatives = new Map();
for (const k in raw) {
if (k === "*") {
this.defaultAlternative = new VbStageAlternative(this.stage, "*", raw[k]);
} else {
this.alternatives.set(k, new VbStageAlternative(this.stage, k, raw[k]));
}
}
for (const v of this.alternatives.values()) v.fallback(this.defaultAlternative);
}
accept(globalState, localState) {
let variantList = Array.from(this.alternatives.values());
variantList.sort((a, b) => (a.rank || 0) - (b.rank || 0));
for (const v of variantList) {
const ans = v.tryAccept(globalState, localState);
if (ans) globalState.stages.get(ans.stage).accept(globalState, ans);
}
}
}
class VbStageAlternative {
constructor(stage, key, raw) {
this.stage = stage;
this.key = key;
this.rank = raw.rank;
this.next = raw.next;
this.keySuffix = raw.keySuffix;
this.descriptionSuffix = raw.descriptionSuffix;
this.descriptionJoiner = raw.descriptionJoiner || "with";
this.disableIf = raw.disableIf;
this.selectorSuffix = raw.selectorSuffix;
}
fallback(defaultAlternative) {
this.next = this.next || defaultAlternative.next;
this.keySuffix = this.keySuffix || defaultAlternative.keySuffix;
this.descriptionSuffix = this.descriptionSuffix || defaultAlternative.descriptionSuffix;
this.descriptionJoiner = this.descriptionJoiner || defaultAlternative.descriptionJoiner;
this.disableIf = this.disableIf || defaultAlternative.disableIf;
this.selectorSuffix = this.selectorSuffix || defaultAlternative.selectorSuffix;
}
tryAccept(globalState, localState) {
// Detect whether this alternative is applicable.
if (this.disableIf) {
for (const branch of this.disableIf) {
let statementMatches = true;
for (let [k, v] of Object.entries(branch)) {
v = v.trim();
if (/^NOT(?=\s)/.test(v)) {
v = v.slice(3).trim();
if (localState.assignments.get(k) === v) {
statementMatches = false;
break;
}
} else {
if (localState.assignments.get(k) !== v) {
statementMatches = false;
break;
}
}
}
if (statementMatches) return null;
}
}
// Accept this alternative.
const ans = localState.clone();
ans.stage = this.next;
ans.assignments.set(this.stage, this.key);
if (this.keySuffix) ans.key.push(this.keySuffix);
if (this.descriptionJoiner && this.descriptionSuffix)
ans.addDescription(this.descriptionJoiner, this.descriptionSuffix);
if (this.selectorSuffix)
for (const [selector, suffix] of Object.entries(this.selectorSuffix))
ans.addSelector(selector, suffix);
if (!this.next) {
ans.rank = ++globalState.rank;
globalState.sink.push(ans);
return null;
} else {
return ans;
}
}
}
class VbGlobalState {
constructor(stages) {
this.stages = stages;
this.rank = 0;
this.sink = [];
}
}
class VbLocalState {
constructor() {
this.stage = ".start";
this.rank = 0;
this.descriptionLeader = "";
this.assignments = new Map();
this.key = [];
this.descriptions = new Map();
this.selector = new Map();
}
clone() {
const ans = new VbLocalState();
ans.stage = this.stage;
ans.rank = this.rank;
ans.descriptionLeader = this.descriptionLeader;
ans.assignments = new Map(this.assignments);
ans.key = [...this.key];
ans.selector = new Map(this.selector);
ans.descriptions = new Map();
for (const [k, v] of this.descriptions) ans.descriptions.set(k, [...v]);
return ans;
}
addDescription(joiner, segment) {
if (!this.descriptions.has(joiner)) this.descriptions.set(joiner, []);
this.descriptions.get(joiner).push(segment);
}
addSelector(selector, value) {
this.selector.set(selector, joinCamel(this.selector.get(selector), value));
}
produceKey() {
return this.key.join("-");
}
produceDescription() {
let desc = [];
for (const [joiner, segments] of this.descriptions) {
if (!segments.length) continue;
desc.push(`${joiner} ${arrayToSentence(segments)}`);
}
return this.descriptionLeader + " " + desc.join("; ");
}
createPrimeVariant() {
return {
key: this.produceKey(),
rank: this.rank,
description: this.produceDescription(),
selector: Object.fromEntries(this.selector)
};
}
}
function arrayToSentence(arr) {
if (arr.length == 1) return arr[0];
let last = arr.pop();
return arr.join(", ") + " and " + last;
}

View file

@ -3400,347 +3400,137 @@ selector.lyogh = "hooky"
sampler = "m"
tag = "cv38"
[prime.m.variants.serifless]
[prime.m.variants-buildup]
entry = "body"
descriptionLeader = "`m`"
[prime.m.variants-buildup.stages.body."*"]
next = "leg"
[prime.m.variants-buildup.stages.body.normal]
rank = 1
description = "`m` with normal middle leg, touching the baseline"
selector.m = "serifless"
selector."m/tailless" = "serifless"
selector."m/sansSerif" = "serifless"
selector."cyrl/te.italic" = "serifless"
selector.mLTail = "serifless"
descriptionSuffix = "eared body shape"
selectorSuffix.m = ""
selectorSuffix."m/tailless" = ""
selectorSuffix."m/sansSerif" = ""
selectorSuffix."cyrl/te.italic" = ""
selectorSuffix.mLTail = ""
[prime.m.variants.top-left-serifed]
[prime.m.variants-buildup.stages.body.earless-corner-double-arch]
rank = 2
description = "`m` with serif at top left, normal middle leg touching baseline"
selector.m = "topLeftSerifed"
selector."m/tailless" = "topLeftSerifed"
selector."m/sansSerif" = "serifless"
selector."cyrl/te.italic" = "topLeftSerifed"
selector.mLTail = "topLeftSerifed"
keySuffix = "earless-corner-double-arch"
descriptionSuffix = "earless (corner top-left) double-arch body shape"
selectorSuffix.m = "earlessCornerDoubleArch"
selectorSuffix."m/tailless" = "earlessCornerDoubleArch"
selectorSuffix."m/sansSerif" = "earlessCornerDoubleArch"
selectorSuffix."cyrl/te.italic" = ""
selectorSuffix.mLTail = "earlessCornerDoubleArch"
[prime.m.variants.top-left-and-bottom-right-serifed]
[prime.m.variants-buildup.stages.body.earless-rounded-double-arch]
rank = 3
description = "`m` with serifs at top left and bottom right, normal middle leg touching baseline"
selector.m = "topLeftAndBottomRightSerifed"
selector."m/tailless" = "topLeftAndBottomRightSerifed"
selector."m/sansSerif" = "serifless"
selector."cyrl/te.italic" = "topLeftAndBottomRightSerifed"
selector.mLTail = "topLeftSerifed"
keySuffix = "earless-rounded-double-arch"
descriptionSuffix = "earless (rounded top-left) double-arch body shape"
selectorSuffix.m = "earlessRoundedDoubleArch"
selectorSuffix."m/tailless" = "earlessRoundedDoubleArch"
selectorSuffix."m/sansSerif" = "earlessRoundedDoubleArch"
selectorSuffix."cyrl/te.italic" = ""
selectorSuffix.mLTail = "earlessRoundedDoubleArch"
[prime.m.variants.serifed]
[prime.m.variants-buildup.stages.body.earless-single-arch]
rank = 4
description = "`m` with serifs, normal middle leg touching baseline"
selector.m = "serifed"
selector."m/tailless" = "serifed"
selector."m/sansSerif" = "serifless"
selector."cyrl/te.italic" = "serifed"
selector.mLTail = "topLeftSerifed"
keySuffix = "earless-single-arch"
descriptionSuffix = "earless (corner top-left) body shape"
selectorSuffix.m = "earlessSingleArch"
selectorSuffix."m/tailless" = "earlessSingleArch"
selectorSuffix."m/sansSerif" = "earlessSingleArch"
selectorSuffix."cyrl/te.italic" = ""
selectorSuffix.mLTail = "earlessSingleArch"
[prime.m.variants.tailed-serifless]
rank = 5
description = "`m` with normal middle leg, touching the baseline, and a curly tail"
selector.m = "tailed"
selector."m/tailless" = "serifless"
selector."m/sansSerif" = "tailed"
selector."cyrl/te.italic" = "tailed"
selector.mLTail = "serifless"
[prime.m.variants-buildup.stages.leg."*"]
next = "tail"
[prime.m.variants.tailed-top-left-serifed]
rank = 6
description = "`m` with serif at top left, normal middle leg touching baseline, and a curly tail"
selector.m = "tailedTopLeftSerifed"
selector."m/tailless" = "topLeftSerifed"
selector."m/sansSerif" = "tailed"
selector."cyrl/te.italic" = "tailedTopLeftSerifed"
selector.mLTail = "topLeftSerifed"
[prime.m.variants-buildup.stages.leg.normal]
rank = 1
descriptionSuffix = "normal middle leg"
selectorSuffix.m = ""
selectorSuffix."m/tailless" = ""
selectorSuffix."m/sansSerif" = ""
selectorSuffix."cyrl/te.italic" = ""
selectorSuffix.mLTail = ""
[prime.m.variants.tailed-serifed]
rank = 7
description = "`m` with serifs, normal middle leg touching baseline, and a curly tail"
selector.m = "tailedSerifed"
selector."m/tailless" = "topLeftSerifed"
selector."m/sansSerif" = "tailed"
selector."cyrl/te.italic" = "tailedSerifed"
selector.mLTail = "topLeftSerifed"
[prime.m.variants-buildup.stages.leg.short-leg]
rank = 2
keySuffix = "short-leg"
descriptionSuffix = "shorter middle leg (like Ubuntu Mono)"
selectorSuffix.m = "shortLeg"
selectorSuffix."m/tailless" = "shortLeg"
selectorSuffix."m/sansSerif" = "shortLeg"
selectorSuffix."cyrl/te.italic" = ""
selectorSuffix.mLTail = "shortLeg"
[prime.m.variants.earless-corner-double-arch]
rank = 8
description = "Earless (corner top-left) `m` with normal middle leg touching baseline"
selector.m = "earlessCornerDoubleArch"
selector."m/tailless" = "earlessCornerDoubleArch"
selector."m/sansSerif" = "earlessCornerDoubleArch"
selector."cyrl/te.italic" = "serifless"
selector.mLTail = "earlessCornerDoubleArch"
[prime.m.variants-buildup.stages.tail."*"]
next = "serifs"
[prime.m.variants.earless-corner-double-arch-serifed]
rank = 9
description = "Earless (corner top-left) `m` with normal middle leg touching baseline, and serifs"
selector.m = "earlessCornerDoubleArchSerifed"
selector."m/tailless" = "earlessCornerDoubleArchSerifed"
selector."m/sansSerif" = "earlessCornerDoubleArch"
selector."cyrl/te.italic" = "serifed"
selector.mLTail = "earlessCornerDoubleArchSerifed"
[prime.m.variants-buildup.stages.tail.normal]
rank = 1
selectorSuffix.m = ""
selectorSuffix."m/tailless" = ""
selectorSuffix."m/sansSerif" = ""
selectorSuffix."cyrl/te.italic" = ""
selectorSuffix.mLTail = ""
[prime.m.variants.earless-corner-double-arch-tailed]
rank = 10
description = "Earless (corner top-left) `m` with normal middle leg touching baseline, and a curly tail"
selector.m = "earlessCornerDoubleArchTailed"
selector."m/tailless" = "earlessCornerDoubleArch"
selector."m/sansSerif" = "earlessCornerDoubleArchTailed"
selector."cyrl/te.italic" = "tailed"
selector.mLTail = "earlessCornerDoubleArch"
[prime.m.variants-buildup.stages.tail.tailed]
rank = 2
keySuffix = "tailed"
descriptionSuffix = "tail"
selectorSuffix.m = "tailed"
selectorSuffix."m/tailless" = ""
selectorSuffix."m/sansSerif" = "tailed"
selectorSuffix."cyrl/te.italic" = "tailed"
selectorSuffix.mLTail = ""
[prime.m.variants.earless-corner-double-arch-tailed-serifed]
rank = 11
description = "Earless (corner top-left) `m` with normal middle leg touching baseline, a curly tail, and serifs"
selector.m = "earlessCornerDoubleArchTailedSerifed"
selector."m/tailless" = "earlessCornerDoubleArchSerifed"
selector."m/sansSerif" = "earlessCornerDoubleArchTailed"
selector."cyrl/te.italic" = "tailedSerifed"
selector.mLTail = "earlessCornerDoubleArchSerifed"
[prime.m.variants-buildup.stages.serifs.serifless]
rank = 1
keySuffix = "serifless"
descriptionJoiner = "without"
descriptionSuffix = "serifs"
selectorSuffix.m = "serifless"
selectorSuffix."m/tailless" = "serifless"
selectorSuffix."m/sansSerif" = "serifless"
selectorSuffix."cyrl/te.italic" = "serifless"
selectorSuffix.mLTail = "serifless"
[prime.m.variants.earless-rounded-double-arch]
rank = 12
description = "Earless (rounded top-left) `m` with normal middle leg touching baseline"
selector.m = "earlessRoundedDoubleArch"
selector."m/tailless" = "earlessRoundedDoubleArch"
selector."m/sansSerif" = "earlessRoundedDoubleArch"
selector."cyrl/te.italic" = "serifless"
selector.mLTail = "earlessRoundedDoubleArch"
[prime.m.variants-buildup.stages.serifs.top-left-serifed]
rank = 2
keySuffix = "top-left-serifed"
descriptionSuffix = "serif at top left"
disableIf = [ { body = "NOT normal" } ]
selectorSuffix.m = "topLeftSerifed"
selectorSuffix."m/tailless" = "topLeftSerifed"
selectorSuffix."m/sansSerif" = "serifless"
selectorSuffix."cyrl/te.italic" = "topLeftSerifed"
selectorSuffix.mLTail = "topLeftSerifed"
[prime.m.variants.earless-rounded-double-arch-serifed]
rank = 13
description = "Earless (rounded top-left) `m` with normal middle leg touching baseline, and serifs"
selector.m = "earlessRoundedDoubleArchSerifed"
selector."m/tailless" = "earlessRoundedDoubleArchSerifed"
selector."m/sansSerif" = "earlessRoundedDoubleArch"
selector."cyrl/te.italic" = "serifed"
selector.mLTail = "earlessRoundedDoubleArchSerifed"
[prime.m.variants-buildup.stages.serifs.top-left-and-bottom-right-serifed]
rank = 3
keySuffix = "top-left-and-bottom-right-serifed"
descriptionSuffix = "serifs at top left and bottom right"
disableIf = [ { body = "NOT normal" }, { tail = "tailed" } ]
selectorSuffix.m = "topLeftAndBottomRightSerifed"
selectorSuffix."m/tailless" = "topLeftAndBottomRightSerifed"
selectorSuffix."m/sansSerif" = "serifless"
selectorSuffix."cyrl/te.italic" = "topLeftAndBottomRightSerifed"
selectorSuffix.mLTail = "topLeftSerifed"
[prime.m.variants.earless-rounded-double-arch-tailed]
rank = 14
description = "Earless (rounded top-left) `m` with normal middle leg touching baseline, and a curly tail"
selector.m = "earlessRoundedDoubleArchTailed"
selector."m/tailless" = "earlessRoundedDoubleArch"
selector."m/sansSerif" = "earlessRoundedDoubleArchTailed"
selector."cyrl/te.italic" = "tailed"
selector.mLTail = "earlessRoundedDoubleArch"
[prime.m.variants.earless-rounded-double-arch-tailed-serifed]
rank = 15
description = "Earless (rounded top-left) `m` with normal middle leg touching baseline, a curly tail, and serifs"
selector.m = "earlessRoundedDoubleArchTailedSerifed"
selector."m/tailless" = "earlessRoundedDoubleArchSerifed"
selector."m/sansSerif" = "earlessRoundedDoubleArchTailed"
selector."cyrl/te.italic" = "tailedSerifed"
selector.mLTail = "earlessRoundedDoubleArchSerifed"
[prime.m.variants.earless-single-arch]
rank = 16
description = "Earless (single-arch) `m` with normal middle leg touching baseline"
selector.m = "earlessSingleArch"
selector."m/tailless" = "earlessSingleArch"
selector."m/sansSerif" = "earlessSingleArch"
selector."cyrl/te.italic" = "serifless"
selector.mLTail = "earlessSingleArch"
[prime.m.variants.earless-single-arch-serifed]
rank = 17
description = "Earless (single-arch) `m` with normal middle leg touching baseline, and serifs"
selector.m = "earlessSingleArchSerifed"
selector."m/tailless" = "earlessSingleArchSerifed"
selector."m/sansSerif" = "earlessSingleArch"
selector."cyrl/te.italic" = "serifed"
selector.mLTail = "earlessSingleArchSerifed"
[prime.m.variants.earless-single-arch-tailed]
rank = 18
description = "Earless (single-arch) `m` with normal middle leg touching baseline, and a curly tail"
selector.m = "earlessSingleArchTailed"
selector."m/tailless" = "earlessSingleArch"
selector."m/sansSerif" = "earlessSingleArchTailed"
selector."cyrl/te.italic" = "tailed"
selector.mLTail = "earlessSingleArch"
[prime.m.variants.earless-single-arch-tailed-serifed]
rank = 19
description = "Earless (single-arch) `m` with normal middle leg touching baseline, a curly tail, and serifs"
selector.m = "earlessSingleArchTailedSerifed"
selector."m/tailless" = "earlessSingleArchSerifed"
selector."m/sansSerif" = "earlessSingleArchTailed"
selector."cyrl/te.italic" = "tailedSerifed"
selector.mLTail = "earlessSingleArchSerifed"
[prime.m.variants.short-leg]
rank = 20
description = "`m` with shorter middle leg, like Ubuntu Mono"
selector.m = "shortLeg"
selector."m/tailless" = "shortLeg"
selector."m/sansSerif" = "shortLeg"
selector."cyrl/te.italic" = "serifless"
selector.mLTail = "shortLeg"
[prime.m.variants.short-leg-top-left-serifed]
rank = 21
description = "`m` with serif at top left, a shorter middle leg like Ubuntu Mono"
selector.m = "shortLegTopLeftSerifed"
selector."m/tailless" = "shortLegTopLeftSerifed"
selector."m/sansSerif" = "shortLeg"
selector."cyrl/te.italic" = "topLeftSerifed"
selector.mLTail = "shortLegTopLeftSerifed"
[prime.m.variants.short-leg-top-left-and-bottom-right-serifed]
rank = 22
description = "`m` with serifs at top left and bottom right, a shorter middle leg like Ubuntu Mono"
selector.m = "shortLegTopLeftAndBottomRightSerifed"
selector."m/tailless" = "shortLegTopLeftAndBottomRightSerifed"
selector."m/sansSerif" = "shortLeg"
selector."cyrl/te.italic" = "topLeftAndBottomRightSerifed"
selector.mLTail = "shortLegTopLeftSerifed"
[prime.m.variants.short-leg-serifed]
rank = 23
description = "`m` with serifs, a shorter middle leg like Ubuntu Mono"
selector.m = "shortLegSerifed"
selector."m/tailless" = "shortLegSerifed"
selector."m/sansSerif" = "shortLeg"
selector."cyrl/te.italic" = "topLeftAndBottomRightSerifed"
selector.mLTail = "shortLegTopLeftSerifed"
[prime.m.variants.short-leg-tailed]
rank = 24
description = "`m` with shorter middle leg, like Ubuntu Mono, and a curly tail"
selector.m = "shortLegTailed"
selector."m/tailless" = "shortLeg"
selector."m/sansSerif" = "shortLegTailed"
selector."cyrl/te.italic" = "tailed"
selector.mLTail = "shortLeg"
[prime.m.variants.short-leg-tailed-top-left-serifed]
rank = 25
description = "`m` with serif at top left, a shorter middle leg like Ubuntu Mono, and a curly tail"
selector.m = "shortLegTailedTopLeftSerifed"
selector."m/tailless" = "shortLegTopLeftSerifed"
selector."m/sansSerif" = "shortLegTailed"
selector."cyrl/te.italic" = "tailedTopLeftSerifed"
selector.mLTail = "shortLegTopLeftSerifed"
[prime.m.variants.short-leg-tailed-serifed]
rank = 26
description = "`m` with serif, a shorter middle leg like Ubuntu Mono, and a curly tail"
selector.m = "shortLegTailedSerifed"
selector."m/tailless" = "shortLegTopLeftSerifed"
selector."m/sansSerif" = "shortLegTailed"
selector."cyrl/te.italic" = "tailedTopLeftSerifed"
selector.mLTail = "shortLegTopLeftSerifed"
[prime.m.variants.earless-corner-double-arch-short-leg]
rank = 27
description = "Earless (corner top-left) `m` with a shorter middle leg like Ubuntu Mono"
selector.m = "earlessCornerDoubleArchShortLeg"
selector."m/tailless" = "earlessCornerDoubleArchShortLeg"
selector."m/sansSerif" = "earlessCornerDoubleArchShortLeg"
selector."cyrl/te.italic" = "serifless"
selector.mLTail = "earlessCornerDoubleArchShortLeg"
[prime.m.variants.earless-corner-double-arch-short-leg-serifed]
rank = 28
description = "Earless (corner top-left) `m` with a shorter middle leg like Ubuntu Mono, and serifs"
selector.m = "earlessCornerDoubleArchShortLegSerifed"
selector."m/tailless" = "earlessCornerDoubleArchShortLegSerifed"
selector."m/sansSerif" = "earlessCornerDoubleArchShortLeg"
selector."cyrl/te.italic" = "serifed"
selector.mLTail = "earlessCornerDoubleArchShortLegSerifed"
[prime.m.variants.earless-corner-double-arch-short-leg-tailed]
rank = 29
description = "Earless (corner top-left) `m` with a shorter middle leg like Ubuntu Mono, and a curly tail"
selector.m = "earlessCornerDoubleArchShortLegTailed"
selector."m/tailless" = "earlessCornerDoubleArchShortLeg"
selector."m/sansSerif" = "earlessCornerDoubleArchShortLegTailed"
selector."cyrl/te.italic" = "tailed"
selector.mLTail = "earlessCornerDoubleArchShortLeg"
[prime.m.variants.earless-corner-double-arch-short-leg-tailed-serifed]
rank = 30
description = "Earless (corner top-left) `m` with a shorter middle leg like Ubuntu Mono, and a curly tail, and serifs"
selector.m = "earlessCornerDoubleArchShortLegTailedSerifed"
selector."m/tailless" = "earlessCornerDoubleArchShortLegSerifed"
selector."m/sansSerif" = "earlessCornerDoubleArchShortLegTailed"
selector."cyrl/te.italic" = "tailedSerifed"
selector.mLTail = "earlessCornerDoubleArchShortLegSerifed"
[prime.m.variants.earless-rounded-double-arch-short-leg]
rank = 31
description = "Earless (rounded top-left) `m` with a shorter middle leg like Ubuntu Mono"
selector.m = "earlessRoundedDoubleArchShortLeg"
selector."m/tailless" = "earlessRoundedDoubleArchShortLeg"
selector."m/sansSerif" = "earlessRoundedDoubleArchShortLeg"
selector."cyrl/te.italic" = "serifless"
selector.mLTail = "earlessRoundedDoubleArchShortLeg"
[prime.m.variants.earless-rounded-double-arch-short-leg-serifed]
rank = 32
description = "Earless (rounded top-left) `m` with a shorter middle leg like Ubuntu Mono, and serifs"
selector.m = "earlessRoundedDoubleArchShortLegSerifed"
selector."m/tailless" = "earlessRoundedDoubleArchShortLegSerifed"
selector."m/sansSerif" = "earlessRoundedDoubleArchShortLeg"
selector."cyrl/te.italic" = "serifed"
selector.mLTail = "earlessRoundedDoubleArchShortLegSerifed"
[prime.m.variants.earless-rounded-double-arch-short-leg-tailed]
rank = 33
description = "Earless (rounded top-left) `m` with a shorter middle leg like Ubuntu Mono, and a curly tail"
selector.m = "earlessRoundedDoubleArchShortLegTailed"
selector."m/tailless" = "earlessRoundedDoubleArchShortLeg"
selector."m/sansSerif" = "earlessRoundedDoubleArchShortLegTailed"
selector."cyrl/te.italic" = "tailed"
selector.mLTail = "earlessRoundedDoubleArchShortLeg"
[prime.m.variants.earless-rounded-double-arch-short-leg-tailed-serifed]
rank = 34
description = "Earless (rounded top-left) `m` with a shorter middle leg like Ubuntu Mono, and a curly tail, and serifs"
selector.m = "earlessRoundedDoubleArchShortLegTailedSerifed"
selector."m/tailless" = "earlessRoundedDoubleArchShortLegSerifed"
selector."m/sansSerif" = "earlessRoundedDoubleArchShortLegTailed"
selector."cyrl/te.italic" = "tailedSerifed"
selector.mLTail = "earlessRoundedDoubleArchShortLegSerifed"
[prime.m.variants.earless-single-arch-short-leg]
rank = 35
description = "Earless (single-arch) `m` with a shorter middle leg like Ubuntu Mono"
selector.m = "earlessSingleArchShortLeg"
selector."m/tailless" = "earlessSingleArchShortLeg"
selector."m/sansSerif" = "earlessSingleArchShortLeg"
selector."cyrl/te.italic" = "serifless"
selector.mLTail = "earlessSingleArchShortLeg"
[prime.m.variants.earless-single-arch-short-leg-serifed]
rank = 36
description = "Earless (single-arch) `m` with a shorter middle leg like Ubuntu Mono, and serifs"
selector.m = "earlessSingleArchShortLegSerifed"
selector."m/tailless" = "earlessSingleArchShortLegSerifed"
selector."m/sansSerif" = "earlessSingleArchShortLeg"
selector."cyrl/te.italic" = "serifed"
selector.mLTail = "earlessSingleArchShortLegSerifed"
[prime.m.variants.earless-single-arch-short-leg-tailed]
rank = 37
description = "Earless (single-arch) `m` with a shorter middle leg like Ubuntu Mono, and a curly tail"
selector.m = "earlessSingleArchShortLegTailed"
selector."m/tailless" = "earlessSingleArchShortLeg"
selector."m/sansSerif" = "earlessSingleArchShortLegTailed"
selector."cyrl/te.italic" = "tailed"
selector.mLTail = "earlessSingleArchShortLeg"
[prime.m.variants.earless-single-arch-short-leg-tailed-serifed]
rank = 38
description = "Earless (single-arch) `m` with a shorter middle leg like Ubuntu Mono, and a curly tail, and serifs"
selector.m = "earlessSingleArchShortLegTailedSerifed"
selector."m/tailless" = "earlessSingleArchShortLegSerifed"
selector."m/sansSerif" = "earlessSingleArchShortLegTailed"
selector."cyrl/te.italic" = "tailedSerifed"
selector.mLTail = "earlessSingleArchShortLegSerifed"
[prime.m.variants-buildup.stages.serifs.serifed]
rank = 4
keySuffix = "serifed"
descriptionSuffix = "serifs"
selectorSuffix.m = "serifed"
selectorSuffix."m/tailless" = "serifed"
selectorSuffix."m/sansSerif" = "serifless"
selectorSuffix."cyrl/te.italic" = "serifed"
selectorSuffix.mLTail = "serifed"
@ -8895,7 +8685,7 @@ g = "earless-corner"
i = "tailed-serifed"
k = "symmetric-touching-serifless"
l = "tailed-serifed"
m = "earless-corner-double-arch-short-leg"
m = "earless-corner-double-arch-short-leg-serifless"
n = "earless-corner-straight-serifless"
p = "earless-corner-serifless"
q = "earless-corner-serifless"