TLDR: I tried to automate the formation of ligatures in style of Slavic calligraphy, called a monospaced Vyaz. A gallery with examples of results can be found here. Details are below.

Aleksey Tikhonov



There is an old Slavic calligraphy tradition, called ‘Russian monospaced Vyaz’ or just ‘Vyaz’. It’s unique in terms of special forms and rules of ligature generation. For example, take a look at works of a contemporary artist Viktor Pushkarev.

Once, a colleague of mine, Anna Shishlyakova drew a nice piece of Vyaz and since then I kept thinking if one can automatically generate such ligatures. Several years have passed and I finally found a weekend to make something like this:

the original drawing by Anna on the left side, the generated vyaz on the right side

General description

The current implementation consists of several components:

  • a configuration file that determines the size of symbols, kerning and ligature assembly parameters (as an example, I give a pack of several different configuration files with crafted parameters);
  • a font geometry file now contains Latin and Cyrillic symbols, plus Arabic numerals, it can be expanded;
  • a script that implements several rendering algorithms.

The current version renders the result in ASCII/unicode graphics, however, the whole core is implemented in a vector logic, so it is possible to rewrite a renderer to produce something like svg or high-resolution bitmap.

Core logic

a font grid scheme

In case you want to add new symbols and/or change how the font looks, you should understand several principles:

  1. Each symbol consists of a set of anchors and some edges between them.
  • The position of each anchor is given in terms of a simple grid:
  • for a horizontal offset I used the zero-based index of “vertical”, for example, ‘I’ has only one vertical, ‘U’ has two verticals, and ‘W’ has three vertical lines (note, ‘Z’ still has only two verticals),
  • for a vertical position I used this scale of 5 positions: b[ottom] < d[own] < m[iddle] < u[p] < t[op].

2. An edge is defined by three parameters:

  • the first anchor,
  • the second anchor,
  • the constraint on a slope of the edge:
  • ‘=’ means both anchors should be strictly on the same vertical position,
  • ‘<’ means the first anchor should be lower than the second, etc.

3. While merging two symbols into ligature the script checks if a left-most vertical of the right symbol conflicts wit a right-most vertical of the left symbol. If so, it tries to distort them somehow to avoid any conflicts. There are two types of distortion implemented:

  • if it’s possible to resize the only one vertical of symbol to remove conflicts without violation of edges constraints, it’s done.
  • Overwise, the whole symbol could be resized to avoid the collision, but it’s bad to resize too much,
  • If nothing helps, the script just puts these two symbols side-by-side separately.
different strategies of ligature construction

Few more words

You can grab a working code just in my github repo.

Despite the output of the asciivyaz script usually looks okay, consider to use it in conjunction with some other tools:

  • try to use lolcat to colorize the output just in a terminal,
  • try to use some online snippet renderers, like carbon to make snippets look better.

Some pictures