Fontista Lua API
A Lua script works on a copy of the open font; when it ends, all its changes apply at once, as a single undo step (Cmd or Ctrl + Z reverts it). Lua 5.4, with the standard library (math, string, table, utf8, os, io). Scripts need a licence (site edition) or the App Store version; the trial refuses them.
Running a script
- Scripts window (Scripts › Scripts window…): paste the code, then Run (Cmd or Ctrl + Enter). The output of
printshows below. - Scripts › Run a Lua script…: pick a
.luafile. - Scripts folder: every
.luain it becomes an item of the Scripts menu. - Plugin: a folder inside the plugins folder, with a
plugin.txtfile, becomes a submenu. - Command line (site edition with a licence):
fontista --lua script.lua font.fontista [out.fontista].
| System | Scripts folder | Plugins folder |
|---|---|---|
| macOS, site edition | ~/Library/Application Support/Fontista/scripts | ~/Library/Application Support/Fontista/plugins |
| macOS, App Store | ~/Library/Containers/dev.thinkspark.fontista/Data/Library/Application Support/Fontista/scripts | same folder, plugins |
| Windows | %APPDATA%\Fontista\scripts | %APPDATA%\Fontista\plugins |
| Linux | ~/.local/share/Fontista/scripts | ~/.local/share/Fontista/plugins |
Scripts › Open the plugins folder opens the right folder. A plugin.txt looks like this:
name = My tools
script = round.lua = Round every corner
script = proof.lua = Export a proofEach script = file = label line becomes an item of the submenu.
The font: font
font is a snapshot of the font taken when the script starts (read only).
| Field | Content |
|---|---|
font.family, font.upm | family name, units per em (often 1000: check it) |
font.masters[i] | id, name, ascender, descender, x_height, cap_height, location ({wght = 400}) |
font.axes[i] | tag, name, min, default, max |
font.glyphs | glyph names, in font order |
lang | interface language, "fr" or "en" (to answer in the user's language) |
Master ids look like m01. Every function that takes a master wants its id, not its name.
Functions
| Function | Effect |
|---|---|
glyph(name) | {name, unicode, note, export, mark, layers}, or nil |
layer(name, master) | {width, contours, empty, ink}, or nil; it is a copy: change it, then set_contours |
set_contours(name, master, contours) | replaces the drawing of the layer (creates it if needed) |
set_width(name, master, width) | advance width |
add_glyph(name [, code]) | adds an empty glyph in every master; false if it exists |
remove_glyph(name), rename_glyph(old, new) | components follow a rename |
set_unicode(name, code or nil) | character of the glyph |
set_note(name, text), set_mark(name, 0..7 or nil), set_export(name, bool) | note, colour label (0 red, 1 orange, 2 yellow, 3 green, 4 cyan, 5 blue, 6 purple, 7 grey), export |
anchors(name, master) | {top = {x = 250, y = 700}, _top = …} |
set_anchor(name, master, anchor, x, y) | creates or moves an anchor (top, bottom, _top, entry, exit…) |
components(name, master) | {{base, dx, dy}, …} (read only) |
set_ink(name, master, brush or nil) | turns the layer into skeletons inked by this brush, or stops inking |
kern(master, left, right, value) | sets a pair (glyph or group names) |
kerning(master) | {left = {right = value}} |
batch("line") | runs a batch command (below) and returns its report |
compile() | the compiled TTF, as a byte string |
export_ttf(path) | compiles and writes a TTF; returns its size |
save(path) | saves a .fontista copy |
print(…) | output in the Scripts window, or on the terminal with --lua |
Glyph names are production names: A, a, zero…nine, period, comma, hyphen, eacute, acutecomb, f_i, a.alt1, uni202F… A new font already holds the Latin-1 set (empty).
Contour format
{ closed = true, nodes = {
{x = 100, y = 0, kind = "line"},
{x = 100, y = 300, kind = "line"},
{x = 155, y = 400, kind = "off"}, -- control points precede the point they bend
{x = 245, y = 400, kind = "off"},
{x = 300, y = 300, kind = "curve", smooth = true},
} }- Font units, y up, baseline at 0, x from the glyph origin.
- A closed contour starts at its first on-curve point and wraps around;
offpoints at the end of the list curve the closing segment. - Two
offpoints: cubic Bézier; one: quadratic; none: straight line. kind:"line"or"curve"for an on-curve point (the kind of the segment ending there),"off"for a control point,"move"for the start of an open contour.smooth = truekeeps the handles aligned.- Direction: outer contours counter-clockwise, counters clockwise.
batch("correct")fixes directions,batch("overlap")merges overlaps. - An open contour (
closed = false) does not fill: it is a stroke, to thicken withbatch("offset rx ry stroke round"), or a skeleton inked by a brush (set_ink).
Skeletons and brush
An inked layer (set_ink) treats its open contours as skeletons: the brush sweeps along them on screen, in the Preview and at export; its closed contours stay filled shapes. A brush is a table {nib = "round" | "broad", width = 80, angle = 40, edge = 9} (also min, max, gamma, taper, smoothing, melt; width sets min and max together). Per skeleton node: w, the pressure from 0 to 1, and cap, an end cut straight along a line at that angle in degrees (absent: round end). Per contour: ink gives that stroke its own brush.
set_contours("l", m, {{closed = false, nodes = {{x = 250, y = 760, kind = "line", cap = 0}, {x = 250, y = 0, kind = "line", cap = 0}}}})
set_ink("l", m, {nib = "round", width = 72}) -- a 72-unit monoline stem, ends cut flat on the zonesBatch commands: batch("…")
batch works on a selection of glyphs (all by default) and a master (the first by default). The selection stays for the rest of the script: run batch("select all") again after a targeted operation.
| Command | Effect |
|---|---|
select all / upper / lower / digits / name name name… | glyphs targeted by the next commands |
master id-or-name | master targeted |
offset dx dy [expand|contract|stroke] [round] [keep] | offset the outline; stroke turns every contour into a band of half-width dx (horizontal) and dy (vertical) |
round r | round every corner with radius r |
fit pct, simplify tol | refit curves; fewer nodes |
smooth, tidy, extremes | smooth nodes; tidy up; add extreme points |
overlap, correct | remove overlaps; correct directions |
transform rotate deg / scale pct / slant deg | around each glyph's centre |
autospace [white] [depth] | automatic spacing (average white per side, counter depth in %) |
autokern [strength] [replace] [all] | automatic kerning of base letters |
metrics-update, kern-clean [threshold] | apply metric keys; remove useless pairs |
weight name wght dx dy [exact], italic name deg, width name pct | new bolder, slanted or narrower master |
smallcaps, tabular, smallforms [sups] [subs] [frac] | derived glyphs and their features |
skeletonize [editable|faithful|exact], weightaxis light bold | brush skeletons; weight axis from the brush |
anchors [height], forms | cursive connection anchors (entry and exit), init and fina forms for joined scripts |
autofeatures on|off | features generated at compile time (kern, mark, liga, calt…) |
Command line
fontista --lua script.lua font.fontista [out.fontista]The script sees the font; if it changed something, the result is saved to out.fontista (or in place without an output). print writes to the terminal. Exit code 1 and the Lua message on error. Program on macOS: /Applications/Fontista.app/Contents/MacOS/fontista; on Windows, fontista.exe; on Linux, fontista.
Tips
- Read what you need first (
font.upm, the master's zones); never assume 1000 units. layer()returns a copy: change it, thenset_contours; read it again after a batch command.- An error stops the script and nothing is applied: read the message in the output.
overlapis a union (non-zero rule): a reversed contour only cuts where it lies inside ink.- Lua keeps only the first value of a call that is not the last argument:
f(g(), x)passes one value fromg. Return tables rather than several values. - A script can reach the computer's files like any program: only run scripts whose source you know. Those of the library are reviewed and tested by Thinkspark.