@eryx/font Module

Font loading, inspection, shaping, and rasterization.

This library opens OpenType, TrueType, and font collection files from disk, from memory, or from the host system font registry. A Typeface represents an unsized face and exposes font metadata, glyph coverage, raw OpenType tables, and variable-font axes. Calling Typeface:at() creates a sized Font, which can shape UTF-8 text with HarfBuzz, measure text, inspect glyph metrics and outlines, rasterize individual glyphs, or render text into a pixel buffer.

Text shaping operates on one run at a time. Resolve bidi order, split text into script/language/font runs, apply fallback fonts, and perform wrapping before calling Font:shape() or the higher-level measurement and rendering helpers.

Example:

local font = require("@eryx/font")

local face = font.findSystem("Inter", { weight = 600 }) or font.openFile("Inter-Regular.ttf")
local body = face:at(18)

local measure = body:measure("Hello, world!")
print(measure.width, measure.height)

local image = body:render("Hello, world!", {
	width = 320,
	align = "center",
	mode = "gray",
})

body:close()
face:close()

Variable-font example:

local face = font.openFile("Recursive_VF.ttf")
local display = face:at(48, {
	variations = {
		wght = 750,
		slnt = -8,
	},
})

Summary

Classes

family: string
style: string
path: string?
closed: boolean
unitsPerEm: number
glyphCount: number
faceIndex: number
weight: number
stretch: number
italic: boolean
variations: { VariationAxis }
Typeface:hasGlyph(codepoint: number)boolean
Typeface:glyphId(codepoint: number)number?
Typeface:hasText(text: string)boolean
Typeface:missingGlyphs(text: string){ MissingGlyph }
Typeface:table(tag: string)buffer?
Typeface:at(size: number, options: FontOptions?)Font
text: string
closed: boolean
glyphs: { ShapedGlyph }
advance: Vector2
bounds: Rect
face: Typeface
size: number
closed: boolean
metrics: FontMetrics
Font:shape(text: string, options: ShapeOptions?)ShapedRun
Font:measure(text: string, options: ShapeOptions?)TextMeasure
Font:bounds(text: string, options: ShapeOptions?)Rect
Font:glyphMetrics(glyphId: number, options: FontOptions?)GlyphMetrics
Font:outlineGlyph(glyphId: number, options: FontOptions?)GlyphOutline?
Font:rasterizeGlyph(glyphId: number, options: RasterizeOptions?)GlyphBitmap
Font:renderGlyph(glyphId: number, options: RenderOptions?)RenderedBuffer
Font:render(text: string, options: RenderOptions?)RenderedBuffer
Font:close()()

Functions

font.openFile(path: string, options: OpenOptions?)Typeface
font.fromBuffer(data: buffer, options: OpenOptions?)Typeface
font.findSystem(family: string, options: SystemFontOptions?)Typeface?

API Reference

Classes

Typeface

An unsized font face.

Properties

family: string

Family name reported by the font.

style: string

Style name reported by the font.

path: string?

Source file path when the face was opened from disk or the system.

closed: boolean

Whether this typeface has been closed.

unitsPerEm: number

Design units per em.

glyphCount: number

Number of glyphs in the face.

faceIndex: number

0-based face index for font collections.

weight: number

OpenType weight class.

stretch: number

OpenType width class.

italic: boolean

Whether the face is italic or oblique.

Selected OS/2 table metrics when available.

variations: { VariationAxis }

Variable-font axes exposed by this face.

Typeface:hasGlyph

Return whether the face contains a glyph for a Unicode codepoint.

Typeface:hasGlyph(codepoint: number)boolean

Parameters

codepoint: number

Unicode codepoint to test.

Returns

boolean

Whether the face has a glyph for the codepoint.

Typeface:glyphId

Return the glyph id for a Unicode codepoint.

Typeface:glyphId(codepoint: number)number?

Parameters

codepoint: number

Unicode codepoint to look up.

Returns

number?

Glyph id, or nil when the codepoint is missing.

Typeface:hasText

