Last active
June 30, 2023 14:20
-
-
Save arrowtype/47937ba868b0b2a49e80684319e56037 to your computer and use it in GitHub Desktop.
A script to help sync spacing & shaping for support sources within a large designspace.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version='1.0' encoding='UTF-8'?> | |
<designspace format="5.0"> | |
<axes elidedfallbackname="Regular"> | |
<axis tag="opsz" name="Optical Size" minimum="8" maximum="72" default="8"> | |
<labelname xml:lang="en">Optical Size</labelname> | |
<map input="72" output="72"/> | |
<map input="20" output="40"/> | |
<map input="8" output="8" name="Text" elidable="true"/> | |
</axis> | |
<axis tag="wght" name="Weight" minimum="1" maximum="1000" default="700"> | |
<labelname xml:lang="en">Weight</labelname> | |
<labels> | |
<label uservalue="25" name="Hairline" /> | |
<label uservalue="50" name="ExtraThin" /> | |
<label uservalue="100" name="Thin" /> | |
<label uservalue="200" name="ExtraLight" /> | |
<label uservalue="300" name="Light" /> | |
<label uservalue="400" name="Regular" linkeduservalue="700" elidable="true"/> | |
<label uservalue="500" name="Medium" /> | |
<label uservalue="600" name="SemiBold" /> | |
<label uservalue="700" name="Bold" linkeduservalue="400"/> | |
<label uservalue="800" name="ExtraBold" /> | |
<label uservalue="900" name="Black" /> | |
<label uservalue="1000" name="Ultra" /> | |
</labels> | |
<map input="1000" output="1000"/> | |
<map input="900" output="850"/> | |
<map input="800" output="775"/> | |
<map input="700" output="700"/> | |
<map input="600" output="600"/> | |
<map input="500" output="500"/> | |
<map input="400" output="400"/> | |
<map input="300" output="300"/> | |
<map input="200" output="200"/> | |
<map input="100" output="100"/> | |
<map input="50" output="50"/> | |
<map input="1" output="1"/> | |
</axis> | |
<axis name="Italic" tag="ital" default="0" values="0 1"> | |
<labels> | |
<label uservalue="0" name="Roman" elidable="true" /> | |
<label uservalue="1" name="Italic" /> | |
</labels> | |
</axis> | |
</axes> | |
<variable-fonts> | |
<variable-font name="AT-NameSansVariable"> | |
<axis-subsets> | |
<axis-subset name="Optical Size"/> | |
<axis-subset name="Weight"/> | |
<axis-subset name="Italic" uservalue="0"/> | |
</axis-subsets> | |
</variable-font> | |
<variable-font name="AT-NameSansVariable-Italic"> | |
<axis-subsets> | |
<axis-subset name="Optical Size"/> | |
<axis-subset name="Weight"/> | |
<axis-subset name="Italic" uservalue="1"/> | |
</axis-subsets> | |
</variable-font> | |
</variable-fonts> | |
<rules> | |
<rule name="Italic a"> | |
<conditionset> | |
<condition name="Italic" minimum="1" maximum="1"/> | |
</conditionset> | |
<sub name="a" with="a.italic"/> | |
<sub name="agrave" with="agrave.italic"/> | |
<sub name="aacute" with="aacute.italic"/> | |
<sub name="acircumflex" with="acircumflex.italic"/> | |
<sub name="atilde" with="atilde.italic"/> | |
<sub name="adieresis" with="adieresis.italic"/> | |
<sub name="aring" with="aring.italic"/> | |
<sub name="amacron" with="amacron.italic"/> | |
<sub name="abreve" with="abreve.italic"/> | |
<sub name="aogonek" with="aogonek.italic"/> | |
<sub name="acaron" with="acaron.italic"/> | |
<sub name="adotbelow" with="adotbelow.italic"/> | |
<sub name="ahook" with="ahook.italic"/> | |
<sub name="acircumflexacute" with="acircumflexacute.italic"/> | |
<sub name="acircumflexgrave" with="acircumflexgrave.italic"/> | |
<sub name="acircumflexhook" with="acircumflexhook.italic"/> | |
<sub name="acircumflextilde" with="acircumflextilde.italic"/> | |
<sub name="acircumflexdot" with="acircumflexdot.italic"/> | |
<sub name="abreveacute" with="abreveacute.italic"/> | |
<sub name="abrevegrave" with="abrevegrave.italic"/> | |
<sub name="abrevehook" with="abrevehook.italic"/> | |
<sub name="abrevetilde" with="abrevetilde.italic"/> | |
<sub name="abrevedot" with="abrevedot.italic"/> | |
</rule> | |
<rule name="Default R in Display"> | |
<conditionset> | |
<condition name="Weight" minimum="1" maximum="1000"/> | |
<condition name="Optical Size" minimum="55.999990" maximum="72"/> | |
</conditionset> | |
<sub name="R" with="R.default"/> | |
<sub name="Rcedilla" with="Rcedilla.default"/> | |
<sub name="Racute" with="Racute.default"/> | |
<sub name="Rcaron" with="Rcaron.default"/> | |
</rule> | |
<rule name="Open Rounds"> | |
<conditionset> | |
<condition name="Weight" minimum="728" maximum="1000"/> | |
<condition name="Optical Size" minimum="8" maximum="72"/> | |
</conditionset> | |
<sub name="Q" with="Q.open"/> | |
<sub name="Oslash" with="Oslash.open"/> | |
<sub name="Oslashacute" with="Oslashacute.open"/> | |
<sub name="Q.RECT" with="Q.RECT_open"/> | |
<sub name="Oslash.RECT" with="Oslash.RECT_open"/> | |
<sub name="Oslashacute.RECT" with="Oslashacute.RECT_open"/> | |
<sub name="oslash" with="oslash.open"/> | |
<sub name="oslashacute" with="oslashacute.open"/> | |
</rule> | |
<rule name="Open Dollar"> | |
<conditionset> | |
<condition name="Weight" minimum="550" maximum="1000"/> | |
<condition name="Optical Size" minimum="8" maximum="72"/> | |
</conditionset> | |
<sub name="dollar" with="dollar.open"/> | |
<sub name="cent" with="cent.open"/> | |
</rule> | |
<rule name="Ultra Alts"> | |
<conditionset> | |
<condition name="Weight" minimum="928" maximum="1000"/> | |
<condition name="Optical Size" minimum="8" maximum="72"/> | |
</conditionset> | |
<sub name="l" with="l.text"/> | |
<sub name="lslash" with="lslash.text"/> | |
<sub name="lacute" with="lacute.text"/> | |
<sub name="lcedilla" with="lcedilla.text"/> | |
<sub name="lcedilla" with="lcedilla.text"/> | |
<sub name="ldot" with="ldot.text"/> | |
<sub name="l_periodcentered_l.loclCAT" with="l_periodcentered_l.text.loclCAT"/> | |
</rule> | |
<rule name="Ultra T"> | |
<conditionset> | |
<condition name="Weight" minimum="781" maximum="1000"/> | |
<condition name="Optical Size" minimum="55.999990" maximum="72"/> | |
</conditionset> | |
<sub name="T" with="T.ultra"/> | |
<sub name="Tcaron" with="Tcaron.ultra"/> | |
</rule> | |
<rule name="Hairline Alts"> | |
<conditionset> | |
<condition name="Weight" minimum="1" maximum="350"/> | |
<condition name="Optical Size" minimum="8" maximum="72"/> | |
</conditionset> | |
<sub name="paragraph" with="paragraph.light"/> | |
<sub name="won" with="won.light"/> | |
</rule> | |
<rule name="Text Alts"> | |
<conditionset> | |
<condition name="Weight" minimum="1" maximum="1000"/> | |
<condition name="Optical Size" minimum="8" maximum="39.999990"/> | |
</conditionset> | |
<sub name="g" with="g.default"/> | |
<sub name="gbreve" with="gbreve.default"/> | |
<sub name="gcedilla" with="gcedilla.default"/> | |
<sub name="l" with="l.default"/> | |
<sub name="lcaron" with="lcaron.default"/> | |
<sub name="lslash" with="lslash.default"/> | |
<sub name="lacute" with="lacute.default"/> | |
<sub name="lcedilla" with="lcedilla.default"/> | |
<sub name="ldot" with="ldot.default"/> | |
<sub name="l_periodcentered_l.loclCAT" with="l_periodcentered_l.default.loclCAT"/> | |
<sub name="I" with="I.default"/> | |
<sub name="Igrave" with="Igrave.default"/> | |
<sub name="Iacute" with="Iacute.default"/> | |
<sub name="Icircumflex" with="Icircumflex.default"/> | |
<sub name="Idieresis" with="Idieresis.default"/> | |
<sub name="Itilde" with="Itilde.default"/> | |
<sub name="Imacron" with="Imacron.default"/> | |
<sub name="Ibreve" with="Ibreve.default"/> | |
<sub name="Idotaccent" with="Idotaccent.default"/> | |
<sub name="Ihook" with="Ihook.default"/> | |
<sub name="Idotbelow" with="Idotbelow.default"/> | |
<sub name="Iogonek" with="Iogonek.default"/> | |
</rule> | |
<rule name="90deg Ones"> | |
<conditionset> | |
<condition name="Weight" minimum="350" maximum="1000"/> | |
<condition name="Optical Size" minimum="8" maximum="72"/> | |
</conditionset> | |
<sub name="one" with="one.90deg"/> | |
<sub name="one.tnum" with="one.90deg_tnum"/> | |
<sub name="one.onum" with="one.90deg_onum"/> | |
</rule> | |
<rule name="Bold y"> | |
<conditionset> | |
<condition name="Weight" minimum="550" maximum="1000"/> | |
<condition name="Optical Size" minimum="62" maximum="72"/> | |
</conditionset> | |
<sub name="y" with="y.bold"/> | |
<sub name="yacute" with="yacute.bold"/> | |
<sub name="ydieresis" with="ydieresis.bold"/> | |
<sub name="ygrave" with="ygrave.bold"/> | |
<sub name="ydotbelow" with="ydotbelow.bold"/> | |
<sub name="yhookabove" with="yhookabove.bold"/> | |
<sub name="ytilde" with="ytilde.bold"/> | |
</rule> | |
</rules> | |
<sources> | |
<source filename="Name_Sans-Display_Hairline.ufo" familyname="AT Name Sans" stylename="Display Hairline"> | |
<location> | |
<dimension name="Weight" xvalue="1"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<source filename="sparse--Name_Sans-Display_100.ufo" familyname="AT Name Sans" stylename="Display Thin"> | |
<location> | |
<dimension name="Weight" xvalue="100"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<source filename="sparse--Name_Sans-Display_200.ufo" familyname="AT Name Sans" stylename="Display ExtraLight"> | |
<location> | |
<dimension name="Weight" xvalue="200"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<source filename="sparse--Name_Sans-Display_500.ufo" familyname="AT Name Sans" stylename="Display Medium"> | |
<location> | |
<dimension name="Weight" xvalue="500"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<source filename="Name_Sans-Display_Bold.ufo" familyname="AT Name Sans" stylename="Display Bold"> | |
<lib copy="1"/> | |
<groups copy="1"/> | |
<features copy="1"/> | |
<info copy="1"/> | |
<location> | |
<dimension name="Weight" xvalue="700"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<source filename="sparse--Name_Sans-Display_800.ufo" familyname="AT Name Sans" stylename="Display ExtraBold"> | |
<location> | |
<dimension name="Weight" xvalue="800"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<source filename="Name_Sans-Display_Ultra.ufo" familyname="AT Name Sans" stylename="Display Ultra"> | |
<location> | |
<dimension name="Weight" xvalue="1000"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<source filename="Name_Sans-Text_Hairline.ufo" familyname="AT Name Sans" stylename="Text Hairline"> | |
<location> | |
<dimension name="Weight" xvalue="1"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<source filename="sparse--Name_Sans-Text_100.ufo" familyname="AT Name Sans" stylename="Text Thin"> | |
<location> | |
<dimension name="Weight" xvalue="100"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<source filename="sparse--Name_Sans-Text_200.ufo" familyname="AT Name Sans" stylename="Text ExtraLight"> | |
<location> | |
<dimension name="Weight" xvalue="200"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<source filename="sparse--Name_Sans-Text_500.ufo" familyname="AT Name Sans" stylename="Text Medium"> | |
<location> | |
<dimension name="Weight" xvalue="500"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<source filename="Name_Sans-Text_Bold.ufo" familyname="AT Name Sans" stylename="Text Bold"> | |
<location> | |
<dimension name="Weight" xvalue="700"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<source filename="Name_Sans-Text_Ultra.ufo" familyname="AT Name Sans" stylename="Text Ultra"> | |
<location> | |
<dimension name="Weight" xvalue="1000"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
</source> | |
<!-- ITALICS --> | |
<source filename="italic/Name_Sans-Display_Hairline_Italic.ufo" familyname="AT Name Sans" stylename="Display Hairline Italic"> | |
<location> | |
<dimension name="Weight" xvalue="1"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
<source filename="italic/sparse--Name_Sans-Display_100_Italic.ufo" familyname="AT Name Sans" stylename="Display Thin Italic"> | |
<location> | |
<dimension name="Weight" xvalue="100"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
<source filename="italic/sparse--Name_Sans-Display_200_Italic.ufo" familyname="AT Name Sans" stylename="Display ExtraLight Italic"> | |
<location> | |
<dimension name="Weight" xvalue="200"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
<source filename="italic/sparse--Name_Sans-Display_500_Italic.ufo" familyname="AT Name Sans" stylename="Display Medium Italic"> | |
<location> | |
<dimension name="Weight" xvalue="500"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
<source filename="italic/Name_Sans-Display_Bold_Italic.ufo" familyname="AT Name Sans" stylename="Display Bold Italic"> | |
<location> | |
<dimension name="Weight" xvalue="700"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
<source filename="italic/sparse--Name_Sans-Display_800_Italic.ufo" familyname="AT Name Sans" stylename="Display ExtraBold Italic"> | |
<location> | |
<dimension name="Weight" xvalue="800"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
<source filename="italic/Name_Sans-Display_Ultra_Italic.ufo" familyname="AT Name Sans" stylename="Display Ultra Italic"> | |
<location> | |
<dimension name="Weight" xvalue="1000"/> | |
<dimension name="Optical Size" xvalue="72"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
<source filename="italic/Name_Sans-Text_Hairline_Italic.ufo" familyname="AT Name Sans" stylename="Text Hairline Italic"> | |
<location> | |
<dimension name="Weight" xvalue="1"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
<source filename="italic/sparse--Name_Sans-Text_100_Italic.ufo" familyname="AT Name Sans" stylename="Text Thin Italic"> | |
<location> | |
<dimension name="Weight" xvalue="100"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
<source filename="italic/sparse--Name_Sans-Text_200_Italic.ufo" familyname="AT Name Sans" stylename="Text ExtraLight Italic"> | |
<location> | |
<dimension name="Weight" xvalue="200"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
<source filename="italic/sparse--Name_Sans-Text_500_Italic.ufo" familyname="AT Name Sans" stylename="Text Medium Italic"> | |
<location> | |
<dimension name="Weight" xvalue="500"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
<source filename="italic/Name_Sans-Text_Bold_Italic.ufo" familyname="AT Name Sans" stylename="Text Bold Italic"> | |
<location> | |
<dimension name="Weight" xvalue="700"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
<source filename="italic/Name_Sans-Text_Ultra_Italic.ufo" familyname="AT Name Sans" stylename="Text Ultra Italic"> | |
<location> | |
<dimension name="Weight" xvalue="1000"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</source> | |
</sources> | |
<instances> | |
<instance familyname="AT Name Sans Variable" stylename="Hairline" filename="instances/AT-NameSansVariable-Hairline.ufo" postscriptfontname="ATNameSansVariable-Hairline" stylemapstylename="regular" stylemapfamilyname="AT Name Sans Variable Hairline"> | |
<location> | |
<dimension name="Weight" xvalue="25"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="ExtraThin" filename="instances/AT-NameSansVariable-ExtraThin.ufo" postscriptfontname="ATNameSansVariable-ExtraThin" stylemapstylename="regular" stylemapfamilyname="AT Name Sans Variable ExtraThin"> | |
<location> | |
<dimension name="Weight" xvalue="50"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Thin" filename="instances/AT-NameSansVariable-Thin.ufo" postscriptfontname="ATNameSansVariable-Thin" stylemapstylename="regular" stylemapfamilyname="AT Name Sans Variable Thin"> | |
<location> | |
<dimension name="Weight" xvalue="100"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="ExtraLight" filename="instances/AT-NameSansVariable-ExtraLight.ufo" postscriptfontname="ATNameSansVariable-ExtraLight" stylemapstylename="regular" stylemapfamilyname="AT Name Sans Variable ExtraLight"> | |
<location> | |
<dimension name="Weight" xvalue="200"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Light" filename="instances/AT-NameSansVariable-Light.ufo" postscriptfontname="ATNameSansVariable-Light" stylemapstylename="regular" stylemapfamilyname="AT Name Sans Variable Light"> | |
<location> | |
<dimension name="Weight" xvalue="300"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Regular" filename="instances/AT-NameSansVariable-Regular.ufo" postscriptfontname="ATNameSansVariable-Regular" stylemapstylename="regular" stylemapfamilyname="AT Name Sans Variable"> | |
<location> | |
<dimension name="Weight" xvalue="400"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Medium" filename="instances/AT-NameSansVariable-Medium.ufo" postscriptfontname="ATNameSansVariable-Medium" stylemapstylename="regular" stylemapfamilyname="AT Name Sans Variable Medium"> | |
<location> | |
<dimension name="Weight" xvalue="500"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="SemiBold" filename="instances/AT-NameSansVariable-SemiBold.ufo" postscriptfontname="ATNameSansVariable-SemiBold" stylemapstylename="regular" stylemapfamilyname="AT Name Sans Variable SemiBold"> | |
<location> | |
<dimension name="Weight" xvalue="600"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Bold" filename="instances/AT-NameSansVariable-Bold.ufo" postscriptfontname="ATNameSansVariable-Bold" stylemapstylename="bold" stylemapfamilyname="AT Name Sans Variable"> | |
<location> | |
<dimension name="Weight" xvalue="700"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="ExtraBold" filename="instances/AT-NameSansVariable-ExtraBold.ufo" postscriptfontname="ATNameSansVariable-ExtraBold" stylemapstylename="regular" stylemapfamilyname="AT Name Sans Variable ExtraBold"> | |
<location> | |
<dimension name="Weight" xvalue="775"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Black" filename="instances/AT-NameSansVariable-Black.ufo" postscriptfontname="ATNameSansVariable-Black" stylemapstylename="regular" stylemapfamilyname="AT Name Sans Variable Black"> | |
<location> | |
<dimension name="Weight" xvalue="850"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Ultra" filename="instances/AT-NameSansVariable-Ultra.ufo" postscriptfontname="ATNameSansVariable-Ultra" stylemapstylename="regular" stylemapfamilyname="AT Name Sans Variable Ultra"> | |
<location> | |
<dimension name="Weight" xvalue="1000"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="0"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Hairline Italic" filename="instances/AT-NameSansVariable-HairlineItalic.ufo" postscriptfontname="ATNameSansVariable-HairlineItalic" stylemapstylename="italic" stylemapfamilyname="AT Name Sans Variable Hairline"> | |
<location> | |
<dimension name="Weight" xvalue="25"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="ExtraThin Italic" filename="instances/AT-NameSansVariable-ExtraThinItalic.ufo" postscriptfontname="ATNameSansVariable-ExtraThinItalic" stylemapstylename="italic" stylemapfamilyname="AT Name Sans Variable ExtraThin"> | |
<location> | |
<dimension name="Weight" xvalue="50"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Thin Italic" filename="instances/AT-NameSansVariable-ThinItalic.ufo" postscriptfontname="ATNameSansVariable-ThinItalic" stylemapstylename="italic" stylemapfamilyname="AT Name Sans Variable Thin"> | |
<location> | |
<dimension name="Weight" xvalue="100"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="ExtraLight Italic" filename="instances/AT-NameSansVariable-ExtraLightItalic.ufo" postscriptfontname="ATNameSansVariable-ExtraLightItalic" stylemapstylename="italic" stylemapfamilyname="AT Name Sans Variable ExtraLight"> | |
<location> | |
<dimension name="Weight" xvalue="200"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Light Italic" filename="instances/AT-NameSansVariable-LightItalic.ufo" postscriptfontname="ATNameSansVariable-LightItalic" stylemapstylename="italic" stylemapfamilyname="AT Name Sans Variable Light"> | |
<location> | |
<dimension name="Weight" xvalue="300"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Italic" filename="instances/AT-NameSansVariable-RegularItalic.ufo" postscriptfontname="ATNameSansVariable-RegularItalic" stylemapstylename="italic" stylemapfamilyname="AT Name Sans Variable"> | |
<location> | |
<dimension name="Weight" xvalue="400"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Medium Italic" filename="instances/AT-NameSansVariable-MediumItalic.ufo" postscriptfontname="ATNameSansVariable-MediumItalic" stylemapstylename="italic" stylemapfamilyname="AT Name Sans Variable Medium"> | |
<location> | |
<dimension name="Weight" xvalue="500"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="SemiBold Italic" filename="instances/AT-NameSansVariable-SemiBoldItalic.ufo" postscriptfontname="ATNameSansVariable-SemiBoldItalic" stylemapstylename="italic" stylemapfamilyname="AT Name Sans Variable SemiBold"> | |
<location> | |
<dimension name="Weight" xvalue="600"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Bold Italic" filename="instances/AT-NameSansVariable-BoldItalic.ufo" postscriptfontname="ATNameSansVariable-BoldItalic" stylemapstylename="bold italic" stylemapfamilyname="AT Name Sans Variable"> | |
<location> | |
<dimension name="Weight" xvalue="700"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="ExtraBold Italic" filename="instances/AT-NameSansVariable-ExtraBoldItalic.ufo" postscriptfontname="ATNameSansVariable-ExtraBoldItalic" stylemapstylename="italic" stylemapfamilyname="AT Name Sans Variable ExtraBold"> | |
<location> | |
<dimension name="Weight" xvalue="775"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Black Italic" filename="instances/AT-NameSansVariable-BlackItalic.ufo" postscriptfontname="ATNameSansVariable-BlackItalic" stylemapstylename="italic" stylemapfamilyname="AT Name Sans Variable Black"> | |
<location> | |
<dimension name="Weight" xvalue="850"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
<instance familyname="AT Name Sans Variable" stylename="Ultra Italic" filename="instances/AT-NameSansVariable-UltraItalic.ufo" postscriptfontname="ATNameSansVariable-UltraItalic" stylemapstylename="italic" stylemapfamilyname="AT Name Sans Variable Ultra"> | |
<location> | |
<dimension name="Weight" xvalue="1000"/> | |
<dimension name="Optical Size" xvalue="8"/> | |
<dimension name="Italic" xvalue="1"/> | |
</location> | |
<kerning/> | |
<info/> | |
</instance> | |
</instances> | |
</designspace> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
A script to make it slightly less painful to work with support sources. | |
Checks the spacing of glyphs in support sources, by re-interpolating | |
those glyphs from main sources, and checking the support glyphs against that. | |
Also places interpolated versions in the background, for visual reference. | |
Fixes small spacing discrepancies, but leaves bigger ones, as they might be intentional. | |
Can be run as a standalone script, or via RoboFont if you have the latest FontTools installed in RoboFont: | |
https://robofont.com/documentation/how-tos/overriding-embedded-libraries/#overriding-embedded-libraries | |
Assumptions / prequesites: | |
- You have a designspace that includes "sparse" / "support" sources | |
- These support sources may have to be separate UFOs. This hasn’t been tested with support layers. | |
- These support sources include the substring "sparse" or "support" in their filenames | |
- Full sources *don’t* include the substring "sparse" or "support" in their filenames | |
- You want to clear glyph color marks in support sources, and use red marks to | |
indicate glyphs to check (this can be configured below) | |
USAGE IN THE TERMINAL: | |
1. Install dependencies. FontTools, FontParts, ufoProcessor, ufonormalizer | |
2. If you have glyphs you don’t want to respace in support sources, update them in glyphsToNotRespace, below | |
3. Run this script in a terminal: | |
python3 <this_script_path>.py <your_designspace_path>.designspace | |
--- | |
MIT LICENSE: | |
Copyright 2023 ArrowType / Stephen Nixon | |
Permission is hereby granted, free of charge, to any person obtaining a | |
copy of this software and associated documentation files (the “Software”), | |
to deal in the Software without restriction, including without | |
limitation the rights to use, copy, modify, merge, publish, | |
distribute, sublicense, and/or sell copies of the Software, and | |
to permit persons to whom the Software is furnished to do so, | |
subject to the following conditions: | |
The above copyright notice and this permission notice shall be included | |
in all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
DEALINGS IN THE SOFTWARE. | |
""" | |
from fontTools.designspaceLib import (DesignSpaceDocument, | |
InstanceDescriptor) | |
from fontParts.fontshell import RFont as Font | |
from ufoProcessor.ufoOperator import UFOOperator | |
from ufonormalizer import normalizeUFO | |
import subprocess | |
import sys | |
import os | |
# ------------------------------------------------------------------- | |
# CONFIGURATION | |
# if you have glyphs you don’t want to automatically respace (because left/right margins are intended to change), list them here | |
glyphsToNotRespace = "dotbelowcmb quoteleft quoteright quotedblleft quotedblright quotesinglbase quotedblbase period comma colon semicolon exclam exclamdown question questiondown dotcomb ldotcomb comma.brut semicolon.brut exclam.brut exclamdown.brut colon.tnum semicolon.tnum exclamdown.case_brut exclamdown.case questiondown.case".split(" ") | |
# a threshold of units above which to not auto-fix spacing differences | |
ignoreSpacingDiffsAbove = 5 | |
# set to True if you want to unmark all glyphs in support sources, then add a certain color to glyphs to check | |
markGlyphsToFix = True | |
markColor = (1.0, 0.65, 0.65, 1) # (1.0, 0.65, 0.65, 1) is a nice pinkish red | |
# CONFIGURATION | |
# ------------------------------------------------------------------- | |
# basics to run the script in RoboFont or in the terminal | |
# if we can import mojo.UI, we are running the script in RoboFont | |
try: | |
from mojo.UI import OutputWindow | |
runInRobofont = True | |
# if we can’t import mojo.UI, we are running the script via the terminal | |
except ImportError: | |
runInRobofont = False | |
# try to get the designspace path passed in | |
try: | |
mainDSpath = sys.argv[1] | |
# if a user doesn’t pass a designspace path, tell them to try again | |
except IndexError: | |
print("You must give a designspace path as an argument, like:") | |
print() | |
print(" python3 <this_script_path>.py <your_designspace_path>.designspace") | |
print() | |
exit() | |
# open & clear output window if running in robofont | |
if runInRobofont: | |
from vanilla.dialogs import getFile | |
from mojo.UI import OutputWindow | |
OutputWindow().show() | |
OutputWindow().clear() | |
mainDSpath = getFile("Select Designspace with sparse/support sources", allowsMultipleSelection=False, fileTypes=["designspace"])[0] | |
# set up a place to store information to print out later | |
report = {} | |
# open main DS & fonts with ufoProcessor.ufoOperator | |
mainDS = DesignSpaceDocument.fromfile(mainDSpath) | |
openedMainDS = UFOOperator() | |
openedMainDS.read(mainDSpath) | |
def createGeneratorDS(mainDS): | |
""" | |
mainDS should be a DesignSpaceDocument which includes "support sources" | |
This function creates a second, more simplistic DesignSpaceDocument, excluding supports. | |
This allows the script to generate glyphs as they would be, without support sources, | |
and in turn, that allows you to update your support sources to more smoothly integrate | |
into the overall designspace, only affecting what you want to affect. | |
""" | |
# creates new generator DS with FontTools | |
generatorDS = DesignSpaceDocument() | |
try: | |
# copies basic things | |
generatorDS.axes = mainDS.axes | |
generatorDS.axisMappings = mainDS.axisMappings | |
generatorDS.variableFonts = mainDS.variableFonts | |
generatorDS.instances = mainDS.instances | |
except AttributeError as e: | |
print(e) | |
print() | |
print("You must first install FontTools version 4.40.0 or higher in the RoboFont app Resources:") | |
print() | |
print("https://robofont.com/documentation/how-tos/overriding-embedded-libraries/#overriding-embedded-libraries") | |
exit() | |
for source in mainDS.sources: | |
# copies sources that aren’t titled as sparse or support sources | |
if "sparse" not in source.filename and "support" not in source.filename: | |
generatorDS.sources.append(source) | |
# also makes instances for support locations, which is important later | |
if "sparse" not in source.filename or "support" not in source.filename: | |
supportInstance = InstanceDescriptor() | |
supportInstance.location = source.location | |
generatorDS.addInstance(supportInstance) | |
# also adds a default instance, as required by mutator math | |
defaultInstance = InstanceDescriptor() | |
defaultInstance.location = dict(weight=0) | |
# saves new DS as a file, so we can open it with ufoProcessor | |
generatorDSpath = mainDS.path.replace(".designspace","-generator.designspace") | |
generatorDS.write(generatorDSpath) | |
return generatorDS, generatorDSpath | |
generatorDS, generatorDSpath = createGeneratorDS(mainDS) | |
# open generator DS & fonts with ufoProcessor | |
openedGeneratorDS = UFOOperator() | |
openedGeneratorDS.read(generatorDSpath) | |
openedGeneratorDS.loadFonts() | |
def fixAnchors(glyph1, glyph2): | |
""" | |
Clears anchors in the support glyph, and copies over new ones with rounded positioning | |
""" | |
# clear any existing anchors | |
glyph1.clearAnchors() | |
# # attempt to position anchors better | |
# glyph2.moveBy((italicOffset, 0)) | |
# copy anchors (may need a loop instead...?) | |
if len(glyph2.anchors) > 0: | |
for a in glyph2.anchors: | |
glyph1.appendAnchor(a.name, (a.x, a.y)) | |
# apply italic offset from interpolated font | |
# for anchor in glyph1.anchors: | |
# anchor.x += -1 * glyph2.font.info.italicOffset | |
def copyG2toG1bg(glyph1, glyph2): | |
""" | |
Copies the outline of glyph2 to the background layer of glyph1. Also places guidelines in the glyph1 foreground to show margins of glyph2. | |
Args: | |
- glyph1: a manually edited glyph in the "support" source of a buildable designspace | |
- glyph2: a newly-generated glyph, interpolated from the main/non-support sources of that designspace | |
""" | |
supportSourceFont = glyph1.font | |
italicOffset = supportSourceFont.lib["com.typemytype.robofont.italicSlantOffset"] | |
# let’s also add a single guide for the interpolated width (TODO: check if italic angle is working) | |
glyph1.clearGuidelines() | |
glyph1.appendGuideline((glyph2.width + italicOffset, 0), 90 + supportSourceFont.info.italicAngle) | |
# also just add a guideline at the left edge, to make the point more obvious | |
glyph1.appendGuideline((0 + italicOffset, 0), 90 + supportSourceFont.info.italicAngle) | |
# get background layer name | |
supportBg = supportSourceFont.layers[1] | |
supportFontBgLayerName = supportBg.name | |
# check if g1 has background layer (really, if layer has g1); if not, add it | |
if glyph1.name not in supportBg: | |
supportBg.newGlyph(glyph1.name) | |
# get glyph1 bg, then clear it | |
glyph1Bg = supportSourceFont[glyph1.name].getLayer(supportFontBgLayerName) | |
glyph1Bg.clear() | |
# # move glyph2 so we can position it better in background | |
# glyph2.moveBy((italicOffset, 0)) | |
# get the point pen of the layer glyph | |
penToDrawWith = glyph1Bg.getPointPen() | |
# draw the points of the imported glyph into the layered glyph | |
glyph2.drawPoints(penToDrawWith) | |
# match new background layer width with expected layer width | |
glyph1Bg.width = glyph2.width | |
def fixSpacing(glyph1, glyph2): | |
""" | |
Fixes/updates spacing for glyphs, so long as they aren't "dot glyphs," | |
which I want to keep the interpolated width, but get a little wider to stay squarish at thinish weights. | |
""" | |
if glyph1.isEmpty() and (glyph1.width - glyph2.width) > ignoreSpacingDiffsAbove: | |
glyph1.width = round(glyph2.width) | |
else: | |
# only fix/update the spacing if the support glyph is not listed in glyphsToNotRespace, and width difference is more than 2 units (i.e. not a rounding issue) | |
if glyph1.name not in glyphsToNotRespace and (glyph1.width - glyph2.width) > ignoreSpacingDiffsAbove: | |
glyph1.leftMargin = glyph2.leftMargin | |
glyph1.width = glyph2.width | |
def checkForSpacingDiffs(glyph1, glyph2): | |
""" | |
Checks for spacing discrepancies in glyph1 vs glyph2. | |
Args: | |
- glyph1: a manually edited glyph in the "support" source of a buildable designspace | |
- glyph2: a newly-generated glyph, interpolated from the main/non-support sources of that designspace | |
""" | |
# get basic dimensions of g1 | |
supportGlyphDimensions = (round(glyph1.width), round(glyph1.leftMargin), round(glyph1.rightMargin)) | |
# get basic dimensions of g2 | |
generatedGlyphDimensions = (round(glyph2.width), round(glyph2.leftMargin), round(glyph2.rightMargin)) | |
spacing = (supportGlyphDimensions, generatedGlyphDimensions) | |
# save differences to logger | |
if supportGlyphDimensions != generatedGlyphDimensions: | |
return spacing | |
def fuzzyReport(glyph1, spacingDiff, marginOfError=2): | |
""" | |
Check spacing differences. If they exceed margin of error, add them to the report for fixing. | |
Spacing diffs arg is a tuple of (glyph1dimensions, glyph2dimensions) if they don't | |
have exactly matched (width, leftMargin, rightMargin): | |
> ( | |
> (589, 164, 189), # from support source | |
> (502, 159, 189) # from generated interpolation | |
> ), | |
""" | |
reportSection = "" | |
# if these equations are true, these variables become True. If false, they become False | |
widthDiff = abs(spacingDiff[1][0] - spacingDiff[0][0]) >= marginOfError | |
leftMarginDiff = abs(spacingDiff[1][1] - spacingDiff[0][1]) >= marginOfError | |
rightMarginDiff = abs(spacingDiff[1][2] - spacingDiff[0][2]) >= marginOfError | |
# if spacing differences are found (above the marginOfError), add it to our report | |
if widthDiff or leftMarginDiff or rightMarginDiff: | |
reportSection += "\n" + "- [ ] " + glyph1.name + "\n" | |
# defined in top configuration | |
if markGlyphsToFix: | |
glyph1.markColor = markColor | |
if widthDiff: | |
reportSection += " - width difference is " + str(abs(spacingDiff[0][0] - spacingDiff[1][0])) + "\n" | |
if leftMarginDiff: | |
reportSection += " - leftMargin difference is " + str(abs(spacingDiff[0][1] - spacingDiff[1][1])) + "\n" | |
if rightMarginDiff: | |
reportSection += " - rightMargin difference is " + str(abs(spacingDiff[0][2] - spacingDiff[1][2])) + "\n" | |
report[glyph1.font.path] += reportSection | |
# a list of locations to check | |
supportLocations = {} | |
# first, we make a dict of sparse sources and their locations | |
for dsSource in openedMainDS.sources: | |
if "sparse" in dsSource.filename or "support" in dsSource.filename: | |
supportLocations[dsSource] = dsSource.location | |
# then we loop through the instances of the "generator" designspace | |
for dsInstance in generatorDS.instances: | |
# and check if it matches a support source | |
for supportSource, location in supportLocations.items(): | |
if dsInstance.location == location: | |
report[supportSource.path] = "" | |
# # open support source as RFont ... should we use RF’s OpenFont() to access angledLeftMargin, etc? | |
supportSourceFont = Font(supportSource.path, showInterface=False) | |
# feed the instance object into makeInstance from ufoProcessor, to generate that font | |
# but wrap this in the FontParts OpenFont() to allow manipulation of the glyph (i.e. rounding coordinates) | |
# generatedInstance = OpenFont(openedGeneratorDS.makeInstance(dsInstance), showInterface=False) | |
generatedInstance = Font(openedGeneratorDS.makeInstance(dsInstance), showInterface=False) | |
## only uncomment this if you want to check that the script is really generating UFOs at support locations | |
# generatedInstance.save(supportSource.path.replace(".ufo","-generated.ufo")) | |
# go through each glyph in manually edited support source | |
for g1 in supportSourceFont: | |
# get corresponding glyph in generated font at same location | |
g2 = generatedInstance[g1.name] | |
# round the glyph geometry | |
g2.round() | |
# copy new glyphs to background of main support glyphs, for reference | |
copyG2toG1bg(g1, g2) | |
# fix some things automatically if possible | |
fixSpacing(g1, g2) | |
# clear existing anchors from support, then add new ones | |
fixAnchors(g1, g2) | |
spacingDiffs = checkForSpacingDiffs(g1, g2) | |
# if spacingDiffs not "None" | |
if spacingDiffs: | |
if markGlyphsToFix: | |
# set mark to None, to overwrite it with fuzzy report | |
g1.markColor = None | |
# make report if things are more than marginOfError off | |
fuzzyReport(g1, spacingDiffs, marginOfError=ignoreSpacingDiffsAbove) | |
supportSourceFont.save() | |
normalizeUFO(supportSourceFont.path, writeModTimes=False) | |
print(".", end=" ") | |
continue | |
finalReport = "" | |
# print the spacing report in a readable way | |
for fontpath, reportSection in report.items(): | |
finalReport += "\n" | |
finalReport += "<details><summary><b>" | |
finalReport += f"{os.path.split(fontpath)[1]}" | |
finalReport += "</b> (Click to expand)</summary>" | |
finalReport += "\n" | |
finalReport += reportSection | |
finalReport += "\n" | |
finalReport += "</details>" | |
finalReport += "\n" | |
print(finalReport) | |
# remove temporary generator DS | |
os.remove(generatorDSpath) | |
subprocess.run("pbcopy", text=True, input=finalReport) | |
print("GitHub-ready markdown report copied to clipboard!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment