Skip to content

Text geometry

Read as Markdown

The optional @pibbl/text package converts one text run into editable PathGeometry. HarfBuzz shapes the whole run, including kerning, ligatures, and mark positioning, before Pibbl copies its outlines into independent geometry. Importing the package does not initialize WASM.

import { loadOutlineFont, createTextGeometry } from "@pibbl/text";
async function label(bytes: Uint8Array) {
using font = await loadOutlineFont(bytes);
return createTextGeometry(font, "Hello Pibbl", {
fontSize: 96,
features: { kern: true, liga: true },
});
}

The returned geometry remains usable after the font is disposed. Pass it to <Path style={{ d: result.geometry, fill: "teal" }} />, inspect its segments, or edit its control points. Geometry mutation does not schedule a repaint; update a signal or state after editing, as in the editable text example.

loadOutlineFont(source, options?) accepts a URL string, URL, ArrayBuffer, or Uint8Array. Strings mean URLs; Node callers read filesystem bytes themselves. An offset typed-array view is respected and copied before asynchronous work. OutlineFontOptions.signal cancels a download. Failed or canceled acquisition returns no font owner.

OutlineFont implements dispose() and [Symbol.dispose]() with the same synchronous, idempotent cleanup. Use using font = await loadOutlineFont(...) for a local conversion or retain one font across edits and call dispose() on teardown. A retained font must outlive every conversion that uses it. Loading belongs outside Pibbl’s synchronous component evaluation.

using requires runtime Symbol.dispose support and a compatible syntax target or compiler transform. TypeScript consumers include ESNext.Disposable (or ESNext) in their configured libraries. Pibbl does not install a global polyfill. Explicit dispose() works without using syntax. Generated paths and metrics hold no borrowed WASM views. Disposing a font releases its native resources; the shared WASM memory may retain its high-water capacity for later reuse.

Supported containers are outline TTF and OTF (quadratic TrueType and cubic CFF outlines). WOFF, WOFF2, collections, and system-font/CSS lookup are not supported. No font fallback is performed. Variable fonts use their default instance; there is no axis or face-selection API in this release.

Fonts declaring COLR, SVG, sbix, CBDT, or EBDT presentation tables are rejected by default. Set monochromeFallback: true to explicitly request their ordinary outlines. This does not convert colors, bitmap images, or SVG artwork; a usable outline is still required. The check is conservative for the entire font.

createTextGeometry(font, text, options) is synchronous. TextGeometryOptions requires a finite positive fontSize in logical units. Optional fields are:

Option Meaning
features Up to 64 four-character OpenType tags mapped to booleans, such as { liga: false }.
direction "ltr" or "rtl"; otherwise inferred by HarfBuzz.
script Four-character ISO 15924 script tag, such as "Arab".
language ASCII language tag, such as "ar" or "en-US", up to 63 characters.
missingGlyphs "error" (default) or explicit "notdef" substitution.
maxSegments Integer output limit from 1 to 1,000,000; default 1,000,000.

The origin is baseline (0, 0), with positive Y down. Negative bearings are preserved. RTL glyphs remain in HarfBuzz’s output order. There is no paragraph bidi algorithm, line wrapping, vertical layout, rich text, caret mapping, or font fallback. Tabs and line breaks are rejected.

TextGeometryResult contains:

  • geometry: a new mutable PathGeometry, preserving curves and closed contours.
  • advance: readonly X/Y layout advance, including whitespace.
  • inkBounds: readonly InkBounds (x, y, width, height) using curve extrema, or null for empty ink. This differs from the advance.
  • glyphs: readonly TextGlyph records with glyphId, UTF-16 cluster, segmentStart, segmentCount, x, y, xAdvance, and yAdvance.

Clusters are source string indices, not character, grapheme, or caret indices. Several glyphs may share a cluster, and RTL cluster indices can descend. Whitespace may have advance and zero segments. Metadata describes the initial conversion: later edits do not update its segment ranges, metrics, or bounds. No per-glyph path copies are created eagerly.

Font inputs are limited to 32 MiB, text to 100,000 UTF-16 units, shaped output to 200,000 glyphs, and extraction to a shared 2²⁴ native work-unit budget. Malformed inputs, missing glyphs, nonfinite results, and exceeded limits throw without returning partial geometry. These bounds do not guarantee a shaping timeout. Reuse fonts and generated paths; do not reshape static text every frame.

