three-text 0.2.6 → 0.2.8

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 @@ A high fidelity 3D font renderer 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 last at least through the end of 2025. 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** renders and formats text from TTF, OTF, and WOFF font files as 3D geometry. It uses [TeX](https://en.wikipedia.org/wiki/TeX)-based parameters for breaking text into paragraphs across multiple lines, and turns font outlines into 3D shapes on the fly, caching their geometries for low CPU overhead in languages with lots of repeating glyphs. Variable fonts are supported as static instances at a given axis coordinate
18
+ **three-text** renders and formats text from TTF, OTF, and WOFF font files as 3D geometry. It uses [TeX](https://en.wikipedia.org/wiki/TeX)-based parameters for breaking text into paragraphs across multiple lines, and turns font outlines into 3D shapes on the fly. Glyph geometry is cached for low CPU overhead, especially in languages with lots of repeating glyphs. Variable fonts are supported as static instances at a given axis coordinate
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
 
@@ -243,7 +243,7 @@ Existing solutions take different approaches:
243
243
  - **three-bmfont-text** is a 2D approach for Three.js, using pre-rendered bitmap fonts with SDF support. Texture atlases are generated at specific sizes, and artifacts are apparent up close
244
244
  - **troika-three-text** uses MSDF, which improves quality, and like three-text, it is built on HarfBuzz, which provides substantial language coverage, but is ultimately a 2D technique in image space. For flat text that does not need formatting or extrusion, and where artifacts are acceptable up close, troika works well
245
245
 
246
- three-text generates true 3D geometry from font files via HarfBuzz. It is sharper at close distances than bitmap approaches when flat, and produces real mesh data that can be used with any rendering system. The library caches tessellated glyphs, so a paragraph of 1000 words might only require 50 tessellations depending on the language. This makes it well-suited to longer texts. In addition to performance considerations, three-text provides control over typesetting and paragraph justification via TeX-based parameters
246
+ three-text generates true 3D geometry from font files via HarfBuzz. It is sharper at close distances than bitmap approaches when flat, and produces real mesh data that can be used with any rendering system. The library caches glyph geometry, so a paragraph of 1000 words might only require 50 unique glyphs to be processed. This makes it well-suited to longer texts. In addition to performance considerations, three-text provides control over typesetting and paragraph justification via TeX-based parameters
247
247
 
248
248
  ## Library structure
249
249
 
@@ -298,7 +298,7 @@ Hyphenation uses patterns derived from the Tex hyphenation project, converted in
298
298
 
299
299
  ### Geometry generation and optimization
300
300
 
301
- To optimize performance, three-text generates the geometry for each unique glyph or glyph cluster only once. The result is stored in a cache for reuse. This initial geometry creation is a multi-stage pipeline:
301
+ The geometry pipeline runs once per unique glyph (or glyph cluster), with intermediate results cached to avoid redundant work:
302
302
 
303
303
  1. **Path collection**: HarfBuzz callbacks provide low level drawing operations
304
304
  2. **Curve polygonization**: Uses Anti-Grain Geometry's recursive subdivision to convert bezier curves into polygons, concentrating points where curvature is high
@@ -315,7 +315,7 @@ The multi-stage geometry approach (curve polygonization followed by cleanup, the
315
315
 
316
316
  The library uses a hybrid caching strategy to maximize performance while ensuring visual correctness
317
317
 
318
- By default, it operates with glyph-level cache. The geometry for each unique character (`a`, `b`, `c`...) is generated only once and stored for reuse to avoiding redundant computation
318
+ By default, it operates with glyph-level cache. The geometry for each unique character (`a`, `b`, `c`...) is generated only once and stored for reuse, avoiding redundant computation
319
319
 
320
320
  For text with tight tracking, connected scripts, or complex kerning pairs, individual glyphs can overlap. When an overlap within a word is found, the entire word is treated as a single unit and escalated to a word-level cache. All of its glyphs are tessellated together to correctly resolve the overlaps, and the resulting geometry for the word is cached
321
321
 
@@ -395,7 +395,8 @@ The Knuth-Plass algorithm provides extensive control over line breaking quality:
395
395
  - **tolerance** (800): Maximum badness for the second pass with hyphenation
396
396
  - **emergencyStretch** (0): Additional stretchability for difficult paragraphs
397
397
  - **autoEmergencyStretch** (0.1): Emergency stretch as percentage of line width (e.g., 0.1 = 10%). Defaults to 10% for non-hyphenated text
398
- - **disableSingleWordDetection** (false): Disable automatic prevention of short single-word lines
398
+ - **disableShortLineDetection** (false): Disable automatic prevention of short lines
399
+ - **shortLineThreshold** (0.5): Width ratio threshold for short line detection (0.0 to 1.0)
399
400
 
400
401
  #### Advanced parameters
401
402
 
@@ -416,9 +417,9 @@ The Knuth-Plass algorithm provides extensive control over line breaking quality:
416
417
 
417
418
  Lower penalty/tolerance values produce tighter spacing but may fail to find acceptable breaks for challenging text
418
419
 
419
- #### Single-word line detection
420
+ #### Short line detection
420
421
 
421
- By default, the library detects and prevents short single-word lines (words occupying less than 50% of the line width on non-final lines) by iteratively applying emergency stretch. This can be disabled if needed:
422
+ By default, the library detects and prevents short lines (lines occupying less than 50% of the target width on non-final lines) by iteratively applying emergency stretch. This can be customized or disabled:
422
423
 
423
424
  ```javascript
424
425
  const text = await Text.create({
@@ -426,7 +427,9 @@ const text = await Text.create({
426
427
  font: '/fonts/Font.ttf',
427
428
  layout: {
428
429
  width: 1000,
429
- disableSingleWordDetection: true,
430
+ shortLineThreshold: 0.6, // Only flag lines < 60% width (more lenient)
431
+ // Or disable entirely:
432
+ // disableShortLineDetection: true,
430
433
  },
431
434
  });
432
435
  ```
@@ -754,9 +757,9 @@ interface LayoutOptions {
754
757
  pretolerance?: number; // Maximum badness for first pass (default: 100)
755
758
  emergencyStretch?: number; // Additional stretchability for difficult paragraphs
756
759
  autoEmergencyStretch?: number; // Emergency stretch as percentage of line width (defaults to 10% for non-hyphenated)
757
- disableSingleWordDetection?: boolean; // Disable automatic single-word line prevention (default: false)
758
- lefthyphenmin?: number; // Minimum character
759
- // s before hyphen (default: 2)
760
+ disableShortLineDetection?: boolean; // Disable automatic short line prevention (default: false)
761
+ shortLineThreshold?: number; // Width ratio threshold for short line detection (default: 0.5)
762
+ lefthyphenmin?: number; // Minimum characters before hyphen (default: 2)
760
763
  righthyphenmin?: number; // Minimum characters after hyphen (default: 4)
761
764
  linepenalty?: number; // Base penalty per line (default: 10)
762
765
  adjdemerits?: number; // Penalty for incompatible fitness classes (default: 10000)
@@ -940,9 +943,9 @@ While `three-text` runs on all modern browsers, performance varies significantly
940
943
 
941
944
  **Chrome** provides the best experience
942
945
 
943
- **Firefox** also delivers great performance but may exhibit less responsive mouse interactions in WebGL contexts due to the way it handles events
946
+ **Firefox** also delivers great performance but may exhibit less responsive mouse interactions
944
947
 
945
- **Safari** for macOS shows reduced performance, which is likely due to the platform's conservative resource management, particularly around battery life; 120FPS is not acheivable
948
+ **Safari** for macOS shows reduced performance, which is likely due to the platform's conservative resource management; 120FPS is not acheivable
946
949
 
947
950
  The library was also tested on a Brightsign 223HD, which took a long time to generate the initial geometry but seemed fine after that
948
951
 
@@ -958,6 +961,23 @@ npm test -- --coverage # Coverage report
958
961
 
959
962
  Tests use mocked HarfBuzz and tessellation libraries for fast execution without requiring WASM files
960
963
 
964
+ ### Benchmarking
965
+
966
+ For performance of the real pipeline using HarfBuzz, including shaping, layout, tessellation, extrusion, there is a dedicated benchmark:
967
+
968
+ ```bash
969
+ npm run benchmark
970
+ ```
971
+
972
+ This runs a Node/Vitest scenario that:
973
+
974
+ - initializes HarfBuzz from `hb.wasm` via `Text.setHarfBuzzBuffer`
975
+ - loads Nimbus Sans and tests the example paragraph from the demos
976
+ - performs a small number of cold runs followed by warm runs of `Text.create()` with justification and hyphenation enabled
977
+ - prints a per-stage timing table (font load, line breaking, polygonization, tessellation, extrusion, and overall geometry creation)
978
+
979
+ Use this to compare changes locally; it is meant as a sanity check on real work rather than a reliable micro-benchmark
980
+
961
981
  ## Build system
962
982
 
963
983
  ### Development