# BinaryFontPacker _(no submodules)_ ## Purpose `BinaryFontPacker` converts a `TypefaceFont` (the typeface.js JSON structure) into a compact binary BTF (Binary TypeFace) buffer. It builds a shared integer dictionary from all unique coordinate values in the font and encodes every number as a 16-bit dictionary index rather than a string, dramatically reducing the payload compared to raw JSON. The BTF format is designed for Three.js and game-engine font pipelines where fonts must be shipped as efficient binary assets rather than verbose JSON strings. ## Features - Dictionary-based compression: all unique integer values stored once in an `Int16Array`; all subsequent references are 16-bit indexes - Full font round-trip: header strings, reversed flag, 9 scalar metrics, bounding box, per-glyph ha/x_min/x_max, and full outline data - Supports all typeface.js command types: `m`, `l`, `b` (cubic), `q` (quadratic), `z` - Little-endian byte layout throughout for cross-platform compatibility - Wraps internal errors in `FontCompressError` with stable code `PACK_FAILED` ## Usage: Basic Example ```typescript import { createBinaryFontPacker } from "@suaveplan/font-compress/packer/binary-font-packer"; import type { TypefaceFont } from "@suaveplan/font-convert"; const font: TypefaceFont = { /* ... */ }; const packer = createBinaryFontPacker(); const buffer: Uint8Array = packer.pack(font); ``` ## Usage: Advanced Example ```typescript import { BinaryFontPacker } from "@suaveplan/font-compress/packer/binary-font-packer"; import { FontCompressError } from "@suaveplan/font-compress"; const packer = new BinaryFontPacker(); try { const packed = packer.pack(font); // Write to disk, send over the wire, or store in IndexedDB await Bun.write("font.btf", packed); } catch (err) { if (err instanceof FontCompressError) { console.error("Pack failed:", err.code, err.message); } } ``` ## API Reference ### `BinaryFontPacker` #### `pack(font: TypefaceFont): Uint8Array` Packs a `TypefaceFont` into a BTF binary buffer. **Parameters:** - `font` — the typeface.js font object, as produced by `@suaveplan/font-convert` **Returns:** `Uint8Array` containing the binary BTF data. **Throws:** `FontCompressError` with code `PACK_FAILED` if packing fails for any reason. ### `createBinaryFontPacker(): BinaryFontPacker` Factory function that creates a new `BinaryFontPacker` instance. ## Implementation Notes ### BTF Binary Layout ```text [familyName: encodeString] [cssFontWeight: encodeString] [cssFontStyle: encodeString] [reversed: uint8 (0 or 1)] [dictLen: uint32 LE] [dict: Int16Array × dictLen] [metricsIdxs: Uint16Array × 9] ← ascender,descender,ulPos,ulThk,res,yMin,xMin,yMax,xMax [glyphCount: uint32 LE] per-glyph: [charCode: uint32 LE] [indexCount: uint32 LE] [indexes: Uint16Array × indexCount] ← ha,x_min,x_max, then (cmd_byte+coord_indexes)... ``` `encodeString` format: `[uint32 length LE][UTF-8 bytes]`. Command bytes map to: `0=m`, `1=l`, `2=b`, `3=q`, `4=z`. Coordinate counts per command: `m=2`, `l=2`, `b=6`, `q=4`, `z=0`. ### Dictionary Construction All unique coordinate values across the entire font (metrics, bounding box, all glyph coordinates) are collected into a sorted `Int16Array`. This single pass over the font data is O(n) in glyph count and produces optimal deduplication. Because typeface.js coordinates are integers in a bounded range (typically ±2048), the dictionary fits comfortably in an Int16Array. ### Alignment All multi-byte typed arrays are written via `Uint8Array` byte copies, not direct TypedArray buffer views, so there are no alignment requirements on the output buffer. Readers (BinaryFontUnpacker) use `DataView` to safely read values at arbitrary offsets.