Python API
Auto-generated from JavaScript object model introspection
Table of Contentslink
- Overview
- Class Reference
- Font -
- Glyph -
- FeatureVariationGlyph - An authorable view over one conditional Glyphs feature-variation layer family.
- Layer - Layer in a glyph representing a master or intermediate design
- Shape - Shape wrapper that can contain either a Component or a Path
- Path - Path (contour) in a layer
- Node - Point in a path
- Component - Component reference to another glyph
- Anchor - Anchor point in a layer
- Guide - Guideline in a layer or master
- Axis - Variation axis in a variable font
- Master - Master/source in a design space
- Instance - Named instance in a variable font
- Complete Examples
- Tips and Best Practices
Overviewlink
The Font Object Model provides an object-oriented interface for manipulating font data. All objects are lightweight facades over the underlying JSON data - changes are immediately reflected in the font structure.
Accessing the Font Modellink
# Get the current font (fonteditor module is pre-loaded)
font = Font()
Dictionary Access (Python wrappers)link
Dictionary-like object model fields are wrapped as live Python mappings. Use normal Python dictionary access for both reading and writing.
font = Font()
master = font.masters[0]
# Nested kerning dictionary (live two-way view)
master.kerning["A"]["V"] = -80
# Internationalized naming dictionaries
font.names.familyName["dflt"] = "My Family"
font.names.familyName["de"] = "Meine Familie"
font.names.familyName["fr"] = "Ma Famille"
font.names.familyName["ar"] = "عائلتي"
master.name["dflt"] = "Standard"
master.name["de"] = "Standard"
master.name["fr"] = "Standard"
master.name["ar"] = "قياسي"
# Optional snapshot copy when needed
kerning_snapshot = master.kerning.as_dict()
Shared Plugin Contextlink
ctx = Context()
ctx.runCount = getattr(ctx, "runCount", 0) + 1
SetContextPatch({"lastRun": {"count": ctx.runCount}})
Parent Navigationlink
All objects in the hierarchy have a parent() method that returns their parent object,
allowing navigation up the object tree to the root Font object.
Example:
# Navigate from node up to font
node = font.glyphs[0].layers[0].paths[0].nodes[0]
path = node.parent() # Path object
shape = path.parent() # Shape object
layer = shape.parent() # Layer object
glyph = layer.parent() # Glyph object
font = glyph.parent() # Font object
Class Referencelink
Fontlink
Access:
# fonteditor module is pre-loaded
font = Font()
Propertieslink
Read/Write Properties
upm(float | int)version([number, number])axes(list[Axis] | None)instances(list[Instance] | None)masters(list[Master] | None)note(str | None)date(str)names(dict[str, dict[str, str] | None])custom_ot_values(list[Unsafe] | None)variation_sequences(dict | None)features(dict[str, Any])first_kern_groups(dict | None)second_kern_groups(dict | None)format_specific(dict | None)source(str | None)
Read-Only Properties
glyphs(list[Glyph])
Methodslink
rebuildAutomaticCompositesForGlyphs(changedGlyphNames: Set<string> | None = None, options: { allowedGlyphNames?: Set<string>; preferredLayerId?: string | null; preferredSourceGlyphName?: string | null; } | None = None) -> Set<string>
collectMetricsKeyDependentGlyphs(sourceGlyphNames: Iterable<string>) -> Set<string>
Collect glyphs whose metrics keys / automatic-offset edges depend on the given source glyphs, whether or not their stored sidebearings currently need updating. Used by cascading commit so live-already-synced dependents are still persisted into Yjs.
collectMetricsKeyPrerequisiteGlyphs(glyphNames: Iterable<string>) -> Set<string>
Return the transitive metrics-key prerequisites of glyphs that must be recomposed live. A visible glyph can reference a hidden glyph through a metrics key (for example a.ss03 =|n); its value is not correct until the hidden reference and its own prerequisites have settled. The live recomposition closure uses this to close its allowed mutation set before running the same work queue as the all-scope commit path.
recomputeMetricsKeys(changedGlyphNames: Set<string> | None = None, options: { allowedGlyphNames?: Set<string>; skipAutomaticCompositeRebuild?: boolean; /** The caller already rebuilt automatic composites for the initial * sources | None = None, but metric-induced changes must still rebuild their * own automatic dependents. */ skipInitialAutomaticCompositeRebuild?: boolean; }) -> Set<string>
findGlyph(name: str) -> [Glyph](#glyph) | None
Find a glyph by name
Example:
glyph = font.findGlyph("A")
if glyph:
print(glyph.name)
renameGlyphs(renameMap: ReadonlyMap<string, string>) -> None
Rename glyphs and every font-owned reference to them in one undoable transaction. The mapping is simultaneous, so swaps are safe.
resolveGlyphView(name: str) -> [Glyph](#glyph) | FeatureVariationGlyph | None
Resolve an editor glyph token to an authorable layer view. A literal glyph
name resolves to its persisted Glyph; base.feaVar.N resolves to the
corresponding synthetic feature-variation family.
findGlyphByCodepoint(codepoint: float | int) -> [Glyph](#glyph) | None
Find a glyph by codepoint
Example:
glyph = font.findGlyphByCodepoint(0x0041) # Find 'A'
invalidateReverseComponentIndex() -> None
invalidateMetricsKeyDependencyEntries() -> None
Drop only the metrics-key dependency cache. Call when a metrics key is added, changed, or removed without the glyph set changing.
getGlyphNamesByLengthDesc() -> list[str]
Returns glyph names sorted by length descending, cached. Used by metrics-key
parsing for longest-prefix matching. Cache is invalidated when glyphs are
added/removed/renamed (see invalidateReverseComponentIndex).
findDirectGlyphsUsingComponent(componentGlyphName: str) -> list[str]
collectComponentDependentGlyphs(componentGlyphNames: Iterable<string>, options: { includeSourceGlyphNames?: boolean; retainGlyphNames?: Set<string>; } | None = None) -> Set<string>
invalidateLayoutCachesForGlyphs(glyphNames: Iterable<string>) -> None
Invalidate automatic composition layout caches for all layers of the specified glyphs. Call before recomputing compositions so that stale cached layouts from a previous frame are not reused.
findGlyphsUsingComponent(componentGlyphName: str) -> list[str]
Find all glyphs that reference a given glyph as a component This recursively finds glyphs at each nesting level
Example:
glyphs = font.findGlyphsUsingComponent("o")
# Returns ["ö", "õ", "ø", ...] if they use "o" as a component
duplicateGlyph(glyph: [Glyph](#glyph), newName: str) -> [Glyph](#glyph)
Duplicate a glyph with a new name, inserted immediately after the source. The duplicate does not keep Unicode codepoints.
Example:
new_glyph = font.duplicateGlyph(glyph, "A.alt")
allocateUniqueGlyphName(baseName: str) -> str
Next free glyph name using Glyphs-style .001 / .002 suffixes.
a → a; if taken → a.001, then a.002, …
duplicateGlyphs(names: Iterable<string>) -> list[[Glyph](#glyph)]
Duplicate each named glyph under a unique .001-style name. Each clone is inserted directly after its source, loses codepoints, regenerates layer IDs, and keeps master references.
findAxis(id: str) -> [Axis](#axis) | None
Find an axis by ID
findAxisByTag(tag: str) -> [Axis](#axis) | None
Find an axis by tag
Example:
weight_axis = font.findAxisByTag("wght")
findMaster(id: str) -> [Master](#master) | None
Find a master by ID
addMaster(master: Babelfont.Master | None = None, options: AddMasterOptions | None = None) -> Promise<Master | null>
removeMastersByIds(masterIds: list[str]) -> Promise<boolean>
findInsertIndexAfterName(baseName: str) -> float | int
Index at which to insert a new glyph that belongs with baseName.
Strips a trailing .NNN so clipboard names like a.001 still land
with the a / a.NNN family. Prefers immediately after the last
existing family sibling; otherwise appends.
addGlyph(name: str, category: Babelfont.GlyphCategory | str, options: { insertIndex?: number } | None = None) -> [Glyph](#glyph)
Add a new glyph to the font
Example:
glyph = font.addGlyph("myGlyph", "Base")
addGlyphs(glyphs: Array<{ name: string; codepoints: number[]; category?: Babelfont.GlyphCategory | string; }>) -> list[[Glyph](#glyph)]
Add several Unicode-backed glyphs as one undoable document edit.
preflightDeleteGlyphs(names: Iterable<string>) -> GlyphDeletePreflight
Count cleanup hits for a proposed glyph deletion and collect preview details for the confirm dialog.
deleteGlyphs(names: Iterable<string>) -> None
Delete glyphs and clean font-owned references in one undoable transaction. Always cleans features/classes/prefixes, metrics keys, components, kerning (LTR + RTL), and kern-group membership (dropping empty groups).
removeGlyph(name: str) -> bool
Remove a glyph by name
Example:
font.removeGlyph("oldGlyph")
toJSONString(options: { compileFacing?: boolean } | None = None) -> str
Serialize the font back to JSON string
fromJSONString(json: str) -> [Font](#font)
Create a Font instance from JSON string
fromData(data: Babelfont.Font) -> [Font](#font)
Create a Font instance from parsed JSON data
toString() -> str
analyzeFeatureTables(featureTag: str) -> { hasGSUB: boolean; hasGPOS: boolean; }
Analyze a feature's code to determine if it contains GSUB and/or GPOS rules
Example:
const analysis = font.analyzeFeatureTables("liga")
if (analysis.hasGSUB) console.log("Feature has substitution rules")
analyzeOpenTypeCode(code: str) -> { hasGSUB: boolean; hasGPOS: boolean; }
Analyze OpenType feature code to determine if it contains GSUB and/or GPOS rules This is a general-purpose method that can analyze code from features, prefixes, or other sources
Example:
const analysis = font.analyzeOpenTypeCode("substitute a by b;")
if (analysis.hasGSUB) console.log("Code contains substitution rules")
analyzePrefix(prefixName: str) -> { hasGSUB: boolean; hasGPOS: boolean; }
Analyze a prefix's code to determine if it contains GSUB and/or GPOS rules
Example:
const analysis = font.analyzePrefix("myLookup")
if (analysis.hasGSUB) console.log("Prefix contains substitution rules")
Glyphlink
Access:
glyph = font.glyphs[0]
# or
glyph = font.findGlyph("A")
Propertieslink
Read/Write Properties
leftMetricsKey(str | None)rightMetricsKey(str | None)name(str)production_name(str | None)category(Babelfont.GlyphCategory)codepoints(list[float | int] | None)exported(bool | None)direction(Babelfont.Direction | None)format_specific(dict | None)
Read-Only Properties
featureVariations(list[FeatureVariationGlyph]): Synthetic, authorable views over this glyph's raw Glyphs feature-variation layers.BUILTIN_CATEGORIES(Any)glyphData(GlyphDataSearchResult | None): Read-only Unicode metadata from the bundled Glyph Data catalog. Encoded base glyphs win over editable glyph names; dotted glyphs inherit the identity of their base glyph before a name fallback is attempted.layers(list[Layer] | None)isCompatible(bool): Returns True/False based on whether the outline structure (components + paths + anchors) is compatible across all main layers of this glyph.
Methodslink
getPathSegment() -> list[(string | number)]
getFeatureVariationLayerEntries(familyId: str | None = None) -> Array<{ familyId: string; layer: Layer }>
addFeatureVariation(axisRules: list[Unsafe]) -> FeatureVariationGlyph
Create one associated feature-variation layer for every base master layer, copying each layer's materialized background when present.
removeFeatureVariation(featureVariation: FeatureVariationGlyph | str) -> None
Delete every raw layer belonging to a feature-variation family.
normalizeCategory(value: Babelfont.GlyphCategory | str | None) -> Babelfont.GlyphCategory
addLayer(width: float | int, master: Babelfont.LayerType | None = None, requestedLayerId: str | None | None = None) -> [Layer](#layer)
Add a new layer to the glyph
Example:
layer = glyph.addLayer(500) # 500 units wide
addBackgroundLayer(foreground: [Layer](#layer)) -> [Layer](#layer)
removeLayer(index: float | int) -> None
Remove a layer at the specified index
removeLayerById(id: str) -> None
Remove a layer by its backing-array ID.
findLayerById(id: str) -> [Layer](#layer) | None
Find a layer by ID
findLayerByMasterId(masterId: str) -> [Layer](#layer) | None
Find a layer by master ID
calculateOutlineCompatibility() -> { compatible: boolean; layerCount: number; referenceLayerId?: string; incompatibleLayerIds: string[]; }
Compare outline structure across main layers (the same list shown in the UI).
For compatibility checks, mixed shape sequences are normalized by moving components before paths while preserving their relative order inside each type.
toString() -> str
FeatureVariationGlyphlink
An authorable view over one conditional Glyphs feature-variation layer family.
Propertieslink
All properties are read-only:
name(str)axisRules(list[Unsafe])layers(list[Layer])
Methodslink
setAxisRules(axisRules: list[Unsafe]) -> FeatureVariationGlyph
Replace the shared Glyphs feature-variation rules on every raw family layer.
findLayerById(id: str) -> [Layer](#layer) | None
findLayerByMasterId(masterId: str) -> [Layer](#layer) | None
addLayer(width: float | int, master: Babelfont.LayerType | None = None, requestedLayerId: str | None | None = None) -> [Layer](#layer)
removeLayer(index: float | int) -> None
removeLayerById(id: str) -> None
toString() -> str
Layerlink
Layer in a glyph representing a master or intermediate design
Access:
layer = glyph.layers[0]
Propertieslink
Read/Write Properties
leftMetricsKey(str | None)rightMetricsKey(str | None)width(float | int)lsb(float | int): Get the left sidebearing (LSB) - the distance from x=0 to the left edge of the bounding boxrsb(float | int): Get the right sidebearing (RSB) - the distance from the right edge of the bounding box to the advance widthlinked(bool): Whether this layer is linked for editor multi-layer operations. This is editor-only runtime state keyed by glyph and layer ID; it is not persisted into font data.name(str | None)id(str | None)master(Babelfont.LayerType | None)smart_component_location(UserspaceLocation | None)selection(list[SelectableLayerObject]): Current UI selection on this layer. Assign a node, anchor, component, guide, or a list of them to replace the selection.color(Babelfont.Color | None)layer_index(float | int | None)is_background(bool | None)background_layer_id(str | None)location(DesignspaceLocation | None)format_specific(dict | None)
Read-Only Properties
guides(list[Guide] | None)paths(list[Path]): Direct path objects in this layer, ready to use without Shape.asPath()components(list[Component]): Direct component objects in this layer, ready to use without Shape.asComponent()anchors(list[Anchor] | None)backgroundLayer(Layer): The paired background layer. Empty backgrounds are transient until a path is added, so merely accessing this property does not alter the glyph.fingerprint(str): Returns a normalized outline-compatibility fingerprint for this layer. The fingerprint includes components, paths, and anchors, with anchors sorted by name and guides excluded.
Methodslink
toJSON() -> Unsafe
[object Object],[object Object],[object Object]
toCompileJSON() -> Unsafe
Compile-facing serialization: applies automatic =+/-= left offsets to
component translates so fontc / worker preview see physical ink and
advance. Must not be written back into the resting model or Yjs.
invalidateShapeCache() -> None
Force shape wrapper rebuild on next access.
Call after replacing data.shapes externally so that
setDirectSidebearing operates on the current shapes array.
invalidateContentCaches() -> None
invalidateLayoutCache() -> None
Invalidate only the automatic composition layout cache. Cheaper than full invalidateContentCaches() when only anchor/composition state has changed (not shapes/guides).
getAutomaticCompositionSourceCacheKey() -> object
syncFromEditorLayerData(layerData: { width: number; height?: number; vertWidth?: number; shapes?: Unsafe[]; anchors?: Unsafe[]; guides?: Unsafe[]; format_specific?: Record<string, Unsafe>; }) -> None
Bulk-sync mutable properties from the outline editor's working copy into this layer's model data. Skips the expensive toJSON() round-trip and layout recomputation that would otherwise occur for automatic-aligned layers.
Must be called inside withSuppressedModelRecording so that the individual property mutations don't trigger recordAndMarkDirty.
clearEffectiveSidebearingKey(side: SidebearingSide) -> None
setDirectSidebearing(side: SidebearingSide, value: float | int) -> None
translateMaterializedBackgroundLayerContentsX(deltaX: float | int) -> None
Keep an existing background drawing aligned with a foreground X shift. Virtual empty backgrounds remain unmaterialized and are intentionally ignored.
recomputeOwnMetricsKeys() -> bool
Resolve and apply this layer's own metrics keys (left/right) without scanning the full font. Use during interactive editing (keyboard/mouse) where only the current layer needs updating.
isAutomaticAlignedLayer() -> bool
assignAutomaticCompositeKerningGroups() -> bool
Copy kerning groups from resolved automatic bases onto this glyph. Invoked only when enabling automatic alignment makes the layer automatic.
getAutomaticComponentTargetAnchorOptions(component: [Component](#component)) -> list[str]
rebuildAutomaticComposition(sourceDataCache: WeakMap<object | None = None, AutomaticCompositionSourceData>) -> bool
applyAutomaticCompositionToLayerData(layerData: { shapes?: Unsafe[]; width?: number; }, sourceDataCache: WeakMap<object | None = None, AutomaticCompositionSourceData>) -> bool
Apply automatic component anchoring and derived width to mutable layer data without mutating the model layer itself.
This is used by live editor interactions, such as resize-box scaling, where component transforms are already edited on a working copy and only the automatic translations and width need to be refreshed.
resolveMetricsKey(side: SidebearingSide, stack: Set<string>) -> MetricsKeyResolution
applySidebearingInput(side: SidebearingSide, rawValue: str) -> MetricsKeyResolution
getPathSegment() -> list[(string | number)]
getMaster() -> [Master](#master) | None
Get the resolved master object for this layer. Returns a Master only when this layer is a DefaultForMaster layer.
getComputedName() -> str
findAnchor(anchorName: str) -> [Anchor](#anchor) | None
addShape(shape: Babelfont.Shape) -> [Shape](#shape)
Add a new shape to the layer
addPath(closed: bool | dict, Unsafe>) -> [Path](#path)
Add a new path to the layer
Example:
path = layer.addPath(closed=True)
addComponent(reference: str, transform: list[float | int] | Babelfont.DecomposedAffine | None = None) -> [Component](#component)
Add a new component to the layer
Example:
component = layer.addComponent("A")
# With transformation matrix (legacy 6-element format converted to DecomposedAffine)
component = layer.addComponent("acutecomb", [1, 0, 0, 1, 250, 500])
insertShapeAt(index: float | int, shape: Babelfont.Shape) -> [Shape](#shape)
Insert a new shape at the specified index
splitOpenPathAtNode(pathOrIndex: float | int | [Shape](#shape) | [Path](#path), nodeIndex: float | int) -> { shapeIndex: number; insertedShapeIndex: number } | None
Split an open path into two open paths at an interior on-curve node.
connectOpenPathEndpoints(sourcePathOrIndex: float | int | [Shape](#shape) | [Path](#path), sourceEdge: 'start' | 'end', targetPathOrIndex: float | int | [Shape](#shape) | [Path](#path), targetEdge: 'start' | 'end') -> { shapeIndex: number; boundaryNodeIndex: number; closed: boolean; } | None
Connect two open-path endpoints or close a single open path by merging its endpoints.
removeShape(shapeOrIndex: float | int | [Shape](#shape) | [Path](#path) | [Component](#component)) -> None
Remove a shape at the specified index
addAnchor(x: float | int, y: float | int, name: str | None = None) -> [Anchor](#anchor)
Add a new anchor to the layer
Example:
anchor = layer.addAnchor(250, 700, "top")
addGuide(pos: Babelfont.Position, name: str | None = None, color: Babelfont.Color | None = None) -> [Guide](#guide)
removeAnchor(index: float | int) -> None
Remove an anchor at the specified index
removeGuide(index: float | int) -> None
processPathSegments(pathData: { nodes: Unsafe[]; closed?: boolean; }) -> Array<{ points: Array<{ x: number; y: number }>; type: 'line' | 'quadratic' | 'cubic'; }>
Process a path into Bezier curve segments Handles the babelfont node format where:
- Nodes can have 'type' (lowercase: o, c, l, q, etc.) or 'nodetype' (capitalized: OffCurve, Curve, Line, etc.)
- Segments are sequences: [oncurve] [offcurve*] [oncurve]
- For closed paths, the path can start with offcurve nodes
getPathSegmentDescriptors(pathData: { nodes: Unsafe[]; closed?: boolean; }) -> Array<{ segmentId: number; type: 'line' | 'quadratic' | 'cubic'; points: Array<{ x: number; y: number }>; startNodeIndex: number; endNodeIndex: number; controlNodeIndices: number[]; runStartNodeIndex: number; runEndNodeIndex: number; runControlNodeIndices: number[]; segmentIndexInRun: number; wrapsAround: boolean; }>
calculatePathBounds(pathData: { nodes?: Unsafe[]; closed?: boolean; }) -> { minX: number; minY: number; maxX: number; maxY: number; width: number; height: number; } | None
calculateShapeBounds(shapes: list[Unsafe] | None, parentTransform: list[float | int]) -> { minX: number; minY: number; maxX: number; maxY: number; width: number; height: number; } | None
calculateSvgPathBounds(pathData: str) -> { minX: number; minY: number; maxX: number; maxY: number; width: number; height: number; } | None
getAllPaths() -> list[Babelfont.Path]
Get all paths in this layer including transformed paths from components (recursively flattened)
calculateBoundingBox(layerData: Unsafe, includeAnchors: bool, font: [Font](#font) | None = None, masterId: str | None = None) -> { minX: number; minY: number; maxX: number; maxY: number; width: number; height: number; } | None
Calculate bounding box for layer data
getBoundingBox(includeAnchors: bool) -> { minX: number; minY: number; maxX: number; maxY: number; width: number; height: number; } | None
Calculate bounding box for this layer
getIntersectionsOnLine(p1: { x: number; y: number }, p2: { x: number; y: number }, includeComponents: bool) -> Array<{ x: number; y: number; t: number }>
Calculate intersections between a line segment and all paths in this layer
getSidebearingsAtHeight(y: float | int) -> { left: number; right: number; } | None
Calculate sidebearings at a given Y height by measuring distance from glyph edges to first/last outline intersections
getMatchingLayerOnGlyph(glyphName: str) -> [Layer](#layer) | None
Find the exact matching stored layer on another glyph for this layer's effective designspace location.
toString() -> str
Shapelink
Shape wrapper that can contain either a Component or a Path
Access:
path = layer.paths[0]
shape = path.parent()
Methodslink
getPathSegment() -> list[(string | number)]
isComponent() -> bool
Check if this shape is a component
isPath() -> bool
Check if this shape is a path
asComponent() -> [Component](#component)
Get as Component (throws if not a component)
asPath() -> [Path](#path)
Get as Path (throws if not a path)
toString() -> str
Pathlink
Path (contour) in a layer
Access:
path = layer.paths[0]
Propertieslink
Read/Write Properties
nodes(list[Node])closed(bool)format_specific(dict | None)
Read-Only Properties
id(str | None): Stable identifier for CRDT addressing. Generated on load; preserved across edits.
Methodslink
getPathSegment() -> list[(string | number)]
insertNode(index: float | int, x: float | int, y: float | int, nodetype: Babelfont.NodeType, smooth: bool | None = None) -> [Node](#node)
Insert a node at the specified index
Example:
path.insertNode(1, 150, 250, "Line") # Insert at index 1
removeNode(index: float | int) -> None
Remove a node at the specified index
Example:
path.removeNode(0) # Remove first node
appendNode(x: float | int, y: float | int, nodetype: Babelfont.NodeType, smooth: bool | None = None) -> [Node](#node)
Append a node to the end of the path
Example:
path.appendNode(100, 200, "Line")
path.appendNode(300, 400, "Curve", smooth=True)
toString() -> str
Nodelink
Point in a path
Access:
node = path.nodes[0]
Propertieslink
Read/Write Properties
selected(bool): Whether this node is selected in the active outline editor.x(float | int)y(float | int)nodetype(Babelfont.NodeType)smooth(bool | None)
Read-Only Properties
id(str | None): Stable identifier for CRDT addressing. Generated on load; preserved across edits.
Methodslink
getPathSegment() -> list[(string | number)]
toString() -> str
Componentlink
Component reference to another glyph
Access:
component = layer.components[0]
Propertieslink
Read/Write Properties
selected(bool): Whether this component is selected in the active outline editor.reference(str)transform(Babelfont.DecomposedAffine)location(DesignspaceLocation | None)anchor(str | None): Glyphs attachment anchor name stored in format_specific.automaticAlignment(bool): Whether this component explicitly opts into Glyphs automatic alignment. Unlike isAutomaticAligned(), this is per-component metadata and does not depend on the rest of its containing layer.format_specific(dict | None)
Read-Only Properties
id(str | None): Stable identifier for CRDT addressing. Generated on load; preserved across edits.
Methodslink
getPathSegment() -> list[(string | number)]
isAutomaticAligned() -> bool
Returns whether every component in the containing layer explicitly opts into Glyphs automatic alignment.
hasExplicitManualAlignment() -> bool
Returns whether this component itself carries Glyphs' explicit manual alignment metadata, independent of the layer's effective state.
toAffineArray() -> list[float | int]
Convert transform to affine matrix array [a, b, c, d, e, f] Uses the proper DecomposedAffineTransform utility
toString() -> str
getTransformedPaths() -> list[Babelfont.Path]
Get all paths from this component with transforms applied recursively Automatically determines the correct master by walking up the parent chain
Anchorlink
Anchor point in a layer
Access:
anchor = layer.anchors[0]
Propertieslink
Read/Write Properties
selected(bool): Whether this anchor is selected in the active outline editor.x(float | int)y(float | int)name(str | None)format_specific(dict | None)
Read-Only Properties
id(str | None): Stable identifier for CRDT addressing. Generated on load; preserved across edits.
Methodslink
getPathSegment() -> list[(string | number)]
toString() -> str
Guidelink
Guideline in a layer or master
Access:
guide = layer.guides[0]
# or
guide = master.guides[0]
Propertieslink
Read/Write Properties
selected(bool): Whether this guide is selected in the active outline editor.pos(Babelfont.Position)name(str | None)color(Babelfont.Color | None)format_specific(dict | None)
Read-Only Properties
id(str | None): Stable identifier for CRDT addressing. Generated on load; preserved across edits.
Methodslink
getPathSegment() -> list[(string | number)]
toString() -> str
Axislink
Variation axis in a variable font
Access:
axis = font.axes[0]
# or
axis = font.findAxisByTag("wght")
Propertieslink
All properties are read/write:
name(dict[str, str])tag(str)id(str)min(float | int | None)max(float | int | None)default(float | int | None)map(list[[number, number]] | None)hidden(bool | None)values(list[float | int] | None)format_specific(dict | None)
Methodslink
getPathSegment() -> list[(string | number)]
toString() -> str
Masterlink
Master/source in a design space
Access:
master = font.masters[0]
# or
master = font.findMaster("master-id")
Propertieslink
Read/Write Properties
name(dict[str, str])id(str)location(DesignspaceLocation | None)metrics(dict)kerning(dict)kerning_rtl(dict)custom_ot_values(list[Unsafe] | None)format_specific(dict | None)
Read-Only Properties
guides(list[Guide] | None)
Methodslink
getPathSegment() -> list[(string | number)]
addGuide(pos: Babelfont.Position, name: str | None = None, color: Babelfont.Color | None = None) -> [Guide](#guide)
removeGuide(index: float | int) -> None
reinterpolateLayers() -> Promise<void>
delete() -> Promise<boolean>
toString() -> str
Instancelink
Named instance in a variable font
Access:
instance = font.instances[0]
Propertieslink
All properties are read/write:
id(str)name(dict[str, str])location(DesignspaceLocation | None)custom_names(dict[str, dict[str, str] | None])variable(bool | None)linked_style(str | None)format_specific(dict | None)
Methodslink
getPathSegment() -> list[(string | number)]
toString() -> str
Complete Exampleslink
Example 1: Creating a Simple Glyphlink
# Get the font
font = Font()
# Create a new glyph
glyph = font.addGlyph("myGlyph", "Base")
# Add a layer
layer = glyph.addLayer(500) # 500 units wide
# Create a rectangle path
path = layer.addPath(closed=True)
path.appendNode(100, 0, "Line")
path.appendNode(400, 0, "Line")
path.appendNode(400, 700, "Line")
path.appendNode(100, 700, "Line")
print(f"Created glyph: {glyph.name}")
Example 2: Modifying Existing Glyphslink
font = Font()
# Find glyph A
glyph_a = font.findGlyph("A")
if glyph_a:
layer = glyph_a.layers[0]
# Modify all nodes
for path in layer.paths:
for node in path.nodes:
node.x += 10 # Shift 10 units right
node.y += 5 # Shift 5 units up
# Add an anchor
layer.addAnchor(250, 700, "top")
print(f"Modified {glyph_a.name}")
Example 3: Working with Componentslink
font = Font()
# Create a glyph with a component
glyph = font.addGlyph("Aacute", "Base")
layer = glyph.addLayer(600)
# Add base letter component
base = layer.addComponent("A")
# Add accent component with transformation
# Transform: [scaleX, skewX, skewY, scaleY, translateX, translateY]
accent = layer.addComponent("acutecomb", [1, 0, 0, 1, 250, 500])
print(f"Created {glyph.name} with components")
Example 4: Iterating Through Fontlink
font = Font()
# Count nodes across all glyphs
total_nodes = 0
for glyph in font.glyphs:
if glyph.layers:
for layer in glyph.layers:
for path in layer.paths:
total_nodes += len(path.nodes)
print(f"Total nodes in font: {total_nodes}")
Example 5: Working with Variable Fontslink
font = Font()
# Check if font has axes
if font.axes:
print("Variable font axes:")
for axis in font.axes:
print(f" {axis.tag}: {axis.min} - {axis.max} (default: {axis.default})")
# Check masters
if font.masters:
print(f"\nFont has {len(font.masters)} masters:")
for master in font.masters:
location_str = ", ".join(f"{k}={v}" for k, v in (master.location or {}).items())
print(f" Master: {location_str}")
Example 6: Batch Processing Glyphslink
font = Font()
# Scale all glyphs by 1.5x
scale_factor = 1.5
for glyph in font.glyphs:
if glyph.layers:
for layer in glyph.layers:
# Scale width
layer.width *= scale_factor
# Scale all outline paths
for path in layer.paths:
for node in path.nodes:
node.x *= scale_factor
node.y *= scale_factor
# Scale anchors
if layer.anchors:
for anchor in layer.anchors:
anchor.x *= scale_factor
anchor.y *= scale_factor
print(f"Scaled {len(font.glyphs)} glyphs by {scale_factor}x")
Example 7: Kerning and i18n Dictionarieslink
font = Font()
master = font.masters[0]
# Ensure nested kerning bucket exists
if "A" not in master.kerning:
master.kerning["A"] = {}
master.kerning["A"]["V"] = -90
master.kerning["A"]["W"] = -70
# Read values with standard dict APIs
av_value = master.kerning["A"].get("V")
print(f"A/V kerning: {av_value}")
# Update localized names
font.names.familyName["dflt"] = "Counterpunch Sans"
font.names.familyName["de"] = "Counterpunch Sans DE"
font.names.familyName["fr"] = "Counterpunch Sans FR"
font.names.familyName["ar"] = "كاونتربنش سانس"
Example 8: Editing OpenType Features Listlink
font = Font()
# features is a live list-like wrapper
feature_items = font.features.features
# Append a new feature tuple: [tag, code-record]
feature_items.append(["liga", {"code": "sub f i by fi;"}])
# Insert at the top
feature_items.insert(0, ["kern", {"code": "pos A V -80;"}])
# Remove entries with normal list operations
if len(feature_items) > 5:
feature_items.pop()
del feature_items[0]
Tips and Best Practiceslink
Performancelink
- Changes to properties are immediately reflected in the underlying JSON data
- No need to "save" or "commit" changes - they are live
- Dictionary-like fields are live Python mappings (no routine
.to_py()needed) - Array fields (for example
font.features.features) are live list-like wrappers - For batch operations, group changes together to minimize redraws
Type Checkinglink
# Use the filtered convenience collections when you know what you want
for path in layer.paths:
# Work with path
for component in layer.components:
# Work with component
Safe Property Accesslink
# Check for optional properties
if glyph.layers:
for layer in glyph.layers:
for path in layer.paths:
for node in path.nodes:
print(f"Node at ({node.x}, {node.y})")
Guardrails for Dictionary Fieldslink
Dictionary-like fields reject scalar overwrite assignments to prevent broken model state.
# ❌ Avoid replacing a language dictionary with a string
# font.names.familyName = "My Font"
# ✅ Set a language value inside the dictionary
font.names.familyName["dflt"] = "My Font"
# ✅ Or replace with a full mapping
font.names.familyName = {
"dflt": "My Font",
"de": "Meine Schrift"
}
Accessing Nodes Examplelink
# Direct access (may fail if properties are None)
# glyph.layers[0].paths[0].nodes # DON'T DO THIS
# Safe access with checks:
layer = glyph.layers[0] if glyph.layers else None
if layer and layer.paths:
path = layer.paths[0]
nodes = path.nodes
print(f"Path has {len(nodes)} nodes")
Coordinate Systemlink
- Origin (0, 0) is at the baseline on the left
- Y-axis points upward
- All coordinates are in font units (1/upm of the em square)
Common Issueslink
Q: Why does glyph.layers[0].paths[0].nodes fail?
A: Optional properties may be None. Use safe access:
# Check each step
if glyph.layers and len(glyph.layers) > 0:
layer = glyph.layers[0]
if layer.paths and len(layer.paths) > 0:
path = layer.paths[0]
nodes = path.nodes # Now safe to access
Q: How do I access only paths or only components in a layer?
A: Use layer.paths and layer.components directly:
for path in layer.paths:
print(len(path.nodes))
for component in layer.components:
print(component.reference)
Generated by generate-api-docs.mjs