Return whether every codepoint in a UTF-8 string has a glyph.

Typeface:hasText(text: string)boolean

Parameters

text: string

Text to check.

Returns

boolean

Whether every codepoint has a glyph.

Typeface:missingGlyphs

Return the codepoints in a UTF-8 string that are missing from this face.

Typeface:missingGlyphs(text: string){ MissingGlyph }

Parameters

text: string

Text to check.

Returns

Missing glyph records in text order.

Typeface:names

Return decoded records from the font name table.

Typeface:names(){ FontNameRecord }

Returns

Name records.

Typeface:table

Return raw data for an OpenType table.

Typeface:table(tag: string)buffer?

Parameters

tag: string

4-byte OpenType table tag, such as "head", "name", or "OS/2".

Returns

buffer?

Table bytes, or nil when the table is absent.

Typeface:codepoints

Return the Unicode cmap entries exposed by this face.

Typeface:codepoints(){ CmapEntry }

Returns

Character-to-glyph mapping entries.

Typeface:at

Create a sized font from this typeface. size is in CSS-style pixels, not points.

Typeface:at(size: number, options: FontOptions?)Font

Parameters

size: number

Pixel size.

options: FontOptions?

Sizing and rendering options.

Returns

Sized font.

Typeface:close

Release resources held by this typeface.

Typeface:close()()

ShapedRun

A shaped text run.

Properties

text: string

Original text that was shaped.

closed: boolean

Whether this shaped run has been closed.

glyphs: { ShapedGlyph }

Positioned glyphs in shaping order.

advance: Vector2

Final pen advance.

bounds: Rect

Ink bounds.

ShapedRun:close

Release resources held by this shaped run.

ShapedRun:close()()

Font

A sized font created from a Typeface.

Properties

face: Typeface

Source typeface.

size: number

Pixel size.

closed: boolean

Whether this font has been closed.

metrics: FontMetrics

Font-wide metrics at this size.

Font:shape

Shape a UTF-8 text run.

Font:shape(text: string, options: ShapeOptions?)ShapedRun

Parameters

text: string

Text to shape.

options: ShapeOptions?

Shaping options.

Returns

Shaped run.

Font:measure

Measure shaped text.

Font:measure(text: string, options: ShapeOptions?)TextMeasure

Parameters

text: string

Text to measure.

options: ShapeOptions?

Shaping options.

Returns

Text measurement.

Font:bounds

Return ink bounds for shaped text.

Font:bounds(text: string, options: ShapeOptions?)Rect

Parameters

text: string

Text to measure.

options: ShapeOptions?

Shaping options.

Returns

Ink bounds.

Font:glyphMetrics

Return metrics for a glyph id.

Font:glyphMetrics(glyphId: number, options: FontOptions?)GlyphMetrics

Parameters

glyphId: number

Glyph id to inspect.

options: FontOptions?

Font options to apply for this lookup.

Returns

Glyph metrics.

Font:outlineGlyph

Return a vector outline for a glyph id.

Font:outlineGlyph(glyphId: number, options: FontOptions?)GlyphOutline?

Parameters

glyphId: number

Glyph id to outline.

options: FontOptions?

Font options to apply for this lookup.

Returns

Glyph outline, or nil when no outline is available.

Font:rasterizeGlyph

Rasterize a glyph id into a glyph bitmap.

Font:rasterizeGlyph(glyphId: number, options: RasterizeOptions?)GlyphBitmap

Parameters

glyphId: number

Glyph id to rasterize.

Rasterization options.

Returns

Glyph bitmap.

Font:renderGlyph

Render a glyph id into an image buffer.

Font:renderGlyph(glyphId: number, options: RenderOptions?)RenderedBuffer

Parameters

glyphId: number

Glyph id to render.

options: RenderOptions?

Rendering options.

Returns

Rendered image buffer.

Font:render

Render UTF-8 text into an image buffer. Multiline rendering splits on "\n". Mixed-direction bidi text still needs run itemization before shaping.

