With apologies for a long post, I’d like to invite anyone interested in TrueType hinting to take a look at an app I’ve been working on for the last few months. Called YGT (don’t ask), it’s a graphical editor somewhat like others I’ve used, but addressing my own wants and concerns about existing tools. To wit:
- Written in Python with PyQt6, fontTools, and FreeType-py, it is cross-platform and independent of existing font editors.
- You can either generate a hinted font from inside the program or produce a script that can be run from makefiles and the like. It’s a useful tool for anyone who needs to generate fonts from command-line scripts.
- All hints are stored in a YAML-based format that’s simple and easy to learn. If you edit the source within the YGT program (you don’t usually have to, but you can if you want), it is validated as you type.
- It’s designed to be fast. Most operations are performed with unmodified shortcut keys so that you can work for considerable stretches with one hand on the mouse and one on the keyboard.
- It names rather than numbers such items as control values, functions, and even points, making them easier to work with.
- It has a light footprint, increasing the size of a font file by about a third as much as, say, ttfautohint. Part of the reason for this is that it dumps only a tiny library of functions into a font—but it does encourage users to write their own functions and macros, and these can be inserted via the GUI like other hints.
YGT does considerably less than VTT, but that’s the point, in a way. Contemporary fonts can be hinted much more lightly than they were twenty years ago: YGT is designed around the things that are required now, and both its GUI and its file format are streamlined by concentrating on just those things. But YGT works well with variable fonts: you can create and edit the cvar table and preview the font’s different instances.
Here’s a screenshot of the main window plus a Font View window, used for navigation and also showing which glyphs have been hinted (they’re highlighted in blue). In the main window, the hint editor is on the right (with tools up above), YAML source in the center text pane, and a preview on the left. The editor for this glyph shows the familiar anchors and arrows of other editors, plus a macro call for the glyph’s cupped serif.

