Files
skills/docs/media/fonts/font-decompress/README.md
2026-05-29 08:20:56 +01:00

5.8 KiB

@suaveplan/font-decompress - BTF (Binary TypeFace) binary unpacking. Reverses @suaveplan/font-compress's BinaryFontPacker output back into typeface.js JSON, ready for Three.js / R3F / game-font rendering pipelines. Universal.

BTF (Binary TypeFace) binary unpacking. Reverses @suaveplan/font-compress's BinaryFontPacker output into a typeface.js JSON shape ready for Three.js / R3F / game-font rendering. Store-agnostic, free of node: / bun: imports.

Documentation tree

  • error-codes — The @suaveplan/font-decompress package centralises every failure mode it can produce behind a single registry built w…
    • error-codes — The @suaveplan/font-decompress package centralises every failure mode it can produce behind a single registry built w…
  • binary-font-unpacker — BinaryFontUnpacker reverses the BTF (Binary TypeFace) wire format produced by BinaryFontPacker from `@suaveplan/fon…
    • binary-font-unpacker — BinaryFontUnpacker reverses the BTF (Binary TypeFace) wire format produced by BinaryFontPacker from `@suaveplan/fon…
  • utils — decodeString reads a length-prefixed UTF-8 string from a Uint8Array at a given offset. The BTF wire format encodes…
    • decode-string — decodeString reads a length-prefixed UTF-8 string from a Uint8Array at a given offset. The BTF wire format encodes…

Purpose

Compressed BTF buffers ship from build-time tooling to the renderer as compact Uint8Array blobs — they are far smaller than the underlying typeface.js JSON for non-trivial fonts. The renderer needs the JSON back to hand to Three.js's FontLoader.parse(...). This package owns that reverse step; the sibling @suaveplan/font-compress owns the forward step.

The split exists because pack and unpack are independent concerns: build tooling never unpacks, runtime renderers never pack. Shipping a unified package forces consumers to drag the other half. Splitting lets each side install only what it actually executes.

Features

  • BinaryFontUnpacker class + createBinaryFontUnpacker() factory
  • Strict boundary validation on every read — raises FontDecompressError with FONT_DECOMPRESS.INVALID_DATA
  • Underlying primitive exceptions (DataView, TextDecoder) wrapped as FontDecompressError with FONT_DECOMPRESS.UNPACK_FAILED and cause preserved
  • All five BTF glyph commands (m/l/b/q/z) round-trip byte-for-byte
  • Unicode glyph keys (multi-byte UTF-8) round-trip correctly
  • Negative coordinates round-trip correctly
  • 100% statement / branch / function / line Istanbul coverage
  • 5 tree-shakeable subpath exports

Usage: Basic

import { createBinaryFontUnpacker } from "@suaveplan/font-decompress";

const unpacker = createBinaryFontUnpacker();
const font = unpacker.unpack(btfBuffer);

console.log(font.familyName); // "Inter Variable"
console.log(font.glyphs["A"]?.ha); // glyph advance width

Usage: Advanced

import {
    BinaryFontUnpacker,
    FONT_DECOMPRESS_CODES,
    FontDecompressError,
} from "@suaveplan/font-decompress";

// Reuse a single instance — stateless and safe.
const unpacker = new BinaryFontUnpacker();

async function loadCdnFont(url: string) {
    const buf = new Uint8Array(
        await (await fetch(url)).arrayBuffer(),
    );
    try {
        return unpacker.unpack(buf);
    } catch (err) {
        if (
            err instanceof FontDecompressError &&
            err.code === FONT_DECOMPRESS_CODES.INVALID_DATA
        ) {
            console.warn("Corrupted BTF from CDN:", err.message);
            return null;
        }
        throw err;
    }
}

API Reference

Public exports

  • class BinaryFontUnpacker — unpack(data: Uint8Array): TypefaceFont
  • createBinaryFontUnpacker(): BinaryFontUnpacker
  • FONT_DECOMPRESS_CODES — frozen registry with UNPACK_FAILED, INVALID_DATA
  • class FontDecompressError extends SuaveplanError<FontDecompressErrorCode>
  • type FontDecompressErrorCode

The TypefaceFont and PathCommand types come from @suaveplan/font-convert; consumers import them directly from there rather than via this package's surface.

Subpath exports

Subpath What
. Root barrel (above)
./error-codes FONT_DECOMPRESS_CODES, FontDecompressError
./constants BTF wire-format constants
./utils/decode-string decodeString helper
./unpacker/binary-font-unpacker BinaryFontUnpacker, factory

Implementation Notes

The package is universal: zero node: / bun: imports anywhere in src/. The only platform-aware calls are DataView, TextDecoder, and String.fromCharCode — all available in every supported runtime (Node ≥ 18, Bun, modern browsers, Web Workers).

The BTF wire-format constants (CMD_M … CMD_Z, BYTE_TO_CMD, CMD_COORD_COUNTS, METRICS_COUNT) are duplicated from @suaveplan/font-compress. Duplicating 19 lines of magic numbers avoids a third "fonts-shared" package and keeps each package self-contained. If the BTF format ever changes — which is a coordinated breaking event — both packages get updated in the same commit.

@suaveplan/font-compress is a devDependency for round-trip tests only. The runtime dependency graph is font-decompress → font-convert + error; the test surface adds font-compress solely to generate known-vector fixtures.