Font:render(text: string, options: RenderOptions?)RenderedBuffer

Parameters

text: string

Text to render.

options: RenderOptions?

Rendering options.

Returns

Rendered image buffer.

Font:close

Release resources held by this sized font.

Font:close()()

Functions

font.openFile

Open a font face from a file path.

font.openFile(path: string, options: OpenOptions?)Typeface

Parameters

path: string

File path to an OpenType, TrueType, TTC, or OTC font.

options: OpenOptions?

Open options.

Returns

Opened typeface.

font.fromBuffer

Open a font face from an in-memory font buffer.

font.fromBuffer(data: buffer, options: OpenOptions?)Typeface

Parameters

data: buffer

Font bytes.

options: OpenOptions?

Open options.

Returns

Opened typeface.

font.findSystem

Find and open the best matching installed system font for a family name.

font.findSystem(family: string, options: SystemFontOptions?)Typeface?

Parameters

family: string

Family name to search for.

System font match options.

Returns

Opened typeface, or nil when no matching font is found.

font.listSystem

List discovered system font faces.

font.listSystem(options: SystemFontOptions?){ SystemFontInfo }

Parameters

System font discovery options.

Returns

Discovered font faces.

font.listSystemFamilies

List discovered system font faces grouped by family.

font.listSystemFamilies(options: SystemFontOptions?){ SystemFontFamilyInfo }

Parameters

System font discovery options.

Returns

Discovered font families.

font.refreshSystem

Refresh the process-local system font cache.

font.refreshSystem(options: SystemFontOptions?)()

Parameters

System font discovery options.

Types

OpenOptions

Options for opening a font face from a file or buffer.

type OpenOptions = { faceIndex: number? }
faceIndex: number?

0-based index for TTC/OTC font collections.

SystemFontOptions

Options for system font discovery and matching.

type SystemFontOptions = { faceIndex: number?, style: string?, weight: number?, stretch: number?, italic: boolean?, directories: { string }?, refresh: boolean? }
faceIndex: number?

0-based index for TTC/OTC font collections.

style: string?

Preferred style name, such as "Regular", "Bold", or "Italic".

weight: number?

Preferred OpenType weight class. Typical values are 100 through 900.

stretch: number?

Preferred OpenType width class, where 5 is normal width.

italic: boolean?

Preferred italic or oblique state.

directories: { string }?

Extra directories to scan in addition to the platform defaults.

refresh: boolean?

Rebuild the process-local system font cache before answering.

SystemFontInfo

Metadata for a discovered system font face.

type SystemFontInfo = { family: string, style: string, faceIndex: number, weight: number, stretch: number, italic: boolean, path: string | { string }, paths: { string } }
family: string

Family name reported by the font.

style: string

Style name reported by the font.

faceIndex: number

0-based face index for font collections.

weight: number

OpenType weight class. Typical values are 100 through 900.

stretch: number

OpenType width class, where 5 is normal width.

italic: boolean

Whether the face is italic or oblique.

path: string | { string }

A single path for the common case, or all matching paths when duplicates were found.

paths: { string }

All discovered paths for this family/style/face combination.

SystemFontFamilyInfo

A system font family grouped with all discovered faces in that family.

type SystemFontFamilyInfo = { family: string, faces: { SystemFontInfo } }
family: string

Family name.

faces: { SystemFontInfo }

Faces discovered for this family.

VariationAxis

OpenType variable-font axis metadata.

type VariationAxis = { tag: string, name: string?, min: number, max: number, default: number }
tag: string

4-byte OpenType variation tag, such as "wght", "wdth", or "slnt".

name: string?

Human-readable axis name when present in the font.

min: number

Minimum supported design coordinate.

max: number

Maximum supported design coordinate.

default: number

Default design coordinate.

FontNameRecord

A decoded entry from a font name table.

type FontNameRecord = { nameId: number, platformId: number, encodingId: number, languageId: number, text: string, raw: buffer }
nameId: number

OpenType name identifier.

platformId: number

OpenType platform identifier.

