Plug-ins
What Fontra expects from a plug-in: the manifest, the address rules, the objects an editor plug-in receives, and the Python entry points. For a guided introduction, see Writing your own plug-ins.
Note
Editor plug-ins work on the editor’s internal objects, not on a frozen API. The names below are those of the current Fontra source; check them again when you update Fontra.
Editor plug-ins
plugin.json
| Key | Value |
|---|---|
name | Display name. Used in the console error if the plug-in fails to run. |
description | Free text. Not used by Fontra. |
init | Path of the ES module to import, relative to the plug-in folder (for example init.js). |
function | Name of the function exported by that module. Called as function(editor, pluginPath). |
Addresses
Added in Application settings › Plugins. Stored in the browser’s localStorage under the key fontra.pluginsplugins as [{"address": "…"}, …], so the list belongs to one browser and one server origin (host and port).
| Address | Resolved to |
|---|---|
owner/repo (exactly one slash) | https://cdn.jsdelivr.net/gh/owner/repo@latest — a GitHub repository with the plug-in files at its root and at least one tagged release: @latest is the latest tag, so a repository without tags is refused (An error occured when fetching the plugin). jsDelivr caches the resolution of @latest per file for up to a day, failures included: purge with https://purge.jsdelivr.net/gh/owner/repo@latest/<file> after tagging. See Publishing your plug-in. |
https://…/folder | Used as is. The server must send CORS headers and serve the scripts with a JavaScript media type (GitHub Pages and jsDelivr do; github.com and raw.githubusercontent.com do not). |
/folder | A path on the Fontra server itself, for example /localplugins/my-plugin or a fontra.webcontent package. |
A trailing slash is removed. The resolved address is what init() receives as pluginPath.
Loading
When the editor starts, for each address in order:
GET <pluginPath>/plugin.json— on failure: console error “… Plugin metadata not found.”, next plug-in.import(<pluginPath>/<init>)— on failure: “Module didn’t load” and the exception, next plug-in.module[function](editor, pluginPath)— on exception: “Error occured when running () plugin.” and the exception.
Plug-ins load in the glyph editor only, after Fontra’s own sidebars, tools, actions and menus have been set up. A plug-in cannot import Fontra’s modules (@fontra/core/…): they are bundled and have no URL.
Files served from the Fontra server (a server path address) are limited to the extensions .js, .json, .svg, .css, .html, .txt, .csv, .ico, .woff2 and .wasm, and are dated at server start-up: the browser’s cached copy is reused (304 Not Modified) until the server restarts or the cache is disabled.
The editor object
| Member | Description |
|---|---|
fontController | The font. glyphMap (glyph name → code points), unitsPerEm, axes, await getGlyph(name). |
sceneSettings | Current state: selectedGlyphName, selectedGlyph, selection, fontLocationUser, positionedLines, text, … |
sceneSettingsController | addKeyListener(keyOrKeys, callback, immediate), waitForKeyChange(key). |
sceneModel | getSelectedPositionedGlyph() → { x, y, glyph, … }; glyph has name, path, components, xAdvance, leftMargin, rightMargin, canEdit. |
sceneController | editLayersAndRecordChanges(fn), editGlyphAndRecordChanges(fn), addCurrentGlyphChangeListener(fn), selectedTool, setSelectedTool(id). |
canvasController | requestUpdate(), magnification, origin, localPoint(event), canvas. |
visualizationLayers | definitions (array sorted by zIndex), toggle(id, on), visibleLayerIds, darkTheme. |
visualizationLayersSettings | Observable of the user-switchable layers: model[id] is true or false. |
addSidebarPanel(panel, side) | side is "left" or "right". Throws if the side is unknown. |
addEditTool(tool) | Appends a button to the toolbar. |
toggleSidebar(id, focus) | Opens or closes a panel by identifier. |
tools | All tools by identifier. |
Edits with undo
editLayersAndRecordChanges(fn) calls fn(layerGlyphs) with the layers being edited, keyed by layer name (one entry, or several when several sources are edited together). fn changes them in place and returns the undo label (a string). The change is recorded, sent to the server, and listed in Edit › Undo.
Sidebar panel
An HTML element (usually with a shadow root) with:
| Member | Description |
|---|---|
identifier | Unique among all panels. Used in data-sidebar-name on the tab and content elements, and in the localStorage key fontra-selected-sidebar-<side>. |
iconPath | URL of the tab's SVG icon. Must be set before addSidebarPanel(). |
toggle(on, focus) | Optional. Called when the panel is shown (on is true) or hidden. |
The tab’s tooltip is translate("sidebar.<identifier>"); for a plug-in that returns the key itself, so set title on .sidebar-tab[data-sidebar-name="<identifier>"] yourself. Fontra’s CSS variables (--ui-element-foreground-color, --ui-element-background-color, …) and the font family fontra-ui-regular are available inside the shadow root.
Edit tool
An object with:
| Member | Description |
|---|---|
identifier | Unique among all tools. Used in data-tool on the button and in editor.tools. |
iconPath | URL of the button's SVG icon. |
activate(), deactivate() | Called when the tool is selected or another tool is. |
async handleDrag(eventStream, initialEvent) | Called on mouse down; iterate eventStream until mouse up. |
handleHover(event) | Mouse move without a button pressed. |
handleKeyDown(event) | Keys other than arrows. Define handleArrowKeys(event) to receive arrow keys too; otherwise Fontra nudges the selection. |
getContextMenuItems() | Items appended to the canvas context menu. |
The button’s tooltip is translate("editor.<identifier>"), so set title on [data-tool="<identifier>"] yourself. The button is created with the selected class; remove it unless the tool is the active one. editor.canvasController.localPoint(event) converts an event to glyph coordinates.
Visualization layer
A definition inserted into editor.visualizationLayers.definitions at the position given by its zIndex, then enabled with toggle(identifier, true):
| Key | Description |
|---|---|
identifier | Unique. Prefix it with your plug-in name. |
name | Translation key of the layer's title (used in the View menu for user-switchable layers). |
zIndex | Drawing order, higher on top. Fontra's own layers use 0 (UPM grid) to 700 (glyph lock). |
userSwitchable, defaultOn | Whether the layer is listed in View › Glyph editor appearance, and its initial state. Those menu actions are registered before plug-ins load, so a plug-in layer should keep userSwitchable: false. |
screenParameters | Numbers in screen pixels, divided by the magnification before drawing (strokeWidth, nodeSize, …). |
glyphParameters | Numbers in glyph units, passed unchanged. |
colors, colorsDarkMode | Colors for the light and dark themes. All four groups are merged into parameters. |
selectionFunc(visContext, layer) | Returns the positioned glyphs to draw for. visContext.glyphsBySelectionMode has all, unselected, hovered, selected, editing and notediting. |
selectionFilter(positionedGlyph) | Optional filter applied by Fontra's own selectors. |
draw({ context, positionedGlyph, parameters, model, controller }) | Called once per glyph with the canvas context translated to the glyph's origin, baseline at y = 0, y up, in glyph units. |
Call editor.canvasController.requestUpdate() after changing a layer’s visibility.
Server plug-ins
Python packages declaring entry points in pyproject.toml, installed in the same environment as Fontra.
| Group | Entry point name → value | Used |
|---|---|---|
fontra.filesystem.backends | File extension → class with fromPath(path), optionally createFromPath(path), implementing ReadableFontBackend / WritableFontBackend (fontra.core.protocols) | When a font file with that extension is opened or created |
fontra.projectmanagers | Subcommand name → project manager factory | fontra <name> … |
fontra.webcontent | URL prefix → package (dotted path to a folder) | Served as static files under /<name>/ |
fontra.workflow.actions | Any name → module to import | Loaded by fontra-workflow; the module registers its actions with @registerFilterAction("…") / @registerOutputAction("…") |
fontra.views | View name → package | Listed as View plugins in Server info only |
Fontra itself registers designspace, ufo, ttf, otf, ttx, woff and woff2 backends, the filesystem project manager, and localplugins = "fontra.localplugins" (the folder src/fontra/localplugins/, not in git).