The published package includes precompiled WASM; consumers need no native SDK. Browser bundlers select browser-only loader code. Bundlers that process new URL(..., import.meta.url) should emit the WASM asset. For a plain esbuild pipeline, copy dist/engine.wasm from the installed package beside the emitted engine chunk and serve it as application/wasm. Test the production output, including any application base path. Node loading resolves the packaged binary relative to the installed loader.

Build-time generation is a planned follow-up; the runtime package does not yet provide a generator or compressed-webfont decoder.

HarfBuzz interns language tags for the shared engine lifetime. To bound that memory, an engine accepts at most 256 distinct explicit language tags, compared case-insensitively. Existing tags and inferred language remain usable after that limit; disposing a font does not reset it.

Axis-aligned bounds of visible glyph outlines in logical output coordinates.

interface InkBounds

Related API: InkBounds.

TextGeometryResult

View source — packages/text/src/lib/bounds.ts:8

x
readonly x: number

Horizontal coordinate or displacement in the containing coordinate system. See InkBounds.

View source — packages/text/src/lib/bounds.ts:13

y
readonly y: number

Vertical coordinate or displacement in the containing coordinate system. See InkBounds .

View source — packages/text/src/lib/bounds.ts:18

width
readonly width: number

Horizontal extent in the units of the containing geometry or surface. See InkBounds.

View source — packages/text/src/lib/bounds.ts:22

height
readonly height: number

Vertical extent in the units of the containing geometry or surface. See InkBounds.

View source — packages/text/src/lib/bounds.ts:24

An explicitly owned native font loaded for text shaping. Dispose it when no more geometry will be created from it; disposal is idempotent.

interface OutlineFont extends Disposable

Related API: OutlineFont.

loadOutlineFont

createTextGeometry

View source — packages/text/src/index.ts:16

dispose
dispose: () => void

Releases the native font owner; repeated calls are harmless and later shaping with this font fails. See OutlineFont.

View source — packages/text/src/index.ts:21

Cancellation and monochrome-fallback policy used when loading an outline font.

interface OutlineFontOptions

Related API: OutlineFontOptions.

loadOutlineFont

View source — packages/text/src/index.ts:28

signal (optional)
signal?: AbortSignal | undefined

Related API: signal.

Abort signal for font loading and validation. See OutlineFontOptions.

View source — packages/text/src/index.ts:30

monochromeFallback (optional)
monochromeFallback?: boolean | undefined

Allows supported monochrome outlines when the font includes color glyph data. See OutlineFontOptions.

View source — packages/text/src/index.ts:35

Font size, shaping direction, OpenType features, and work limits for one text run.

interface TextGeometryOptions

Related API: TextGeometryOptions.

createTextGeometry

View source — packages/text/src/index.ts:42

fontSize
fontSize: number

Positive finite output font size in logical units. See TextGeometryOptions.

View source — packages/text/src/index.ts:44

maxSegments (optional)
maxSegments?: number | undefined

Upper bound on the number of output path segments. See TextGeometryOptions.

View source — packages/text/src/index.ts:46

missingGlyphs (optional)
missingGlyphs?: "error" | "notdef" | undefined

Whether an absent glyph fails shaping or uses the font’s .notdef glyph. See TextGeometryOptions.

View source — packages/text/src/index.ts:51

direction (optional)
direction?: "ltr" | "rtl" | undefined

Explicit left-to-right or right-to-left shaping direction; omitted direction is inferred. See TextGeometryOptions.

View source — packages/text/src/index.ts:56

script (optional)
script?: string | undefined

Four-character OpenType script tag overriding script inference. See TextGeometryOptions.

View source — packages/text/src/index.ts:61

language (optional)
language?: string | undefined

Language tag used for shaping; distinct interned tags are bounded by the engine. See TextGeometryOptions.

View source — packages/text/src/index.ts:66

features (optional)
features?: Readonly<Record<string, boolean>> | undefined

OpenType feature overrides keyed by four-character tags. See TextGeometryOptions.

View source — packages/text/src/index.ts:68

Shaped glyph identity, UTF-16 source cluster, outline segment range, and scaled placement metrics.

