# Text outline
Load an outline font, shape a text run, and paint its editable path with glyph metrics.

## APIs demonstrated

- [loadOutlineFont](/reference/functions/text-geometry/) from `@pibbl/text`
- [createTextGeometry](/reference/functions/text-geometry/) from `@pibbl/text`
- [InkBounds](/reference/functions/text-geometry/) from `@pibbl/text`
- [OutlineFont](/reference/functions/text-geometry/) from `@pibbl/text`
- [OutlineFontOptions](/reference/functions/text-geometry/) from `@pibbl/text`
- [TextGeometryOptions](/reference/functions/text-geometry/) from `@pibbl/text`
- [TextGeometryResult](/reference/functions/text-geometry/) from `@pibbl/text`
- [TextGlyph](/reference/functions/text-geometry/) from `@pibbl/text`

## Complete example

[Plain source](/minimal/text/outline.tsx). Run as a browser module after the document body exists. TSX uses `jsx: "react-jsx"` and `jsxImportSource: "@pibbl/core"`.

```tsx
import { Path, pibbl, type PibblController } from '@pibbl/core';
import {
  createTextGeometry,
  loadOutlineFont,
  type InkBounds,
  type OutlineFont,
  type OutlineFontOptions,
  type TextGeometryOptions,
  type TextGeometryResult,
  type TextGlyph,
} from '@pibbl/text';

const canvas = document.createElement('canvas');
canvas.width = 440;
canvas.height = 230;
const status = document.createElement('p');
status.textContent = 'Loading outline font...';
document.body.append(canvas, status);

const abort = new AbortController();
const fontOptions: OutlineFontOptions = { signal: abort.signal };
const shapeOptions: TextGeometryOptions = {
  fontSize: 72,
  direction: 'ltr',
  features: { kern: true, liga: true },
};
let font: OutlineFont | undefined;
let controller: PibblController | undefined;
let disposed = false;

function dispose() {
  if (disposed) return;
  disposed = true;
  abort.abort();
  controller?.dispose();
  font?.dispose();
  window.removeEventListener('pagehide', dispose);
}

window.addEventListener('pagehide', dispose);

void loadOutlineFont(new URL('/pibbl-text/ABeeZee-Regular.ttf', document.baseURI), fontOptions)
  .then((loadedFont) => {
    if (disposed) {
      loadedFont.dispose();
      return;
    }
    font = loadedFont;
    const result: TextGeometryResult = createTextGeometry(font, 'Hello Pibbl', shapeOptions);
    const firstGlyph: TextGlyph | undefined = result.glyphs[0];
    const ink: Readonly<InkBounds> | null = result.inkBounds;
    result.geometry.transform({ a: 1, d: 1, e: 24, f: 145 });
    controller = pibbl(
      canvas,
      <Path style={{ d: result.geometry, fill: '#0f766e' }} />,
    );
    status.textContent = `${result.glyphs.length} glyphs; first cluster ${firstGlyph?.cluster ?? 'none'}; advance ${result.advance.x.toFixed(1)}; ink ${ink ? `${ink.width.toFixed(1)} x ${ink.height.toFixed(1)}` : 'empty'}`;
  })
  .catch((error: unknown) => {
    if (!disposed) status.textContent = `Could not load font: ${String(error)}`;
  });

```

## Usage notes

- The browser example requires the existing Studio /pibbl-text/ABeeZee-Regular.ttf asset and the @pibbl/text WASM loader asset; retain and dispose the font explicitly.

## Documentation version

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