Files
2026-05-27 23:29:53 +01:00

3.4 KiB
Raw Permalink Blame History

OpenSpec Change: enterprise-font-compress-btf

  • Change ID: enterprise-font-compress-btf
  • Package: @suaveplan/font-compress
  • Category: universal
  • Target path: universal/compression/font-compress
  • Status: PROPOSED
  • Date: 2026-04-25
  • Reference source: /mnt/s/web/suaveplan/packages/universal/font-compress/src/packer/

Summary

Deliver @suaveplan/font-compress on the genesis branch from scratch at enterprise quality. The package implements BTF (Binary TypeFace) binary packing: takes a TypefaceFont JSON (from @suaveplan/font-convert) and produces a compact Uint8Array using dictionary-based compression with @suaveplan/bitpacker. Also provides BinaryFontUnpacker which reverses the process (BTF binary → TypefaceFont JSON).


Current-state audit (genesis)

The package does not exist on genesis. The original logic was split across @suaveplan/font-compress (packing) and @suaveplan/font-decompress (unpacking) on main. In genesis we co-locate packer and unpacker here since they share the binary format and dictionary logic.


BTF binary format

[metadata: familyName string][cssFontWeight string][cssFontStyle string]
[reversed: 1 byte]
[dictLen: uint32][dictionary: Int16Array × dictLen]
[metrics: 9 × uint16 (indexes into dictionary)]
[glyphCount: uint32]
[per glyph: char codepoint uint32][ha/x_min/x_max: 3 × uint16][cmdCount: uint16]
[per cmd: type byte + coord indexes uint16 × 2|4|0]

String encoding: [length: uint16][utf8 bytes]


Available workspace deps on genesis

Package Role
@suaveplan/error (workspace:^) Base class for FontCompressError; FONT_COMPRESS.* codes
@suaveplan/types (workspace:^) LoggerLike, Clock
@suaveplan/font-convert (workspace:^) TypefaceFont, TypefaceGlyph, PathCommand types
@suaveplan/bitpacker (workspace:^) BitWriter/BitReader for bit-packed command encoding
zod (catalog:forms) Option schemas
@opentelemetry/api (catalog:observability) Spans + metrics

Public API

class FontCompressError extends SuaveplanError<FontCompressErrorCode>

type FontCompressErrorCode =
  | 'FONT_COMPRESS_PACK_FAILED'
  | 'FONT_COMPRESS_UNPACK_FAILED'
  | 'FONT_COMPRESS_INVALID_DATA'

class BinaryFontPacker {
    pack(font: TypefaceFont): Uint8Array
}

class BinaryFontUnpacker {
    unpack(data: Uint8Array): TypefaceFont
}

function createBinaryFontPacker(): BinaryFontPacker
function createBinaryFontUnpacker(): BinaryFontUnpacker

File layout

universal/compression/font-compress/
  package.json
  tsconfig.lib.json
  vitest.config.ts
  vite.config.ts
  src/
    index.ts
    error-codes.ts
    constants/
      index.ts
    packer/
      binary-font-packer/
        binary-font-packer.ts
        binary-font-packer.md
        binary-font-packer.test.ts
        index.ts
    unpacker/
      binary-font-unpacker/
        binary-font-unpacker.ts
        binary-font-unpacker.md
        binary-font-unpacker.test.ts
        index.ts
    utils/
      encode-string.ts
      encode-string.md
      encode-string.test.ts
      parse-path.ts
      parse-path.md
      parse-path.test.ts
    __benchmarks__/
      font-compress.bench.ts
  tests/
    roundtrip.test.ts
    property.test.ts

Impact

Downstream: Three.js font loading pipelines. Prerequisites: @suaveplan/font-convert, @suaveplan/bitpacker.