diff --git a/README.md b/README.md index 8c5a7cce2..ecf2a0dd0 100644 --- a/README.md +++ b/README.md @@ -72,8 +72,8 @@ Since version 2.0, Iosevka would no longer support building via `makefile`. To i # Override default building weights # When buildPlans..weights is absent # All weights would built and mapped to default shape/CSS - # IMPORTANT : Currently "shape" property only support 100, 200, 300, 400, 500, 600, 700, 800, 900. - [buildPlans.iosevka-custom.weights.regular] + # IMPORTANT : Currently "menu" property only support 100, 200, 300, 400, 500, 600, 700, 800, 900. + # and "shape" properly only supports number between 100 and 900 (inclusive). shape = 400 # Weight for glyph shapes menu = 400 # Weight for menu name css = 400 # Weight for WebFont CSS diff --git a/build-plans.toml b/build-plans.toml index 418bb46c1..292dca361 100644 --- a/build-plans.toml +++ b/build-plans.toml @@ -512,7 +512,8 @@ distinguishSlant = false # Shape weight : affects the shape of the glyphs # Menu weight : affects the font menu name # CSS weight : affects the webfont CSS "font-weight" property -# IMPORTANT : Currently "shape" property only support 100, 200, 300, 400, 500, 600, 700, 800, 900. +# IMPORTANT : Currently "menu" property only support 100, 200, 300, 400, 500, 600, 700, 800, 900. +# and "shape" properly only supports number between 100 and 900 (inclusive). [weights.thin] shape = 100 @@ -573,6 +574,7 @@ italic = "italic" # CSS stretch : affects the webfont CSS "font-stretch" property # # IMPORTANT : Currently "shape" property only support 3, 5, and 7 +# and "menu" only support 1, 2, 3, 4, 5, 6, 7, 8, 9 [widths.normal] shape = 5 diff --git a/changes/3.0.0-beta.3.md b/changes/3.0.0-beta.3.md index 6f8868cee..ea87cb4df 100644 --- a/changes/3.0.0-beta.3.md +++ b/changes/3.0.0-beta.3.md @@ -1,4 +1,5 @@ * Made the curly-bar variant via OpenType tag `ss20`. * Alias U+2B95 to U+27A1. * Add symbol U+22DA, U+22DB, U+23B0, U+23B1, etc. -* Finished the unicode block that supports retro computer characters. \ No newline at end of file +* Finished the unicode block that supports retro computer characters. +* Building: The shape weight is now a continuous space. diff --git a/gen/generator.js b/gen/generator.js index b274194b6..5a4e48248 100644 --- a/gen/generator.js +++ b/gen/generator.js @@ -39,7 +39,7 @@ function getParameters(argv) { ); const variantData = tryParseToml(VARIANTS_TOML); - const para = parameters.build(parametersData, argv._); + const para = parameters.build(parametersData, argv._, { "shape-weight": argv["shape-weight"] }); const variantsData = formVariantData(variantData, para); para.variants = variantsData; para.variantSelector = parameters.build(variantsData, ["default", ...argv._]); diff --git a/glyphs/letters-unified-basic.ptl b/glyphs/letters-unified-basic.ptl index 40fb8784f..2ec4f0390 100644 --- a/glyphs/letters-unified-basic.ptl +++ b/glyphs/letters-unified-basic.ptl @@ -603,7 +603,7 @@ export : define [apply] : begin define { VShape VShapeOutline } : do "V, v and related ========================================" define cornerdist : HALFSTROKE * HVCONTRAST * 1.15 define vcurviness : if (SLAB && !para.isItalic) 0.15 0.3 - define VShapeFine : STROKE * [fallback para.vtipfine : if SLAB 0.9 0.8] + define VShapeFine : STROKE * [if SLAB para.vtipfineSlab para.vtipfine] define VShapeFineStraight : Math.max [adviceBlackness 7] [STROKE * 0.66] define VShapeMiddleWidth : adviceBlackness 3 define pInktrap 0.5 diff --git a/parameters.toml b/parameters.toml index 6d43fc2aa..1e4e3ecba 100644 --- a/parameters.toml +++ b/parameters.toml @@ -24,7 +24,6 @@ arrowSize = 1.50 pictSize = 1.10 contrast = 1.11111 # Stroke width contrast. -essx = 1.12 # Contrast of the middle of 'S'. slantAngle = 0 # Slant angle, in degrees. @@ -35,42 +34,8 @@ overshootx = -8 # Horizontal overshoot for arcs. oxhook = -2 # Horizontal overshoot for hook tips. fovershoot = -40 # Overshoot of the top end of italic `f`. -longjut = 175 # Length of long serifs, like that in `i`. -jut = 85 # Length of short serifs, used in Slab only. -vjut = 145 # Length of vertical serifs, used in Slab only. - -smooth = 195 # Vertical arc size in capital letters. -smallsmooth = 200 # Vertical arc size in lowercase letters. -smoothadjust = 120 # Parameter to balance arcs in slanted shapes. -superness = 2.2 # Superness of arcs. -tightHookSuperness = 2.3 # superness of tight hooks - -barpos = 0.525 # Position of the middle bar in most letters, like `E`. -overlaypos = 0.52 # Position of the overlay mark. -ebarpos = 0.50 # Position of the middle bar in `e`. -gbarpos = 0.42 -fivebarpos = 0.64 -fbarpos = 0.91 # Position of the middle bar in `f` -fbarStrokeAdj = 0.25 # Portion of the fill above the f-bar position - -hook = 155 # Hook depth in most letters. -ahook = 130 -shook = 110 -jhook = 135 -fhook = 120 -rhook = 110 -hookx = 170 - shoulderfineMin = 0.8 -tbalance = 50 -tbalance2 = 30 -rbalance = 60 -rbalance2 = 15 -jbalance = 63 -fbalance = 6 -onebalance = 30 - isItalic = false # Use italic shapes? isOblique = false # Use oblique shapes? @@ -102,114 +67,175 @@ enableLigation = true # Excluded code points excludedCodePointRanges = [] -[verbose] -verbose = true +[shape-weight.blend.400] +stroke = 72 # Primary stroke width +sb = 60 # Primary sidebearings +essx = 1.12 # Proportion of widen of center of "S" +dotsize = 125 # Size of dots +periodsize = 140 # Size of period -### Weights -[w-100] +jut = 85 # Length of slab serif +vjut = 145 # Length of vertical slab serif +longjut = 175 # Length of long serifs, like that in `i`. + +smooth = 195 # Vertical arc size in capital letters. +smallsmooth = 200 # Vertical arc size in lowercase letters. +smoothadjust = 120 # Parameter to balance arcs in slanted shapes. +superness = 2.2 # Superness of arcs. +tightHookSuperness = 2.3 # superness of tight hooks + +barpos = 0.525 # Position of most crossbars +overlaypos = 0.52 # Position of the overlay mark. +ebarpos = 0.50 # Position of the middle bar in `e`. +gbarpos = 0.42 +fivebarpos = 0.64 +fbarpos = 0.91 # Position of the middle bar in `f` +fbarStrokeAdj = 0.25 # Portion of the fill above the f-bar position + +rbalance = 60 +rbalance2 = 15 +tbalance = 50 +tbalance2 = 30 +jbalance = 63 +fbalance = 6 +onebalance = 30 + +hook = 155 # Hook depth in most letters. +ahook = 130 +shook = 110 +jhook = 135 +fhook = 120 +hookx = 170 +rhook = 110 + +cthin = 0.75 +cthinb = 0.5 +vtipfine = 0.8 +vtipfineSlab = 0.9 + +[shape-weight.blend.100] +jut = 85 +vjut = 145 +smooth = 195 +barpos = 0.525 +rhook = 110 +rbalance = 60 +rbalance2 = 15 +cthin = 0.9 +cthinb = 0.9 +vtipfine = 1 +vtipfineSlab = 1 stroke = 18 sb = 72 dotsize = 53 periodsize = 55 -cthin = 0.9 -cthinb = 0.9 +[shape-weight.blend.200] +jut = 85 +vjut = 145 +smooth = 195 +barpos = 0.525 +rhook = 110 +rbalance = 60 +rbalance2 = 15 +cthin = 0.75 +cthinb = 0.75 vtipfine = 1 - -[w-200] +vtipfineSlab = 1 stroke = 36 sb = 68 dotsize = 70 periodsize = 77 +[shape-weight.blend.300] +jut = 85 +vjut = 145 +smooth = 195 +barpos = 0.525 +rhook = 110 +rbalance = 60 +rbalance2 = 15 cthin = 0.75 -cthinb = 0.75 -vtipfine = 1 - -[w-300] +cthinb = 0.5 +vtipfine = 0.9 +vtipfineSlab = 0.9 stroke = 56 sb = 64 dotsize = 100 periodsize = 115 -vtipfine = 0.9 - -[w-400] -sb = 60 # Side bearing. -stroke = 72 # Stroke width of horizontal strokes. -dotsize = 125 # "Visual" size of dots in /i. -periodsize = 140 # "Visual" size of period. - -[w-500] -sb = 57 +[shape-weight.blend.500] +essx = 1.12 +jut = 85 +vjut = 157 +smooth = 200 +barpos = 0.525 +rhook = 110 +rbalance = 60 +rbalance2 = 15 stroke = 84 +sb = 57 dotsize = 135 periodsize = 160 -smooth = 200 -vjut = 157 -[w-600] -sb = 54 -stroke = 97 -dotsize = 145 -periodsize = 168 +[shape-weight.blend.600] essx = 1.07 +jut = 85 vjut = 170 - +smooth = 203 +barpos = 0.525 +rhook = 110 rbalance = 55 rbalance2 = 20 -smooth = 203 +stroke = 97 +sb = 54 +dotsize = 145 +periodsize = 168 -[w-700] -sb = 50 -stroke = 106 -dotsize = 157 -periodsize = 180 +[shape-weight.blend.700] essx = 1.06 -essxq = 1.10 jut = 89 vjut = 179 - +smooth = 206 barpos = 0.51 -fivebarpos = 0.64 +rhook = 95 rbalance = 52 rbalance2 = 23 -rhook = 95 -smooth = 206 +stroke = 106 +sb = 50 +dotsize = 157 +periodsize = 180 -[w-800] -sb = 45 -stroke = 116 -dotsize = 167 -periodsize = 188 +[shape-weight.blend.800] essx = 1.05 -essxq = 1.15 jut = 96 vjut = 189 - +smooth = 210 barpos = 0.51 -fivebarpos = 0.64 +rhook = 97 rbalance = 50 rbalance2 = 25 -rhook = 97 -smooth = 210 +stroke = 116 +sb = 45 +dotsize = 167 +periodsize = 188 -[w-900] -sb = 42 -stroke = 126 -dotsize = 180 -periodsize = 200 +[shape-weight.blend.900] essx = 1.03 -essxq = 1.15 jut = 100 vjut = 199 - +smooth = 215 barpos = 0.51 -fivebarpos = 0.64 +rhook = 105 rbalance = 50 rbalance2 = 25 -rhook = 105 -smooth = 215 +stroke = 126 +sb = 42 +dotsize = 180 +periodsize = 200 + +[verbose] +verbose = true ### Slantness [s-italic] diff --git a/private-build-plans.sample.toml b/private-build-plans.sample.toml index 25de86b4d..b997a8552 100644 --- a/private-build-plans.sample.toml +++ b/private-build-plans.sample.toml @@ -7,7 +7,8 @@ hintParams = ["-a", "sss"] # Optional custom parameters # Override default building weights # When buildPlans..weights is absent # All weights would built and mapped to default shape/CSS -# IMPORTANT : Currently "shape" property only support 100, 200, 300, 400, 500, 600, 700, 800, 900. +# IMPORTANT : Currently "menu" property only support 100, 200, 300, 400, 500, 600, 700, 800, 900. +# and "shape" properly only supports number between 100 and 900 (inclusive). [buildPlans.iosevka-custom.weights.regular] shape = 400 # Weight for glyph shapes menu = 400 # Weight for menu name diff --git a/support/param-blend.js b/support/param-blend.js new file mode 100644 index 000000000..3781f03a7 --- /dev/null +++ b/support/param-blend.js @@ -0,0 +1,28 @@ +const blend = require("./monotonic-interpolate"); + +module.exports = function(aspect, hive, params, sink) { + if (!hive || !hive.blend || !params) return; + + const block = hive.blend; + let keys = new Set(); + for (const grade in block) { + if (!isFinite(parseFloat(grade))) continue; + for (const key in block[grade]) { + if (block[grade][key] == null) continue; + keys.add(key); + } + } + + for (const key of keys) { + let xs = [], + ys = []; + for (const grade in block) { + if (!isFinite(parseFloat(grade))) continue; + if (block[grade][key] == null) continue; + xs.push(grade); + ys.push(block[grade][key]); + } + const fn = blend(xs, ys); + sink[key] = fn(params[aspect]); + } +}; diff --git a/support/parameters.ptl b/support/parameters.ptl index 8deb31aa0..df1829d1b 100644 --- a/support/parameters.ptl +++ b/support/parameters.ptl @@ -1,17 +1,20 @@ -export : define [build parametersData styles] : begin - local param {.} - - define [introStyle style] : begin - local hive parametersData.(style) - if (!hive) : return nothing - if hive.inherits : foreach [h : items-of hive.inherits] : introStyle h - foreach [k : items-of : Object.keys hive] : set param.(k) hive.(k) - if hive.multiplies : foreach [k : items-of : Object.keys hive.multiplies] : begin - set param.(k) : param.(k) * hive.multiplies.(k) - if hive.adds : foreach [k : items-of : Object.keys hive.adds] : begin - set param.(k) : param.(k) + hive.adds.(k) - if hive.appends : foreach [k : items-of : Object.keys hive.appends] : begin - set param.(k) : (param.(k) || {}).concat(hive.appends.(k)) - - foreach [style : items-of styles] : introStyle style - return param +import "./param-blend" as paramBlend + +export : define [build parametersData styles blendParams] : begin + local param {.} + + define [introStyle style] : begin + local hive parametersData.(style) + if (!hive) : return nothing + if hive.inherits : foreach [h : items-of hive.inherits] : introStyle h + foreach [k : items-of : Object.keys hive] : set param.(k) hive.(k) + if hive.multiplies : foreach [k : items-of : Object.keys hive.multiplies] : begin + set param.(k) : param.(k) * hive.multiplies.(k) + if hive.adds : foreach [k : items-of : Object.keys hive.adds] : begin + set param.(k) : param.(k) + hive.adds.(k) + if hive.appends : foreach [k : items-of : Object.keys hive.appends] : begin + set param.(k) : (param.(k) || {}).concat(hive.appends.(k)) + paramBlend style hive blendParams param + + foreach [style : items-of styles] : introStyle style + return param diff --git a/verdafile.js b/verdafile.js index fecb02e22..63a9257fe 100644 --- a/verdafile.js +++ b/verdafile.js @@ -128,6 +128,25 @@ function makeSuffix(w, wd, s, fallback) { ); } +function nValidate(key, v, f) { + if (typeof v !== "number" || !isFinite(v) || (f && !f(v))) { + throw new TypeError(`${key} = "${v}" is not a valid number.`); + } + return v; +} +function vlShapeWeight(x) { + return x >= 100 && x <= 900; +} +function vlMenuWeight(x) { + return x >= 100 && x <= 900 && x % 100 === 0; +} +function vlShapeWidth(x) { + return x === 3 || x === 5 || x === 7; +} +function vlMenuWidth(x) { + return x >= 1 && x <= 9 && x % 1 === 0; +} + function getSuffixSet(weights, slants, widths) { const mapping = {}; for (const w in weights) { @@ -135,13 +154,15 @@ function getSuffixSet(weights, slants, widths) { for (const wd in widths) { const suffix = makeSuffix(w, wd, s, "regular"); mapping[suffix] = { - hives: [`w-${weights[w].shape}`, `s-${s}`, `wd-${widths[wd].shape}`], + hives: [`shape-weight`, `s-${s}`, `wd-${widths[wd].shape}`], weight: w, - cssWeight: weights[w].css || w, - menuWeight: weights[w].menu || weights[w].css || w, + shapeWeight: nValidate("Shape weight of " + w, weights[w].shape, vlShapeWeight), + cssWeight: nValidate("CSS weight of " + w, weights[w].css), + menuWeight: nValidate("Menu weight of " + w, weights[w].menu, vlMenuWeight), width: wd, + shapeWidth: nValidate("Shape width of " + wd, widths[wd].shape, vlShapeWidth), cssStretch: widths[wd].css || wd, - menuWidth: widths[wd].menu || widths[wd].css || wd, + menuWidth: nValidate("Menu width of " + wd, widths[wd].menu, vlMenuWidth), slant: s, cssStyle: slants[s] || s, menuStyle: slants[s] || s @@ -184,6 +205,8 @@ const FontBuildingParameters = computed(`metadata:font-building-parameters`, asy name: fileName, family, hives: ["iosevka", ...preHives, ...suffixMapping[suffix].hives, ...postHives], + shapeWeight: suffixMapping[suffix].shapeWeight, + shapeWidth: suffixMapping[suffix].shapeWidth, menuWeight: suffixMapping[suffix].menuWeight, menuWidth: suffixMapping[suffix].menuWidth, menuStyle: suffixMapping[suffix].menuStyle, @@ -289,10 +312,10 @@ const CollectionPartsOf = computed.group("metadata:collection-parts-of", async ( const BuildTTF = file.make( (gr, fn) => `${BUILD}/${gr}/${fn}.ttf`, async (target, output, _gr, fn) => { - const [{ hives, family, menuWeight, menuStyle, menuWidth }, version] = await target.need( - HivesOf(fn), - Version - ); + const [ + { hives, family, shapeWeight, menuWeight, menuStyle, menuWidth }, + version + ] = await target.need(HivesOf(fn), Version); const otd = output.dir + "/" + output.name + ".otd"; const ttfTmp = output.dir + "/" + output.name + ".tmp.ttf"; const otdTmp = output.dir + "/" + output.name + ".tmp.otd"; @@ -304,6 +327,7 @@ const BuildTTF = file.make( ["--charmap", charmap], ["--family", family], ["--ver", version], + ["--shape-weight", shapeWeight], ["--menu-weight", menuWeight], ["--menu-slant", menuStyle], ["--menu-width", menuWidth],