three-text 0.4.4 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,7 @@ High fidelity 3D mesh font geometry and text layout engine for the web
15
15
  > [!CAUTION]
16
16
  > three-text is an alpha release and the API may break rapidly. This warning will likely last until the end of March 2026. If API stability is important to you, consider pinning your version. Community feedback is encouraged; please open an issue if you have any suggestions or feedback, thank you
17
17
 
18
- **three-text** is a 3D mesh font geometry and text layout library for the web. It supports TTF, OTF, and WOFF font files. For layout, it uses [TeX](https://en.wikipedia.org/wiki/TeX)-based parameters for breaking text into paragraphs across multiple lines and supports CJK and RTL scripts. three-text caches the geometries it generates for low CPU overhead in languages with lots of repeating glyphs. Variable fonts are supported as static instances at a given axis coordinate, and can be animated by re-drawing each frame with new coordinates
18
+ **three-text** is a 3D mesh font geometry and text layout library for the web. It supports TTF, OTF, WOFF, and WOFF2 font files. For layout, it uses [TeX](https://en.wikipedia.org/wiki/TeX)-based parameters for breaking text into paragraphs across multiple lines and supports CJK and RTL scripts. three-text caches the geometries it generates for low CPU overhead in languages with lots of repeating glyphs. Variable fonts are supported as static instances at a given axis coordinate, and can be animated by re-drawing each frame with new coordinates
19
19
 
20
20
  The library has a framework-agnostic core that returns raw vertex data, with lightweight adapters for [Three.js](https://threejs.org), [React Three Fiber](https://docs.pmnd.rs/react-three-fiber), [p5.js](https://p5js.org), [WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API), and [WebGPU](https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API)
21
21
 
@@ -78,13 +78,14 @@ Choose the import that matches your stack. Most users will use `three-text/three
78
78
 
79
79
  ```javascript
80
80
  import { Text } from 'three-text/three';
81
+ import { decode } from 'woff2-decode'; // Optional
81
82
  import * as THREE from 'three';
82
83
 
83
84
  Text.setHarfBuzzPath('/hb/hb.wasm');
84
-
85
+ Text.enableWoff2(decode); // Enabling WOFF2 support adds ~45kb to the bundle
85
86
  const result = await Text.create({
86
87
  text: 'Hello World',
87
- font: '/fonts/Font.woff',
88
+ font: '/fonts/Font.woff2',
88
89
  size: 72
89
90
  });
90
91
 
@@ -116,13 +117,15 @@ function App() {
116
117
 
117
118
  ```javascript
118
119
  import 'three-text/p5';
120
+ import { decode } from 'woff2-decode';
119
121
 
120
122
  let font;
121
123
  let textResult;
122
124
 
123
125
  function preload() {
124
126
  loadThreeTextShaper('/hb/hb.wasm');
125
- font = loadThreeTextFont('/fonts/Font.woff');
127
+ enableThreeTextWoff2(decode); // Optional, adds ~45KB to bundle
128
+ font = loadThreeTextFont('/fonts/Font.woff2');
126
129
  }
127
130
 
128
131
  async function setup() {
@@ -195,6 +198,12 @@ self.onmessage = (e) => {
195
198
 
196
199
  The library will prioritize the buffer if both a path and a buffer have been set
197
200
 
201
+ #### Platform-specific notes
202
+
203
+ **NW.js with CommonJS:** If using `require()` to load the CJS build in NW.js, use Option 2 (buffer-based loading). NW.js's [dual-context architecture](https://docs.nwjs.io/For%20Users/Advanced/JavaScript%20Contexts%20in%20NW.js/#separate-context-mode) causes path resolution issues in this specific scenario. ESM imports and bundled code work normally
204
+
205
+ **Electron with `file://` protocol:** If loading HTML directly from the filesystem (not via a dev server), use Option 2 (buffer-based loading) or enable `nodeIntegration` in your BrowserWindow
206
+
198
207
  ### Hyphenation patterns
199
208
 
200
209
  **For ES Modules (recommended):** Import and register only the languages you need:
@@ -724,7 +733,7 @@ Below are the most important configuration interfaces. For a complete list of al
724
733
  ```typescript
725
734
  interface TextOptions {
726
735
  text: string; // Text content to render
727
- font: string | ArrayBuffer; // Font file path or buffer (TTF, OTF, or WOFF)
736
+ font: string | ArrayBuffer; // Font file path or buffer (TTF, OTF, WOFF, or WOFF2)
728
737
  size?: number; // Font size in scene units (default: 72)
729
738
  depth?: number; // Extrusion depth (default: 0)
730
739
  lineHeight?: number; // Line height multiplier (default: 1.0)
@@ -907,7 +916,9 @@ The library requires WebAssembly support for HarfBuzz text shaping:
907
916
  - Safari 16.4+
908
917
  - Edge 80+
909
918
 
910
- WOFF fonts are automatically decompressed to TTF/OTF using the browser's native decompression with zero bundle cost. For older browsers, use TTF or OTF fonts directly
919
+ WOFF fonts are automatically decompressed to TTF/OTF using the browser's native `DecompressionStream` API with zero bundle cost. For older browsers without `DecompressionStream`, use TTF or OTF fonts directly
920
+
921
+ **WOFF2 font support** is opt-in (see [Basic Usage](#basic-usage))
911
922
 
912
923
  **ES modules** (recommended) are supported in:
913
924
 
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * three-text v0.4.4
2
+ * three-text v0.4.6
3
3
  * Copyright (C) 2025 Countertype LLC
4
4
  *
5
5
  * This program is free software: you can redistribute it and/or modify
@@ -1469,7 +1469,7 @@ class FontMetadataExtractor {
1469
1469
  FONT_SIGNATURE_OPEN_TYPE_CFF
1470
1470
  ];
1471
1471
  if (!validSignatures.includes(sfntVersion)) {
1472
- throw new Error(`Invalid font format. Expected TTF/OTF (or WOFF), got signature: 0x${sfntVersion.toString(16)}`);
1472
+ throw new Error(`Invalid font format. Expected TTF/OTF/WOFF/WOFF2, got signature: 0x${sfntVersion.toString(16)}`);
1473
1473
  }
1474
1474
  const tableDirectory = parseTableDirectory(view);
1475
1475
  const isCFF = tableDirectory.has(TABLE_TAG_CFF) || tableDirectory.has(TABLE_TAG_CFF2);
@@ -1658,7 +1658,7 @@ class FontMetadataExtractor {
1658
1658
  FONT_SIGNATURE_OPEN_TYPE_CFF
1659
1659
  ];
1660
1660
  if (!validSignatures.includes(sfntVersion)) {
1661
- throw new Error(`Invalid font format. Expected TTF/OTF (or WOFF), got signature: 0x${sfntVersion.toString(16)}`);
1661
+ throw new Error(`Invalid font format. Expected TTF/OTF/WOFF/WOFF2, got signature: 0x${sfntVersion.toString(16)}`);
1662
1662
  }
1663
1663
  const tableDirectory = parseTableDirectory(view);
1664
1664
  const nameTableOffset = tableDirectory.get(TABLE_TAG_NAME)?.offset ?? 0;
@@ -1892,6 +1892,10 @@ class FontMetadataExtractor {
1892
1892
  }
1893
1893
  }
1894
1894
 
1895
+ let woff2Decoder = null;
1896
+ function setWoff2Decoder(decoder) {
1897
+ woff2Decoder = decoder;
1898
+ }
1895
1899
  // Uses DecompressionStream to decompress WOFF (WOFF is just zlib compressed TTF/OTF so we can use deflate)
1896
1900
  class WoffConverter {
1897
1901
  static detectFormat(buffer) {
@@ -1993,6 +1997,21 @@ class WoffConverter {
1993
1997
  logger.log('WOFF font decompressed successfully');
1994
1998
  return sfntData.buffer.slice(0, sfntOffset);
1995
1999
  }
2000
+ static decompressWoff2(woff2Buffer) {
2001
+ const view = new DataView(woff2Buffer);
2002
+ const signature = view.getUint32(0);
2003
+ if (signature !== FONT_SIGNATURE_WOFF2) {
2004
+ throw new Error('Not a valid WOFF2 font');
2005
+ }
2006
+ if (!woff2Decoder) {
2007
+ throw new Error('WOFF2 fonts require enabling the decoder. Add to your code:\n' +
2008
+ " import { decode } from 'woff2-decode';\n" +
2009
+ ' Text.enableWoff2(decode);');
2010
+ }
2011
+ const decoded = woff2Decoder(woff2Buffer);
2012
+ logger.log('WOFF2 font decompressed successfully');
2013
+ return decoded.buffer;
2014
+ }
1996
2015
  static async decompressZlib(compressedData) {
1997
2016
  const stream = new ReadableStream({
1998
2017
  start(controller) {
@@ -2023,7 +2042,8 @@ class FontLoader {
2023
2042
  fontBuffer = await WoffConverter.decompressWoff(fontBuffer);
2024
2043
  }
2025
2044
  else if (format === 'woff2') {
2026
- throw new Error('WOFF2 fonts are not yet supported. Please use WOFF or TTF/OTF format.');
2045
+ logger.log('WOFF2 font detected, decompressing...');
2046
+ fontBuffer = WoffConverter.decompressWoff2(fontBuffer);
2027
2047
  }
2028
2048
  const view = new DataView(fontBuffer);
2029
2049
  const sfntVersion = view.getUint32(0);
@@ -2032,7 +2052,7 @@ class FontLoader {
2032
2052
  FONT_SIGNATURE_OPEN_TYPE_CFF
2033
2053
  ];
2034
2054
  if (!validSignatures.includes(sfntVersion)) {
2035
- throw new Error(`Invalid font format. Expected TTF/OTF (or WOFF), got signature: 0x${sfntVersion.toString(16)}`);
2055
+ throw new Error(`Invalid font format. Expected TTF/OTF/WOFF/WOFF2, got signature: 0x${sfntVersion.toString(16)}`);
2036
2056
  }
2037
2057
  const { hb, module } = await this.getHarfBuzzInstance();
2038
2058
  try {
@@ -2212,7 +2232,6 @@ async function loadPattern(language, patternsPath) {
2212
2232
  }
2213
2233
  }
2214
2234
 
2215
- // Bector and bounding box types for core
2216
2235
  // 2D Vector
2217
2236
  class Vec2 {
2218
2237
  constructor(x = 0, y = 0) {
@@ -4811,6 +4830,41 @@ class TextShaper {
4811
4830
  }
4812
4831
  }
4813
4832
 
4833
+ // Fetch with fs fallback for Electron file:// and Node.js environments
4834
+ async function loadBinary(filePath) {
4835
+ try {
4836
+ const res = await fetch(filePath);
4837
+ if (!res.ok) {
4838
+ throw new Error(`HTTP ${res.status}`);
4839
+ }
4840
+ return await res.arrayBuffer();
4841
+ }
4842
+ catch (fetchError) {
4843
+ const req = globalThis.require;
4844
+ if (typeof req !== 'function') {
4845
+ throw new Error(`Failed to fetch ${filePath}: ${fetchError}`);
4846
+ }
4847
+ try {
4848
+ const fs = req('fs');
4849
+ const nodePath = req('path');
4850
+ // file:// URLs need path resolution relative to the HTML document
4851
+ let resolvedPath = filePath;
4852
+ if (typeof window !== 'undefined' &&
4853
+ window.location?.protocol === 'file:') {
4854
+ const dir = nodePath.dirname(window.location.pathname);
4855
+ resolvedPath = nodePath.join(dir, filePath);
4856
+ }
4857
+ const buffer = fs.readFileSync(resolvedPath);
4858
+ if (buffer instanceof ArrayBuffer)
4859
+ return buffer;
4860
+ return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
4861
+ }
4862
+ catch (fsError) {
4863
+ throw new Error(`Failed to load ${filePath}: fetch failed (${fetchError}), fs.readFileSync failed (${fsError})`);
4864
+ }
4865
+ }
4866
+ }
4867
+
4814
4868
  var hb = {exports: {}};
4815
4869
 
4816
4870
  var fs = {};
@@ -5401,11 +5455,9 @@ try {
5401
5455
  var hbjsExports = hbjs$2.exports;
5402
5456
  var hbjs$1 = /*@__PURE__*/getDefaultExportFromCjs(hbjsExports);
5403
5457
 
5404
- // These will be bundled by Rollup
5405
- // @ts-expect-error - no declarations for harfbuzzjs/hb.js
5406
5458
  let harfbuzzPromise = null;
5407
5459
  let wasmPath = null;
5408
- let wasmBuffer = null; // Add buffer option
5460
+ let wasmBuffer = null;
5409
5461
  const HarfBuzzLoader = {
5410
5462
  setWasmPath(path) {
5411
5463
  wasmPath = path;
@@ -5428,12 +5480,7 @@ const HarfBuzzLoader = {
5428
5480
  moduleConfig.wasmBinary = wasmBuffer;
5429
5481
  }
5430
5482
  else if (wasmPath) {
5431
- moduleConfig.locateFile = (path, scriptDirectory) => {
5432
- if (path.endsWith('.wasm')) {
5433
- return wasmPath;
5434
- }
5435
- return scriptDirectory + path;
5436
- };
5483
+ moduleConfig.wasmBinary = await loadBinary(wasmPath);
5437
5484
  }
5438
5485
  else {
5439
5486
  throw new Error('HarfBuzz WASM path or buffer must be set before initialization.');
@@ -5555,6 +5602,11 @@ class Text {
5555
5602
  static { this.fontCacheMemoryBytes = 0; }
5556
5603
  static { this.maxFontCacheMemoryBytes = Infinity; }
5557
5604
  static { this.fontIdCounter = 0; }
5605
+ // Enable WOFF2 font support (adds ~45KB to bundle if imported)
5606
+ // Usage: import { decode } from 'woff2-decode'; Text.enableWoff2(decode);
5607
+ static enableWoff2(decoder) {
5608
+ setWoff2Decoder(decoder);
5609
+ }
5558
5610
  // Stringify with sorted keys for cache stability
5559
5611
  static stableStringify(obj) {
5560
5612
  const keys = Object.keys(obj).sort();
@@ -5730,14 +5782,7 @@ class Text {
5730
5782
  Text.hbInitPromise = HarfBuzzLoader.getHarfBuzz();
5731
5783
  }
5732
5784
  await Text.hbInitPromise;
5733
- const fontBuffer = typeof fontSrc === 'string'
5734
- ? await fetch(fontSrc).then((res) => {
5735
- if (!res.ok) {
5736
- throw new Error(`Failed to load font from ${fontSrc}: HTTP ${res.status} ${res.statusText}`);
5737
- }
5738
- return res.arrayBuffer();
5739
- })
5740
- : fontSrc;
5785
+ const fontBuffer = typeof fontSrc === 'string' ? await loadBinary(fontSrc) : fontSrc;
5741
5786
  try {
5742
5787
  if (this.loadedFont) {
5743
5788
  this.destroy();
package/dist/index.d.ts CHANGED
@@ -352,6 +352,7 @@ declare class Text {
352
352
  private static fontCacheMemoryBytes;
353
353
  private static maxFontCacheMemoryBytes;
354
354
  private static fontIdCounter;
355
+ static enableWoff2(decoder: (data: ArrayBuffer | Uint8Array) => Uint8Array): void;
355
356
  private static stableStringify;
356
357
  private fontLoader;
357
358
  private loadedFont?;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * three-text v0.4.4
2
+ * three-text v0.4.6
3
3
  * Copyright (C) 2025 Countertype LLC
4
4
  *
5
5
  * This program is free software: you can redistribute it and/or modify
@@ -1466,7 +1466,7 @@ class FontMetadataExtractor {
1466
1466
  FONT_SIGNATURE_OPEN_TYPE_CFF
1467
1467
  ];
1468
1468
  if (!validSignatures.includes(sfntVersion)) {
1469
- throw new Error(`Invalid font format. Expected TTF/OTF (or WOFF), got signature: 0x${sfntVersion.toString(16)}`);
1469
+ throw new Error(`Invalid font format. Expected TTF/OTF/WOFF/WOFF2, got signature: 0x${sfntVersion.toString(16)}`);
1470
1470
  }
1471
1471
  const tableDirectory = parseTableDirectory(view);
1472
1472
  const isCFF = tableDirectory.has(TABLE_TAG_CFF) || tableDirectory.has(TABLE_TAG_CFF2);
@@ -1655,7 +1655,7 @@ class FontMetadataExtractor {
1655
1655
  FONT_SIGNATURE_OPEN_TYPE_CFF
1656
1656
  ];
1657
1657
  if (!validSignatures.includes(sfntVersion)) {
1658
- throw new Error(`Invalid font format. Expected TTF/OTF (or WOFF), got signature: 0x${sfntVersion.toString(16)}`);
1658
+ throw new Error(`Invalid font format. Expected TTF/OTF/WOFF/WOFF2, got signature: 0x${sfntVersion.toString(16)}`);
1659
1659
  }
1660
1660
  const tableDirectory = parseTableDirectory(view);
1661
1661
  const nameTableOffset = tableDirectory.get(TABLE_TAG_NAME)?.offset ?? 0;
@@ -1889,6 +1889,10 @@ class FontMetadataExtractor {
1889
1889
  }
1890
1890
  }
1891
1891
 
1892
+ let woff2Decoder = null;
1893
+ function setWoff2Decoder(decoder) {
1894
+ woff2Decoder = decoder;
1895
+ }
1892
1896
  // Uses DecompressionStream to decompress WOFF (WOFF is just zlib compressed TTF/OTF so we can use deflate)
1893
1897
  class WoffConverter {
1894
1898
  static detectFormat(buffer) {
@@ -1990,6 +1994,21 @@ class WoffConverter {
1990
1994
  logger.log('WOFF font decompressed successfully');
1991
1995
  return sfntData.buffer.slice(0, sfntOffset);
1992
1996
  }
1997
+ static decompressWoff2(woff2Buffer) {
1998
+ const view = new DataView(woff2Buffer);
1999
+ const signature = view.getUint32(0);
2000
+ if (signature !== FONT_SIGNATURE_WOFF2) {
2001
+ throw new Error('Not a valid WOFF2 font');
2002
+ }
2003
+ if (!woff2Decoder) {
2004
+ throw new Error('WOFF2 fonts require enabling the decoder. Add to your code:\n' +
2005
+ " import { decode } from 'woff2-decode';\n" +
2006
+ ' Text.enableWoff2(decode);');
2007
+ }
2008
+ const decoded = woff2Decoder(woff2Buffer);
2009
+ logger.log('WOFF2 font decompressed successfully');
2010
+ return decoded.buffer;
2011
+ }
1993
2012
  static async decompressZlib(compressedData) {
1994
2013
  const stream = new ReadableStream({
1995
2014
  start(controller) {
@@ -2020,7 +2039,8 @@ class FontLoader {
2020
2039
  fontBuffer = await WoffConverter.decompressWoff(fontBuffer);
2021
2040
  }
2022
2041
  else if (format === 'woff2') {
2023
- throw new Error('WOFF2 fonts are not yet supported. Please use WOFF or TTF/OTF format.');
2042
+ logger.log('WOFF2 font detected, decompressing...');
2043
+ fontBuffer = WoffConverter.decompressWoff2(fontBuffer);
2024
2044
  }
2025
2045
  const view = new DataView(fontBuffer);
2026
2046
  const sfntVersion = view.getUint32(0);
@@ -2029,7 +2049,7 @@ class FontLoader {
2029
2049
  FONT_SIGNATURE_OPEN_TYPE_CFF
2030
2050
  ];
2031
2051
  if (!validSignatures.includes(sfntVersion)) {
2032
- throw new Error(`Invalid font format. Expected TTF/OTF (or WOFF), got signature: 0x${sfntVersion.toString(16)}`);
2052
+ throw new Error(`Invalid font format. Expected TTF/OTF/WOFF/WOFF2, got signature: 0x${sfntVersion.toString(16)}`);
2033
2053
  }
2034
2054
  const { hb, module } = await this.getHarfBuzzInstance();
2035
2055
  try {
@@ -2209,7 +2229,6 @@ async function loadPattern(language, patternsPath) {
2209
2229
  }
2210
2230
  }
2211
2231
 
2212
- // Bector and bounding box types for core
2213
2232
  // 2D Vector
2214
2233
  class Vec2 {
2215
2234
  constructor(x = 0, y = 0) {
@@ -4808,6 +4827,41 @@ class TextShaper {
4808
4827
  }
4809
4828
  }
4810
4829
 
4830
+ // Fetch with fs fallback for Electron file:// and Node.js environments
4831
+ async function loadBinary(filePath) {
4832
+ try {
4833
+ const res = await fetch(filePath);
4834
+ if (!res.ok) {
4835
+ throw new Error(`HTTP ${res.status}`);
4836
+ }
4837
+ return await res.arrayBuffer();
4838
+ }
4839
+ catch (fetchError) {
4840
+ const req = globalThis.require;
4841
+ if (typeof req !== 'function') {
4842
+ throw new Error(`Failed to fetch ${filePath}: ${fetchError}`);
4843
+ }
4844
+ try {
4845
+ const fs = req('fs');
4846
+ const nodePath = req('path');
4847
+ // file:// URLs need path resolution relative to the HTML document
4848
+ let resolvedPath = filePath;
4849
+ if (typeof window !== 'undefined' &&
4850
+ window.location?.protocol === 'file:') {
4851
+ const dir = nodePath.dirname(window.location.pathname);
4852
+ resolvedPath = nodePath.join(dir, filePath);
4853
+ }
4854
+ const buffer = fs.readFileSync(resolvedPath);
4855
+ if (buffer instanceof ArrayBuffer)
4856
+ return buffer;
4857
+ return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
4858
+ }
4859
+ catch (fsError) {
4860
+ throw new Error(`Failed to load ${filePath}: fetch failed (${fetchError}), fs.readFileSync failed (${fsError})`);
4861
+ }
4862
+ }
4863
+ }
4864
+
4811
4865
  var hb = {exports: {}};
4812
4866
 
4813
4867
  var fs = {};
@@ -5398,11 +5452,9 @@ try {
5398
5452
  var hbjsExports = hbjs$2.exports;
5399
5453
  var hbjs$1 = /*@__PURE__*/getDefaultExportFromCjs(hbjsExports);
5400
5454
 
5401
- // These will be bundled by Rollup
5402
- // @ts-expect-error - no declarations for harfbuzzjs/hb.js
5403
5455
  let harfbuzzPromise = null;
5404
5456
  let wasmPath = null;
5405
- let wasmBuffer = null; // Add buffer option
5457
+ let wasmBuffer = null;
5406
5458
  const HarfBuzzLoader = {
5407
5459
  setWasmPath(path) {
5408
5460
  wasmPath = path;
@@ -5425,12 +5477,7 @@ const HarfBuzzLoader = {
5425
5477
  moduleConfig.wasmBinary = wasmBuffer;
5426
5478
  }
5427
5479
  else if (wasmPath) {
5428
- moduleConfig.locateFile = (path, scriptDirectory) => {
5429
- if (path.endsWith('.wasm')) {
5430
- return wasmPath;
5431
- }
5432
- return scriptDirectory + path;
5433
- };
5480
+ moduleConfig.wasmBinary = await loadBinary(wasmPath);
5434
5481
  }
5435
5482
  else {
5436
5483
  throw new Error('HarfBuzz WASM path or buffer must be set before initialization.');
@@ -5552,6 +5599,11 @@ class Text {
5552
5599
  static { this.fontCacheMemoryBytes = 0; }
5553
5600
  static { this.maxFontCacheMemoryBytes = Infinity; }
5554
5601
  static { this.fontIdCounter = 0; }
5602
+ // Enable WOFF2 font support (adds ~45KB to bundle if imported)
5603
+ // Usage: import { decode } from 'woff2-decode'; Text.enableWoff2(decode);
5604
+ static enableWoff2(decoder) {
5605
+ setWoff2Decoder(decoder);
5606
+ }
5555
5607
  // Stringify with sorted keys for cache stability
5556
5608
  static stableStringify(obj) {
5557
5609
  const keys = Object.keys(obj).sort();
@@ -5727,14 +5779,7 @@ class Text {
5727
5779
  Text.hbInitPromise = HarfBuzzLoader.getHarfBuzz();
5728
5780
  }
5729
5781
  await Text.hbInitPromise;
5730
- const fontBuffer = typeof fontSrc === 'string'
5731
- ? await fetch(fontSrc).then((res) => {
5732
- if (!res.ok) {
5733
- throw new Error(`Failed to load font from ${fontSrc}: HTTP ${res.status} ${res.statusText}`);
5734
- }
5735
- return res.arrayBuffer();
5736
- })
5737
- : fontSrc;
5782
+ const fontBuffer = typeof fontSrc === 'string' ? await loadBinary(fontSrc) : fontSrc;
5738
5783
  try {
5739
5784
  if (this.loadedFont) {
5740
5785
  this.destroy();