YGT is far from finished. The preview (by FreeType) is primitive: I
need to supply a grid and perhaps an outline, figure out subpixel
rendering, and find a better way to feed FreeType a glyph to display
(the procedure right now is slow and clunky). There’s no undo/redo
yet. No deltas yet. No preliminary autohinting. I need better
interfaces for editing control values and other stuff. I’m an
amateur programmer, and I suspect that my code is often amateurish
and inefficient, with plenty of things needing improvement or
tidying
I’d like to hear
from anyone who thinks this project is worthwhile. What features do
you absolutely have to have in an app like this? What features look superfluous or badly
implemented? This is an Open Source project, and I welcome
contributions, especially from people who know more about GUI design
than I do, or are more familiar than I am with Qt, fontTools, and
FreeType. All contributors will be gratefully acknowledged and, where
appropriate, added to the list of authors.
YGT is here: https://github.com/psb1558/ygt. It’s not on PyPi yet:
installation instructions are at the site. If you find yourself
actually using it, save often. This program is young, and while it is
way more stable than it was a month ago (I’ve used it for hours at
a stretch and hinted 2000+ glyphs with it), I can’t guarantee that
it will never crash.
Comments
And, is it using any of the vtt code/resources Microsoft has liberated?
If not because its too slow, would a Rust replacement to fontTools like https://github.com/googlefonts/fontations be fast enough?
When I launch ygt, I get the following error:
Once installed 'fs' with pip, I launch ygt
Maybe you should change these lines using os.path.join()?Out of all the programming languages that I tried to do something similar to
"VTT's ability to instantly update its preview", Google's own go/golang is the hardest. Good you are not trying to write a font editor with golang. 😀
https://unifiedfontobject.org/versions/ufo3/lib.plist/#publictruetypeinstructions
https://unifiedfontobject.org/versions/ufo3/glyphs/glif/#publictruetypeinstructions
You would need to store your custom hinting language in private font/glyph lib keys. And AFAIK the only font building tool that supports compiling the UFO ttx code is my fork of ufo2ft.
is equivalent to this in VTT assembly:
You might consider using VTT assembly via vttLib instead of xgridfit as a backend for your editor.
Since the issue of instantaneous (or at least quick) previews has gotten some attention, I’ll report on progress there. The original implementation (re)read the font from disk so as to get a clean copy, compiled the TrueType instructions for the current glyph and inserted them into the font, saved the font to a temporary file, and read that file and displayed the hinted glyph. Whew! It could take up to two seconds for a biggish (ca. 4900 glyphs) font on a reasonably fast machine. On the old slow machine where I run Linux, it could take five seconds.
The new implementation keeps a clean copy of the font (via fontTools) in memory to avoid that first disk access. When a preview is called for, it makes a deep copy of the font, inserts the instructions, has fontTools subset the font (dropping all OT features and all but one glyph), saves that to a spooled temporary file (again avoiding a disk access), and reads and displays the tiny font. (I would have guessed that the subsetting would cost instead of save time, but it doesn’t.) The whole operation (for a biggish font) takes about 0.66 seconds. For a font with about 1000 glyphs, it takes about 0.40 seconds.
Finally, all of this happens in its own thread so as to avoid blocking the GUI. With these changes, I feel comfortable updating the preview whenever any change takes place in the editing pane. The result is not quite an instantaneous update of the preview pane, but it feels more or less like that. Half a second isn’t a lot.
This change is not in the repository yet: I need to test more before I post it, and take care of a few details.
Here are the substantive developments (excluding bug fixes and other minor changes) since I last posted a couple of weeks ago.
File handling:
Ygt can now have several files open, in separate windows.
“Export font” (which can take a couple of minutes for a very large font) now runs in a background thread, with an indicator to show it is running.
Preferences:
Early versions kept preferences in a YAML file on Unix-like systems; now Ygt saves preferences in the Windows registry as well.
Preview pane:
Preview is now updated automatically; but you can turn this off if it’s too laggy.
Hinting can now be toggled on and off in the preview pane.
For variable fonts: flip through instances with Shift-Left and Shift-Right.
Editing:
Supplementing the choice between “round” and “don’t round,” Ygt can now use TrueType’s rounding types (to-half-grid, down-to-grid, etc.). Not yet via the GUI.
You can choose the initial round state for each kind of hint, e.g. if you want rounding off by default for stem hints. Not yet via the GUI.
Control values:
Ygt guesses at eleven control values when a font is opened for the first time (this was broken for a time and is fixed now).
Now control values can be linked, somewhat in the manner of VTT’s “inheritance.” This is done via a dialog box, and Ygt generates code for the prep table.
Select a hint and type a question mark to make Ygt guess the correct control value.
Ygt now uses Unicode character categories to filter control values. It can also filter by suffix (e.g. “smcp” or “pcap”). If a font has a large number of control values, this makes them easier to navigate.
Documentation:
Documentation is still sketchy, but has been updated to reflect (what I understand to be) current best practices in hinting.
Major to-dos:
Autohinting! I hardly know where to start. I’ve begun to study how other Open-Source programs do it.
Undo/Redo. Still on course to use the Qt Undo Framework.
Another progress report:
I’ve fixed up the preview pane, adding a grid (which can be toggled off and on) with baseline. The last major to-do for this main preview will to add an outline (via FreeType’s stroker).
Also added a smaller preview pane beneath the main one: by default this shows the current glyph in an array of sizes (from 10 to 100 ppem, or as much as fits). For variable fonts, this pane always shows the same instance as the main preview. If you click on any character, the main preview will change to that size.
You can type a short text in the “Text” box to see glyphs in context (the size and instance always the same as in the main preview). Click on any letter to jump to that glyph in the editing pane.
This preview doesn’t yet use kerning (that will come soon). An additional plan is to use Harfbuzz to apply OT features so that any glyph in the font can be displayed in this pane.
I can’t remember, though, how data should be recorded if the default location is at the axis extreme, e.g. if your 6pt opsz extreme is also the default instance.
If the default instance is at one end of the axis, you only need to go one direction.