encodingId: number

OpenType encoding identifier.

languageId: number

OpenType language identifier.

text: string

Decoded text for this name record.

raw: buffer

Raw name bytes as stored in the font.

CmapEntry

A character-to-glyph mapping entry.

type CmapEntry = { codepoint: number, glyphId: number }
codepoint: number

Unicode codepoint.

glyphId: number

Glyph id used by the font.

OS2Metrics

Selected metrics from a font OS/2 table.

type OS2Metrics = { version: number, weight: number, stretch: number, selection: number, typoAscender: number, typoDescender: number, typoLineGap: number, winAscent: number, winDescent: number, subscriptXSize: number, subscriptYSize: number, superscriptXSize: number, superscriptYSize: number, strikeoutSize: number, strikeoutPosition: number, xHeight: number?, capHeight: number? }
version: number

OS/2 table version.

weight: number

OpenType weight class.

stretch: number

OpenType width class.

selection: number

OS/2 selection bitfield.

typoAscender: number

Typographic ascender in font units.

typoDescender: number

Typographic descender in font units.

typoLineGap: number

Typographic line gap in font units.

winAscent: number

Windows ascent in font units.

winDescent: number

Windows descent in font units.

subscriptXSize: number

Recommended subscript glyph width in font units.

subscriptYSize: number

Recommended subscript glyph height in font units.

superscriptXSize: number

Recommended superscript glyph width in font units.

superscriptYSize: number

Recommended superscript glyph height in font units.

strikeoutSize: number

Recommended strikeout thickness in font units.

strikeoutPosition: number

Recommended strikeout position in font units.

xHeight: number?

Lowercase x-height in font units when available.

capHeight: number?

Capital letter height in font units when available.

HintingMode

FreeType hinting mode used when sizing and rasterizing glyphs.

type HintingMode = "none" | "light" | "normal" | "mono"

FontOptions

Options for creating or using a sized font.

type FontOptions = { dpi: number?, hinting: HintingMode?, antialias: boolean?, embeddedBitmaps: boolean?, colorGlyphs: boolean?, variations: { [string]: number }? }
dpi: number?

Device DPI for backends that need physical point-size conversion.

hinting: HintingMode?

Hinting mode.

antialias: boolean?

Whether to use antialiasing when rasterizing.

embeddedBitmaps: boolean?

Whether embedded bitmap strikes may be used.

colorGlyphs: boolean?

Whether color glyph layers may be used.

variations: { [string]: number }?

OpenType variation coordinates keyed by 4-byte axis tags.

MissingGlyph

A missing codepoint reported by Typeface:missingGlyphs().

type MissingGlyph = { codepoint: number, offset: number }
codepoint: number

Unicode codepoint that has no glyph.

offset: number

0-based byte offset into the original UTF-8 string.

TypeFace

Deprecated alias for Typeface.

Implements: Typeface

FontMetrics

Metrics for a sized font in pixels.

type FontMetrics = { ascent: number, descent: number, lineGap: number, height: number, underlinePosition: number?, underlineThickness: number?, strikethroughPosition: number?, strikethroughThickness: number? }
ascent: number

Distance from baseline to ascender.

descent: number

Distance from baseline to descender.

lineGap: number

Recommended gap between lines.

height: number

Recommended line height.

underlinePosition: number?

Underline position relative to the baseline when available.

underlineThickness: number?

Underline thickness when available.

strikethroughPosition: number?

Strikethrough position relative to the baseline when available.

strikethroughThickness: number?

Strikethrough thickness when available.

TextDirection

Text direction for shaping.

type TextDirection = "auto" | "ltr" | "rtl" | "ttb" | "btt"

ClusterLevel

HarfBuzz cluster granularity.

type ClusterLevel = "monotoneGraphemes" | "monotoneCharacters" | "characters"

ShapeOptions

Options for shaping a single text run.

type ShapeOptions = { direction: TextDirection?, script: string?, language: string?, features: { [string]: boolean | number }?, clusterLevel: ClusterLevel? }
direction: TextDirection?

