Sans 0.2: italic Cyrillic, OTF hinting, Latin Extended-A, kerning fixes

RI
6h ago
+17379-299

Summary

machine-made Sans 0.2 (font version 0.200). All changes are made by the scripts from the pinned upstream sources (sans/scripts/fork.py, new sans/scripts/extend.py); no binary or outline is edited by hand. Fonts rebuilt and committed.

  • Italic Cyrillic. The italic gets the 98 Cyrillic code points of the upright. The upstream Latin italic is the upright slanted 8° about half the x-height with the same widths (H, E, n match to under 1 unit), so the italic Cyrillic is made the same way: outlines and anchors slanted, components kept (а е о р с у х і ј ѕ use the italic Latin glyphs), mirrored components (Я Э Є є) turned into outlines first. Bulgarian forms (locl BGR, ss04) work in the italic. It is a sloped roman like the Latin: и п т keep their upright forms.
  • Hinting. Static OTF are now hinted with otfautohint (afdko 5.0.1, run in a Python 3.13 venv because afdko has no 3.14 wheel; sans/requirements-otf.txt). The upright source gets the italic's stem values. The CFF is subroutinized again with cffsubr 0.4.0 (pinned). Static TTF stay on ttfautohint. Variable fonts are left unhinted: ttfautohint-vf is unmaintained and has no pinned release (reasons in sans/STATUS.md).
  • Style names in Word. Italic VF instances renamed XLight Italic, SemiBd Italic, XBold Italic (≤ 32 characters with the family). STAT keeps the full names. The Fontspector override is removed.
  • Latin Extended-A + Șș Țț complete. New: ſ (the upstream f without its crossbar) and ʼn (quoteright + n).
  • Kerning. sans/scripts/kernaudit.py measures 11,610 pairs. 47 upright and 31 italic exceptions (accented i after T V W Y F f P, Ľ before T V W X Y, Cyrillic ї, italic Yř), each the smallest value that leaves 20 units between the inks. Cyrillic look-alikes get the Latin kerning groups. Overlapping pairs across the 14 statics: 326 → 0.
  • Docs. sans/STATUS.md, CHANGELOG.md, RELEASE-NOTES-0.2.md, README.md. OFL FAQ 5.10 confirmed on openfontlicense.org (RFN page). The CSS size-adjust to match Weft's nominal x-height is 93.3 %; outlines are not scaled.
  • CI / release. sans.yml and the sans job in release.yml install Python 3.13 next to 3.14 for otfautohint; sans.yml also runs the OCR gate.
  • Site. Sans page, home and download point to sans-v0.2.0; a "New in 0.2" section with an italic Cyrillic line.

Effect on machine-made.github.io (not edited): no advance width, word space or metric change. GPOS differs in 9 Latin-1 pairs (Fì Fî Tì Vì Wì Yì fì ¥ì Ýì). src/style.css and brand.py need no change; regenerate mm-sans.woff2 with fonts.py when the site takes 0.2.

Checks

  • Build: two builds give the same bytes (hinting included).
  • pytest sans/tests: 249 passed.
  • Fontspector 1.9.0 universal: 0 FAIL, 0 ERROR (variable 182 PASS / 9 WARN, TTF 1002 / 46, OTF 890 / 46, WOFF2 10 / 0). Accepted WARNs listed in sans/STATUS.md.
  • varLib.interpolatable on both master sets: no problems.
  • OCR gate (Tesseract 5.3.4): Regular CER 0.0350 (0.1: 0.0350), Italic 0.0439 (0.1: 0.0439). DejaVu Sans 0.0073 / 0.0106 for reference.
  • Site: build passes; Chromium at 360 and 1366 px: no external requests, no horizontal scroll, both Sans fonts load.

Review

Please look at:

  • proofs/sans/sans-italic-cyrillic.png: upright and italic Cyrillic at 400 and 800, and the check of the slant method on Latin.
  • proofs/sans/sans-kerning.png: before and after.
  • proofs/sans/sans-coverage.png: Latin Extended-A and comma below.
  • proofs/sans/sans-hinting-otf.png: OTF at 9 to 14 px, 0.1 against 0.2.
  • Decisions to confirm: italic Cyrillic as a sloped roman (no cursive и п т by default); short italic names XLight / SemiBd / XBold; variable fonts unhinted.

Generated by Claude Code