npm package: @fekit/harfbuzz
Description: ESM wrapper for HarfBuzz font shaping engine with bidirectional text support
Latest version: 1.0.0

# @fekit/harfbuzz

ESM wrapper for HarfBuzz font shaping engine with bidirectional text support for browsers.

## Features

- ✅ **Pure ESM** - Modern ES Module support
- ✅ **Browser-only** - Optimized for browser environments
- ✅ **Bidirectional Text** - Built-in bidi support using [bidi-js](https://github.com/lojjic/bidi-js)
- ✅ **WebAssembly** - Fast font shaping using HarfBuzz WASM
- ✅ **TypeScript** - Full TypeScript type definitions
- ✅ **Zero Configuration** - Works out of the box in Vite/Webpack
- ✅ **Zero Runtime Requests** - WASM inlined at build time

## Installation

```bash
npm install @fekit/harfbuzz
```

## Usage

### Basic Example

```javascript
import harfbuzz from '@fekit/harfbuzz';

// Initialize HarfBuzz (zero configuration!)
await harfbuzz.init();

// Load a font file
const fontData = await fetch('/path/to/font.ttf').then(r => r.arrayBuffer());

// Create a font instance
const font = harfbuzz.createFont('my-font', fontData);

// Shape text (automatic bidirectional support)
const result = font.shape('Hello مرحبا');

console.log(result.glyphs);  // Array of glyph information
console.log(result.bounds);  // Text bounds
```

### How It Works

The library automatically handles WASM loading with **zero configuration**:

- In **Vite/Webpack**: WASM is automatically inlined at build time using `import('./hb.wasm?init')`
- **Zero runtime requests** - No need to fetch `.wasm` files
- **Fallback support** - Works in all environments with automatic detection

### Bidirectional Text

The library automatically handles bidirectional text (Arabic, Hebrew, mixed):

```javascript
// Arabic text
const arabicResult = font.shape('مرحبا بك');

// Hebrew text
const hebrewResult = font.shape('שלום עולם');

// Mixed LTR/RTL
const mixedResult = font.shape('Hello مرحبا World');
```

### Advanced Usage

```javascript
// Get glyph information
const glyphName = font.glyphName(42);
const glyphPath = font.glyphPath(42);  // SVG path string
const glyphGeometry = font.glyphGeometry(42);  // Path segments

// Variable fonts
const axisInfos = font.getAxisInfos();
font.setVariations({ 'wght': 700, 'wdth': 100 });

// Set font scale
font.setScale(1000, 1000);

// Get supported Unicode codepoints
const unicodes = font.collectUnicodes();

// Access OpenType tables
const gsubTable = font.referenceTable('GSUB');

// Clean up when done
font.destroy();
harfbuzz.freeFont('my-font');
```

### Managing Multiple Fonts

```javascript
await harfbuzz.init();

// Create multiple fonts
const font1 = harfbuzz.createFont('font1', data1);
const font2 = harfbuzz.createFont('font2', data2);

// Get font by ID
const myFont = harfbuzz.getFont('font1');

// List all loaded fonts
console.log(harfbuzz.fontIds);  // ['font1', 'font2']

// Free individual font
harfbuzz.freeFont('font1');
```

### Using Bidi Separately

If you need direct access to the bidirectional text algorithm:

```javascript
import bidiFactory from 'bidi-js';

const bidi = bidiFactory();
const result = bidi.getEmbeddingLevels('مرحبا Hello');
console.log(result.levels);
```

## API Reference

### HarfBuzzSingleton (default export)

#### `init(options?): Promise<void>`
Initialize HarfBuzz. Must be called before using any other methods.

**Options** (all optional):
- `wasmURL` (string): Custom WASM file URL
- `locateFile` (function): Custom file locator function
- `wasmBinary` (Uint8Array): Pre-loaded WASM binary

**Examples:**

```javascript
// Zero configuration (recommended)
await harfbuzz.init();

// (Optional) With custom WASM URL if needed
import wasmURL from '@fekit/harfbuzz/src/hb.wasm?url';
await harfbuzz.init({ wasmURL });
```

#### `createFont(id, data, index?): Font`
Create a new font instance.
- `id`: Unique identifier for the font
- `data`: Font binary data (ArrayBuffer or Uint8Array)
- `index`: Font index for TTC/OTC files (default: 0)

#### `getFont(id): Font | undefined`
Get an existing font by ID.

#### `freeFont(id): void`
Free font resources by ID.

#### `fontIds: string[]`
Array of all loaded font IDs.

#### `version(): VersionInfo`
Get HarfBuzz version information.

#### `versionString(): string`
Get HarfBuzz version as string.

### Font

#### `shape(text): ShapeResult`
Shape text with automatic bidirectional support.

Returns:
```typescript
{
  glyphs: Array<{ id: number, base: { x: number, y: number } }>,
  bounds: { width: number, height: number }
}
```

#### `glyphName(id): string`
Get glyph name by glyph ID.

#### `glyphPath(id): string`
Get glyph outline as SVG path string.

#### `glyphGeometry(id): PathSegment[]`
Get glyph outline as path segments.

#### `setScale(xScale, yScale): void`
Set font scale factors.

#### `setVariations(variations): void`
Set variable font variations.

```javascript
font.setVariations({ 'wght': 700, 'wdth': 100 });
```

#### `getAxisInfos(): Record<string, AxisInfo>`
Get variation axis information.

#### `collectUnicodes(): Uint32Array`
Get all supported Unicode codepoints.

#### `referenceTable(table): Uint8Array | undefined`
Get OpenType table data.

#### `destroy(): void`
Free font resources.

#### `upem: number`
Units per em (read-only).

## Browser Compatibility

This library requires:
- ES Modules support
- WebAssembly support
- Modern browsers (Chrome 61+, Firefox 60+, Safari 11+, Edge 79+)

## License

MIT

## Credits

- [HarfBuzz](https://harfbuzz.github.io/) - Text shaping engine
- [harfbuzzjs](https://github.com/harfbuzz/harfbuzzjs) - Original WASM wrapper
- [bidi-js](https://github.com/lojjic/bidi-js) - Unicode bidirectional algorithm
- [harfbuzz-modern-wrapper](https://github.com/beanandbean/font-mesh-pipeline) - Simplified wrapper