Text direction.

script: string?

ISO 15924 script tag, such as "Latn", "Arab", "Deva", or "auto".

language: string?

BCP 47 language tag, such as "en" or "ar".

features: { [string]: boolean | number }?

OpenType feature settings keyed by feature tag.

clusterLevel: ClusterLevel?

Cluster granularity reported in shaped glyphs.

ShapedGlyph

A positioned glyph from a shaped text run.

type ShapedGlyph = { id: number, cluster: number, xAdvance: number, yAdvance: number, xOffset: number, yOffset: number }
id: number

Glyph id.

cluster: number

0-based byte offset into the original UTF-8 string.

xAdvance: number

Horizontal advance in pixels.

yAdvance: number

Vertical advance in pixels.

xOffset: number

Horizontal offset in pixels.

yOffset: number

Vertical offset in pixels.

GlyphMetrics

Metrics for a single glyph in a sized font.

type GlyphMetrics = { width: number, height: number, horiBearingX: number, horiBearingY: number, horiAdvance: number, vertBearingX: number?, vertBearingY: number?, vertAdvance: number? }
width: number

Glyph bitmap width in pixels.

height: number

Glyph bitmap height in pixels.

horiBearingX: number

Horizontal bearing X in pixels.

horiBearingY: number

Horizontal bearing Y in pixels.

horiAdvance: number

Horizontal advance in pixels.

vertBearingX: number?

Vertical bearing X in pixels when available.

vertBearingY: number?

Vertical bearing Y in pixels when available.

vertAdvance: number?

Vertical advance in pixels when available.

PathMoveToCommand

A path command that moves the current point.

type PathMoveToCommand = { type: "moveTo", x: number, y: number }
type: "moveTo"

Command discriminator.

x: number

Destination X coordinate.

y: number

Destination Y coordinate.

PathLineToCommand

A path command that draws a line.

type PathLineToCommand = { type: "lineTo", x: number, y: number }
type: "lineTo"

Command discriminator.

x: number

Destination X coordinate.

y: number

Destination Y coordinate.

PathQuadToCommand

A path command that draws a quadratic Bezier curve.

type PathQuadToCommand = { type: "quadTo", controlX: number, controlY: number, x: number, y: number }
type: "quadTo"

Command discriminator.

controlX: number

Control point X coordinate.

controlY: number

Control point Y coordinate.

x: number

Destination X coordinate.

y: number

Destination Y coordinate.

PathCubicToCommand

A path command that draws a cubic Bezier curve.

type PathCubicToCommand = { type: "cubicTo", control1X: number, control1Y: number, control2X: number, control2Y: number, x: number, y: number }
type: "cubicTo"

Command discriminator.

control1X: number

First control point X coordinate.

control1Y: number

First control point Y coordinate.

control2X: number

Second control point X coordinate.

control2Y: number

Second control point Y coordinate.

x: number

Destination X coordinate.

y: number

Destination Y coordinate.

PathCommand

A vector outline drawing command for a glyph.

GlyphOutline

A glyph outline and its layout metrics.

type GlyphOutline = { commands: { PathCommand }, bounds: Rect, advanceX: number, advanceY: number }
commands: { PathCommand }

Drawing commands in glyph coordinate order.

bounds: Rect

Outline bounds in pixels.

advanceX: number

Horizontal advance in pixels.

advanceY: number

Vertical advance in pixels.

RasterizeMode

Mode for rasterizing an individual glyph.

type RasterizeMode = "mono" | "gray" | "lcd" | "color"

RasterizeOptions

Options for rasterizing an individual glyph.

type RasterizeOptions = { mode: RasterizeMode?, subpixelX: number?, subpixelY: number? }

Rasterization mode.

subpixelX: number?

Horizontal subpixel offset.

subpixelY: number?

Vertical subpixel offset.

RenderMode

Mode for rendering text buffers.

type RenderMode = "mono" | "gray"

TextAlign

Horizontal alignment for multiline rendering.