interface TextGlyph

Related API: TextGlyph.

TextGeometryResult

View source — packages/text/src/index.ts:75

glyphId
readonly glyphId: number

Font-specific identifier of the shaped glyph. See TextGlyph.

View source — packages/text/src/index.ts:77

cluster
readonly cluster: number

UTF-16 offset of the source cluster associated with this glyph. See TextGlyph.

View source — packages/text/src/index.ts:79

segmentStart
readonly segmentStart: number

Index of the glyph’s first segment in the returned geometry. See TextGlyph.

View source — packages/text/src/index.ts:81

segmentCount
readonly segmentCount: number

Number of outline segments belonging to this glyph. See TextGlyph.

View source — packages/text/src/index.ts:83

x
readonly x: number

Horizontal coordinate or displacement in the containing coordinate system. See TextGlyph.

View source — packages/text/src/index.ts:88

y
readonly y: number

Vertical coordinate or displacement in the containing coordinate system. See TextGlyph .

View source — packages/text/src/index.ts:93

xAdvance
readonly xAdvance: number

Horizontal pen advance in scaled logical units. See TextGlyph.

View source — packages/text/src/index.ts:95

yAdvance
readonly yAdvance: number

Vertical pen advance in Canvas-oriented logical units. See TextGlyph.

View source — packages/text/src/index.ts:97

Independent path geometry, optional ink bounds, advances, and glyph metadata for a shaped text run.

interface TextGeometryResult

Related API: TextGeometryResult.

PathGeometry

InkBounds

TextGlyph

createTextGeometry

View source — packages/text/src/index.ts:107

geometry
readonly geometry: PathGeometry

Related API: PathGeometry.

Independent mutable outline geometry in Canvas-oriented output coordinates. See PathGeometry.

View source — packages/text/src/index.ts:112

inkBounds
readonly inkBounds: Readonly<InkBounds> | null

Related API: InkBounds.

Bounds of visible outlines, or null when the run has no ink. See InkBounds.

View source — packages/text/src/index.ts:114

advance
readonly advance: Readonly<{ x: number; y: number; }>

Final pen displacement, including glyph advances even when no ink is drawn. See TextGeometryResult.

View source — packages/text/src/index.ts:119

glyphs
readonly glyphs: readonly TextGlyph[]

Related API: TextGlyph.

Ordered shaped-glyph metadata corresponding to the returned outline segments. See TextGlyph.

View source — packages/text/src/index.ts:135

Loads and validates font bytes from a URL or buffer and returns an explicitly disposable font. Rejects on cancellation, unsupported font data, or allocation failure.

loadOutlineFont: (source: string | URL | ArrayBuffer | Uint8Array, options?: OutlineFontOptions) => Promise<OutlineFont>

Related API: loadOutlineFont, OutlineFontOptions, OutlineFont.

  • source — Font URL to fetch, or in-memory font bytes to copy into the shaping engine.

  • options — Cancellation signal and explicit monochrome fallback policy. See OutlineFontOptions .

A promise for an owned font; dispose it when no further shaping will use it. See OutlineFont .

OutlineFontOptions

OutlineFont

View source — packages/text/src/index.ts:157

Synchronously shapes a single text run into independent Canvas-oriented outlines. The font must be live, fontSize positive and finite, and text must not contain line breaks or tabs.

createTextGeometry: (font: OutlineFont, text: string, options: TextGeometryOptions) => TextGeometryResult

Related API: createTextGeometry, OutlineFont, TextGeometryOptions, TextGeometryResult.

  • font — Live font returned by loadOutlineFont; it must not have been disposed. See OutlineFont .

  • text — Text to shape as one run.

  • options — Font size, shaping overrides, missing-glyph policy, and work limits. See TextGeometryOptions .

Independent mutable path geometry plus glyph placements, ink bounds, and advances; the result remains usable after font disposal. See TextGeometryResult .

OutlineFont

TextGeometryOptions

TextGeometryResult

View source — packages/text/src/index.ts:226

Read the Text outlines and typography companion for ownership, adaptation, failure modes, and verification. Agent start provides the version-selection workflow.

Documentation built with @pibbl/core 0.0.2, revision 272a94a. ALPHA — NOT FOR PRODUCTION USE.