type TextAlign = "left" | "center" | "right"

RenderOptions

Options for rendering text into a pixel buffer.

type RenderOptions = { direction: TextDirection?, script: string?, language: string?, features: { [string]: boolean | number }?, clusterLevel: ClusterLevel?, dpi: number?, hinting: HintingMode?, antialias: boolean?, embeddedBitmaps: boolean?, colorGlyphs: boolean?, variations: { [string]: number }?, mode: RenderMode?, subpixelX: number?, subpixelY: number?, width: number?, lineHeight: number?, align: TextAlign? }
direction: TextDirection?

Text direction.

script: string?

ISO 15924 script tag, such as "Latn", "Arab", or "Deva".

language: string?

BCP 47 language tag, such as "en" or "ar".

features: { [string]: boolean | number }?

OpenType feature settings keyed by feature tag.

clusterLevel: ClusterLevel?

Cluster granularity reported during shaping.

dpi: number?

Device DPI for backends that need physical point-size conversion.

hinting: HintingMode?

Hinting mode.

antialias: boolean?

Whether to use antialiasing when rasterizing.

embeddedBitmaps: boolean?

Whether embedded bitmap strikes may be used.

colorGlyphs: boolean?

Whether color glyph layers may be used.

variations: { [string]: number }?

OpenType variation coordinates keyed by 4-byte axis tags.

mode: RenderMode?

Render mode.

subpixelX: number?

Horizontal subpixel offset.

subpixelY: number?

Vertical subpixel offset.

width: number?

Maximum line width for multiline rendering.

lineHeight: number?

Override line height in pixels.

align: TextAlign?

Horizontal alignment for lines.

LcdOrder

Subpixel component order for LCD glyph bitmaps.

type LcdOrder = "rgb" | "bgr" | "vrgb" | "vbgr"

GlyphBitmapFormat

Pixel format for an individual glyph bitmap.

type GlyphBitmapFormat = "mono1" | "gray8" | "lcd24" | "bgra32"

GlyphBitmap

A rasterized individual glyph.

type GlyphBitmap = { width: number, height: number, pitch: number, left: number, top: number, advanceX: number, advanceY: number, format: GlyphBitmapFormat, lcdOrder: LcdOrder?, buffer: buffer }
width: number

Bitmap width in pixels.

height: number

Bitmap height in pixels.

pitch: number

Bytes per bitmap row.

left: number

Horizontal bitmap origin relative to the pen position.

top: number

Vertical bitmap origin relative to the baseline.

advanceX: number

Horizontal advance in pixels.

advanceY: number

Vertical advance in pixels.

Pixel format.

lcdOrder: LcdOrder?

LCD component order when format is "lcd24".

buffer: buffer

Raw pixel data.

RenderedBuffer

A rendered text or glyph image buffer.

type RenderedBuffer = { width: number, height: number, stride: number, format: "grayAlpha8" | "rgba8", baseline: Vector2, advance: Vector2, bounds: Rect, buffer: buffer }
width: number

Buffer width in pixels.

height: number

Buffer height in pixels.

stride: number

Bytes per image row.

format: "grayAlpha8" | "rgba8"

Pixel format.

baseline: Vector2

Baseline position inside the image.

advance: Vector2

Final pen advance after rendering.

bounds: Rect

Ink bounds inside the image.

buffer: buffer

Raw pixel data.

TextMeasure

Measurement result for shaped text.

type TextMeasure = { width: number, height: number, advance: Vector2, bounds: Rect }
width: number

Measured width in pixels.

height: number

Measured height in pixels.

advance: Vector2

Final pen advance.

bounds: Rect

Ink bounds.

Vector2

A 2D vector.

type Vector2 = { x: number, y: number }
x: number

X coordinate.

y: number

Y coordinate.

Rect

A rectangle.

type Rect = { x: number, y: number, width: number, height: number }
x: number

X coordinate of the top-left corner.

y: number

Y coordinate of the top-left corner.

width: number

Rectangle width.

height: number

Rectangle height.