three-text 0.4.10 → 0.4.12

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.
Files changed (76) hide show
  1. package/README.md +257 -38
  2. package/dist/index.cjs +3409 -3356
  3. package/dist/index.d.ts +166 -9
  4. package/dist/index.js +3405 -3357
  5. package/dist/index.min.cjs +765 -746
  6. package/dist/index.min.js +756 -737
  7. package/dist/index.umd.js +3548 -3487
  8. package/dist/index.umd.min.js +800 -776
  9. package/dist/p5/index.cjs +2738 -5
  10. package/dist/p5/index.js +2738 -5
  11. package/dist/slug/index.cjs +380 -0
  12. package/dist/slug/index.d.ts +62 -0
  13. package/dist/slug/index.js +374 -0
  14. package/dist/three/index.cjs +50 -35
  15. package/dist/three/index.js +50 -35
  16. package/dist/three/react.cjs +5 -2
  17. package/dist/three/react.d.ts +69 -120
  18. package/dist/three/react.js +6 -3
  19. package/dist/types/core/Text.d.ts +3 -10
  20. package/dist/types/core/cache/sharedCaches.d.ts +2 -1
  21. package/dist/types/core/shaping/DrawCallbacks.d.ts +11 -3
  22. package/dist/types/core/shaping/TextShaper.d.ts +1 -5
  23. package/dist/types/core/types.d.ts +87 -0
  24. package/dist/types/index.d.ts +7 -3
  25. package/dist/types/{core/cache → mesh}/GlyphContourCollector.d.ts +4 -4
  26. package/dist/types/{core/cache → mesh}/GlyphGeometryBuilder.d.ts +5 -5
  27. package/dist/types/mesh/MeshGeometryBuilder.d.ts +18 -0
  28. package/dist/types/{core → mesh}/geometry/BoundaryClusterer.d.ts +1 -1
  29. package/dist/types/{core → mesh}/geometry/Extruder.d.ts +1 -1
  30. package/dist/types/{core → mesh}/geometry/PathOptimizer.d.ts +1 -3
  31. package/dist/types/{core → mesh}/geometry/Polygonizer.d.ts +11 -6
  32. package/dist/types/{core → mesh}/geometry/Tessellator.d.ts +1 -1
  33. package/dist/types/react/utils.d.ts +2 -0
  34. package/dist/types/vector/GlyphOutlineCollector.d.ts +25 -0
  35. package/dist/types/vector/GlyphVectorGeometryBuilder.d.ts +26 -0
  36. package/dist/types/vector/LoopBlinnGeometry.d.ts +68 -0
  37. package/dist/types/vector/index.d.ts +29 -0
  38. package/dist/types/vector/loopBlinnTSL.d.ts +11 -0
  39. package/dist/types/vector/react.d.ts +24 -0
  40. package/dist/types/vector/webgl/index.d.ts +7 -0
  41. package/dist/types/vector/webgpu/index.d.ts +11 -0
  42. package/dist/vector/index.cjs +1458 -0
  43. package/dist/vector/index.d.ts +122 -0
  44. package/dist/vector/index.js +1434 -0
  45. package/dist/vector/react.cjs +153 -0
  46. package/dist/vector/react.d.ts +317 -0
  47. package/dist/vector/react.js +132 -0
  48. package/dist/vector/types/slug-lib/src/SlugPacker.d.ts +17 -0
  49. package/dist/vector/types/slug-lib/src/WebGL2Renderer.d.ts +21 -0
  50. package/dist/vector/types/slug-lib/src/WebGPURenderer.d.ts +16 -0
  51. package/dist/vector/types/slug-lib/src/index.d.ts +15 -0
  52. package/dist/vector/types/slug-lib/src/shaderStrings.d.ts +9 -0
  53. package/dist/vector/types/slug-lib/src/types.d.ts +34 -0
  54. package/dist/vector/types/src/core/types.d.ts +381 -0
  55. package/dist/vector/types/src/hyphenation/HyphenationPatternLoader.d.ts +2 -0
  56. package/dist/vector/types/src/hyphenation/index.d.ts +7 -0
  57. package/dist/vector/types/src/hyphenation/types.d.ts +6 -0
  58. package/dist/vector/types/src/utils/Cache.d.ts +14 -0
  59. package/dist/vector/types/src/utils/vectors.d.ts +75 -0
  60. package/dist/vector/types/src/vector/VectorDataBuilder.d.ts +30 -0
  61. package/dist/vector/types/src/vector/VectorThreeAdapter.d.ts +27 -0
  62. package/dist/vector/types/src/vector/index.d.ts +15 -0
  63. package/dist/vector/webgl/index.cjs +229 -0
  64. package/dist/vector/webgl/index.d.ts +53 -0
  65. package/dist/vector/webgl/index.js +227 -0
  66. package/dist/vector/webgpu/index.cjs +321 -0
  67. package/dist/vector/webgpu/index.d.ts +57 -0
  68. package/dist/vector/webgpu/index.js +319 -0
  69. package/dist/webgl-vector/index.cjs +243 -0
  70. package/dist/webgl-vector/index.d.ts +34 -0
  71. package/dist/webgl-vector/index.js +241 -0
  72. package/dist/webgpu-vector/index.cjs +336 -0
  73. package/dist/webgpu-vector/index.d.ts +38 -0
  74. package/dist/webgpu-vector/index.js +334 -0
  75. package/package.json +48 -3
  76. package/dist/types/utils/MinHeap.d.ts +0 -14
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![TypeScript](https://img.shields.io/badge/built%20with-TypeScript-007acc.svg)](https://www.typescriptlang.org/)
5
5
  [![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3_or_later-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
6
6
 
7
- High fidelity 3D mesh font geometry and text layout engine for the web
7
+ High fidelity 3D text rendering and layout for the web
8
8
 
9
9
  ![Screenshot of three-text example file](https://countertype.com/assets/three-text/3D.png)
10
10
 
@@ -13,22 +13,21 @@ High fidelity 3D mesh font geometry and text layout engine for the web
13
13
  ## Overview
14
14
 
15
15
  > [!CAUTION]
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
16
+ > three-text is in alpha release and the API may break rapidly. This warning will likely last until summer of 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, 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
18
+ **three-text** is a 3D font rendering and text layout library for the web. It supports TTF, OTF, WOFF, and WOFF2 font files and uses [TeX](https://en.wikipedia.org/wiki/TeX)-based parameters for layout, with support for CJK and RTL scripts. Two rendering pipelines share the same core: **mesh** (extruded, lit, deformable geometry) and **vector** (resolution-independent Loop-Blinn outlines). Contours and geometries are cached per glyph for low CPU overhead in text-heavy scenes. Variable fonts are supported
19
19
 
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)
20
+ The library has a framework-agnostic core 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
 
22
- Under the hood, three-text relies on [harfbuzzjs](https://github.com/harfbuzz/harfbuzzjs) (based on [HarfBuzz](https://github.com/harfbuzz/harfbuzz) by Behdad Esfahbod et al) for text shaping, [Knuth-Plass](http://www.eprg.org/G53DOC/pdfs/knuth-plass-breaking.pdf) line breaking (with [SILE](https://github.com/sile-typesetter/sile/blob/master/core/break.lua) being the cleanest modern reference), [Liang](https://tug.org/docs/liang/liang-thesis.pdf) hyphenation and the [TeX hyphenation patterns](https://github.com/hyphenation/tex-hyphen), [libtess-ts](https://github.com/countertype/libtess-ts) (a port of the [GLU tessellator](https://www.songho.ca/opengl/gl_tessellation.html) by Eric Veach) for removing overlaps and triangulation, adaptive curve polygonization from Maxim Shemanarev's [Anti-Grain Geometry](https://web.archive.org/web/20060128212843/http://www.antigrain.com/research/adaptive_bezier/index.html), [Visvalingam-Whyatt](https://hull-repository.worktribe.com/preview/376364/000870493786962263.pdf) [line simplification](https://bost.ocks.org/mike/simplify/), as well as [woff-lib](https://github.com/countertype/woff-lib) for optional WOFF2 support
22
+ Under the hood, three-text relies on a core of [harfbuzzjs](https://github.com/harfbuzz/harfbuzzjs) (based on [HarfBuzz](https://github.com/harfbuzz/harfbuzz) by Behdad Esfahbod et al) for text shaping, [Knuth-Plass](http://www.eprg.org/G53DOC/pdfs/knuth-plass-breaking.pdf) line breaking (with [SILE](https://github.com/sile-typesetter/sile/blob/master/core/break.lua) and LuaTex being the closest modern references), [Liang](https://tug.org/docs/liang/liang-thesis.pdf) hyphenation and the [TeX hyphenation patterns](https://github.com/hyphenation/tex-hyphen), and [woff-lib](https://github.com/countertype/woff-lib) for optional WOFF2 support. The mesh text pipeline uses [libtess-ts](https://github.com/countertype/libtess-ts) (a port of the [GLU tessellator](https://www.songho.ca/opengl/gl_tessellation.html) by Eric Veach) for removing overlaps and triangulation, adaptive curve polygonization from Maxim Shemanarev's [Anti-Grain Geometry](https://web.archive.org/web/20060128212843/http://www.antigrain.com/research/adaptive_bezier/index.html), and [Visvalingam-Whyatt](https://hull-repository.worktribe.com/preview/376364/000870493786962263.pdf) [line simplification](https://bost.ocks.org/mike/simplify/). The vector pipeline uses [Loop-Blinn](https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf) resolution-independent curve rendering with [Kokojima et al.](https://dl.acm.org/doi/10.1145/1179849.1179997) stencil filling
23
23
 
24
24
  ## Table of contents
25
25
 
26
26
  - [Overview](#overview)
27
27
  - [Getting started](#getting-started)
28
28
  - [Architecture](#architecture)
29
- - [Three.js](#threejs)
30
- - [React Three Fiber](#react-three-fiber)
31
- - [p5.js](#p5js)
29
+ - [Mesh vs vector](#mesh-vs-vector)
30
+ - [Basic Usage](#basic-usage)
32
31
  - [Coordinate systems](#coordinate-systems)
33
32
  - [Development and examples](#development-and-examples)
34
33
  - [Why three-text?](#why-three-text)
@@ -63,22 +62,44 @@ npm install three
63
62
 
64
63
  three-text has a framework-agnostic core that processes fonts and generates geometry data. Lightweight adapters convert this data to framework-specific formats:
65
64
 
66
- - **`three-text`** - Three.js adapter (default export, returns BufferGeometry)
67
- - **`three-text/three`** - Same as above (explicit alias)
68
- - **`three-text/three/react`** - React Three Fiber component
65
+ - **`three-text`** - Three.js adapter (default export, returns `BufferGeometry`)
66
+ - **`three-text/mesh`** - Same as above (explicit alias)
67
+ - **`three-text/mesh/react`** - React Three Fiber component for extruded mesh text
68
+ - **`three-text/three`** - Deprecated, use `three-text/mesh`
69
+ - **`three-text/three/react`** - Deprecated, use `three-text/mesh/react`
70
+ - **`three-text/mesh/webgl`** - WebGL mesh buffer utility
71
+ - **`three-text/mesh/webgpu`** - WebGPU mesh buffer utility
72
+ - **`three-text/mesh/p5`** - p5.js adapter
69
73
  - **`three-text/core`** - Framework-agnostic core (returns raw arrays)
70
- - **`three-text/webgl`** - WebGL buffer utility
71
- - **`three-text/webgpu`** - WebGPU buffer utility
72
- - **`three-text/p5`** - p5.js adapter
74
+ - **`three-text/vector`** - Vector rendering (Loop-Blinn and Kokojima stencil fill, resolution-independent)
75
+ - **`three-text/vector/react`** - React Three Fiber component for vector text
76
+ - **`three-text/vector/webgl`** - WebGL vector renderer
77
+ - **`three-text/vector/webgpu`** - WebGPU vector renderer
78
+ - **`three-text/webgl`** - Deprecated, use `three-text/mesh/webgl`
79
+ - **`three-text/webgpu`** - Deprecated, use `three-text/mesh/webgpu`
80
+ - **`three-text/p5`** - Deprecated, use `three-text/mesh/p5`
73
81
 
74
- Most users will just `import { Text } from 'three-text'` for Three.js projects
82
+ Most users will just `import { Text } from 'three-text'` for Three.js projects with mesh, or `import { Text } from 'three-text/vector'` for vector text
83
+
84
+ ### Mesh vs vector
85
+
86
+ The library offers two rendering modes that share the same core (HarfBuzz shaping, Knuth-Plass justification, glyph caching):
87
+
88
+ - **Mesh** (`three-text` (default) / `three-text/mesh`): triangulated geometry you can extrude, light, and shade. Use for 3D text, text in a scene graph, or anywhere you need depth
89
+ - **Vector** (`three-text/vector`): resolution-independent rendering on the GPU without tessellation. Use for text that needs to stay sharp at arbitrary zoom
90
+
91
+ Both can be used in the same project from separate entry points
92
+
93
+ **React Three Fiber:** both `three-text/mesh/react` and `three-text/vector/react` export `Text`
75
94
 
76
95
  ### Basic Usage
77
96
 
78
- #### Three.js
97
+ #### Mesh (Three.js)
98
+
99
+ Extruded `BufferGeometry` — light, shade, and deform as a normal mesh:
79
100
 
80
101
  ```javascript
81
- import { Text } from 'three-text/three';
102
+ import { Text } from 'three-text';
82
103
  import { woff2Decode } from 'woff-lib/woff2/decode';
83
104
  import * as THREE from 'three';
84
105
 
@@ -94,11 +115,58 @@ const mesh = new THREE.Mesh(result.geometry, material);
94
115
  scene.add(mesh);
95
116
  ```
96
117
 
97
- #### React Three Fiber
118
+ #### Vector (Three.js)
119
+
120
+ Resolution-independent outlines via Loop-Blinn stencil passes (see [Vector rendering](#vector-rendering)):
121
+
122
+ ```javascript
123
+ import { Text } from 'three-text/vector';
124
+ import { woff2Decode } from 'woff-lib/woff2/decode';
125
+
126
+ Text.setHarfBuzzPath('/hb/hb.wasm');
127
+ Text.enableWoff2(woff2Decode);
128
+ const result = await Text.create({
129
+ text: 'Hello Vector',
130
+ font: '/fonts/Font.woff2',
131
+ size: 72
132
+ });
133
+
134
+ const vectorData = result.geometryData;
135
+ ```
136
+
137
+ Use `createVectorMeshes(vectorData)` from `three-text/vector` for TSL / `WebGPURenderer`, or build your own stencil materials (see [Vector rendering](#vector-rendering))
138
+
139
+ #### Mesh + vector in one scene
140
+
141
+ Alias one import to avoid the name collision between `Text` components. The entry points share a core (shaping, layout, font cache) so you can mix them freely — fonts load once regardless of which entry point requests them:
142
+
143
+ ```javascript
144
+ import { Text as MeshText } from 'three-text';
145
+ import { Text as VectorText, createVectorMeshes } from 'three-text/vector';
146
+
147
+ MeshText.setHarfBuzzPath('/hb/hb.wasm');
148
+
149
+ const heading = await MeshText.create({
150
+ text: 'Heading',
151
+ font: '/fonts/Font.woff2',
152
+ size: 72, depth: 10
153
+ });
154
+ scene.add(new THREE.Mesh(heading.geometry, material));
155
+
156
+ const caption = await VectorText.create({
157
+ text: 'Caption text',
158
+ font: '/fonts/Font.woff2',
159
+ size: 24
160
+ });
161
+ const { interiorMesh, curveMesh, fillMesh } = createVectorMeshes(caption.geometryData);
162
+ scene.add(interiorMesh, curveMesh, fillMesh);
163
+ ```
164
+
165
+ #### React Three Fiber — mesh
98
166
 
99
167
  ```jsx
100
168
  import { Canvas } from '@react-three/fiber';
101
- import { Text } from 'three-text/three/react';
169
+ import { Text } from 'three-text/mesh/react';
102
170
 
103
171
  Text.setHarfBuzzPath('/hb/hb.wasm');
104
172
 
@@ -114,6 +182,72 @@ function App() {
114
182
  }
115
183
  ```
116
184
 
185
+ #### React Three Fiber — vector
186
+
187
+ The vector `Text` builds three internal meshes (interior / curve / fill) with TSL stencil materials. Requires a renderer that supports `MeshBasicNodeMaterial` (Three.js r170+). With WebGPU, pass a `WebGPURenderer` with `stencil: true` and await `init()` (see the [three.js WebGPU examples](https://threejs.org/examples/?q=webgpu)):
188
+
189
+ ```jsx
190
+ import { Canvas } from '@react-three/fiber';
191
+ import * as THREE from 'three/webgpu';
192
+ import { Text } from 'three-text/vector/react';
193
+
194
+ Text.setHarfBuzzPath('/hb/hb.wasm');
195
+
196
+ function App() {
197
+ return (
198
+ <Canvas
199
+ gl={async (props) => {
200
+ const renderer = new THREE.WebGPURenderer({
201
+ canvas: props.canvas,
202
+ stencil: true
203
+ });
204
+ await renderer.init();
205
+ return renderer;
206
+ }}
207
+ >
208
+ <Text font="/fonts/Font.woff" size={72} fillColor="#ffffff">
209
+ Sharp vector text
210
+ </Text>
211
+ </Canvas>
212
+ );
213
+ }
214
+ ```
215
+
216
+ #### React Three Fiber — both in one app
217
+
218
+ Since both adapters export `Text`, alias one at the import site:
219
+
220
+ ```jsx
221
+ import { Canvas } from '@react-three/fiber';
222
+ import * as THREE from 'three/webgpu';
223
+ import { Text as MeshText } from 'three-text/mesh/react';
224
+ import { Text as VectorText } from 'three-text/vector/react';
225
+
226
+ MeshText.setHarfBuzzPath('/hb/hb.wasm');
227
+
228
+ function App() {
229
+ return (
230
+ <Canvas
231
+ gl={async (props) => {
232
+ const renderer = new THREE.WebGPURenderer({
233
+ canvas: props.canvas,
234
+ stencil: true
235
+ });
236
+ await renderer.init();
237
+ return renderer;
238
+ }}
239
+ >
240
+ <MeshText font="/fonts/Font.woff" size={72} depth={10}>
241
+ Extruded heading
242
+ </MeshText>
243
+ <VectorText font="/fonts/Font.woff" size={24} fillColor="#cccccc">
244
+ Sharp caption
245
+ </VectorText>
246
+ </Canvas>
247
+ );
248
+ }
249
+ ```
250
+
117
251
  #### p5.js
118
252
 
119
253
  ```javascript
@@ -147,6 +281,54 @@ function draw() {
147
281
 
148
282
  `createThreeTextGeometry()` accepts all the same options as Three.js (`layout`, `fontVariations`, `depth`, etc.) and returns `{ geometry, planeBounds, glyphs }`. Use `planeBounds` to center the text
149
283
 
284
+ #### Vector rendering
285
+
286
+ **Raw WebGL2 (via `three-text/vector/webgl`):**
287
+
288
+ ```javascript
289
+ import { Text } from 'three-text/vector';
290
+ import { createWebGLVectorRenderer } from 'three-text/vector/webgl';
291
+ import { woff2Decode } from 'woff-lib/woff2/decode';
292
+
293
+ Text.setHarfBuzzPath('/hb/hb.wasm');
294
+ Text.enableWoff2(woff2Decode);
295
+
296
+ const gl = canvas.getContext('webgl2', { antialias: true, stencil: true });
297
+ const renderer = createWebGLVectorRenderer(gl);
298
+
299
+ const result = await Text.create({ text: 'Hello', font: '/fonts/Font.woff2', size: 72 });
300
+ const vectorData = result.geometryData;
301
+ renderer.setGeometry(vectorData);
302
+
303
+ // In render loop:
304
+ renderer.render(mvpMatrix, new Float32Array([1, 1, 1, 1]));
305
+ ```
306
+
307
+ **Raw WebGPU (via `three-text/vector/webgpu`):**
308
+
309
+ ```javascript
310
+ import { Text } from 'three-text/vector';
311
+ import { createWebGPUVectorRenderer } from 'three-text/vector/webgpu';
312
+ import { woff2Decode } from 'woff-lib/woff2/decode';
313
+
314
+ Text.setHarfBuzzPath('/hb/hb.wasm');
315
+ Text.enableWoff2(woff2Decode);
316
+
317
+ const renderer = createWebGPUVectorRenderer(device, format, {
318
+ depthStencilFormat: 'depth24plus-stencil8',
319
+ sampleCount: 4
320
+ });
321
+
322
+ const result = await Text.create({ text: 'Hello', font: '/fonts/Font.woff2', size: 72 });
323
+ const vectorData = result.geometryData;
324
+ renderer.setGeometry(vectorData);
325
+
326
+ // In render pass:
327
+ renderer.render(passEncoder, mvpMatrix, new Float32Array([1, 1, 1, 1]));
328
+ ```
329
+
330
+ See `examples/webgl-vector.html` and `examples/webgpu-vector.html` for raw WebGL/WebGPU demos. The main interactive demo (`examples/index.html`) uses `WebGPURenderer` with TSL node materials for both mesh and Loop-Blinn vector paths. A `WebGLRenderer` variant is available at `examples/index-webgl.html`
331
+
150
332
  ### Coordinate systems
151
333
 
152
334
  The core library uses a right-handed coordinate system with +Y down. Text extrudes from z=0 toward positive Z
@@ -253,15 +435,24 @@ Then navigate to `http://localhost:3000`
253
435
 
254
436
  ## Why three-text?
255
437
 
256
- three-text generates high-fidelity 3D mesh geometry from font files. Unlike texture-based approaches, it produces true geometry that can be lit, shaded, and manipulated like any 3D model
438
+ three-text renders text from real font files (TTF, OTF, WOFF, WOFF2) with two pipelines:
439
+
440
+ - **Mesh** — tessellated 3D geometry that can be extruded, lit, and shaded like any model
441
+ - **Vector** — resolution-independent outlines rendered directly from curve data on the GPU, sharp at any zoom or angle
442
+
443
+ Both share the same layout engine (HarfBuzz shaping, Knuth-Plass line breaking) and glyph cache, so a paragraph of 1000 words might only require 50 unique glyphs to be processed
257
444
 
258
445
  Existing solutions take different approaches:
259
446
 
260
- - **Three.js native TextGeometry** uses fonts converted by facetype.js to JSON format. It creates 3D text by extruding flat 2D character outlines. While this produces true 3D geometry with depth, there is no support for real fonts or OpenType features needed for many of the world's scripts
261
- - **three-bmfont-text** renders from pre-generated SDF atlas textures. Atlases are built offline at fixed sizes
262
- - **troika-three-text** generates SDF glyphs at runtime from font files via HarfBuzz. More flexible than bmfont, but still a 2D image-space technique with artifacts up close
447
+ - **Three.js native TextGeometry** extrudes 2D outlines from facetype.js JSON. True 3D geometry with depth, but no support for real fonts or OpenType features needed for many of the world's scripts
448
+ - **three-bmfont-text** renders from pre-generated SDF atlas textures built offline at fixed sizes
449
+ - **troika-three-text** generates SDF glyphs at runtime via HarfBuzz. More flexible than bmfont, but still an image-space technique with artifacts up close
450
+
451
+ three-text produces actual geometry from font files, sharper at close distances than bitmap approaches, with control over typesetting and paragraph justification via TeX-based parameters
452
+
453
+ ### Why Loop-Blinn
263
454
 
264
- three-text generates true 3D geometry from font files via HarfBuzz. It is sharper at close distances than bitmap approaches, and produces 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. three-text also provides control over typesetting and paragraph justification via TeX-based parameters
455
+ The vector path uses Loop-Blinn curve rendering, where each quadratic Bezier segment becomes a triangle whose fragment shader evaluates the implicit equation `u² - v = 0` to resolve inside/outside analytically, while interior regions are filled separately. We also evaluated Eric Lengyel's [Slug](https://github.com/EricLengyel/Slug) algorithm, which renders glyphs by casting rays against banded curve data over a dilated bounding polygon, and tested several antialiasing configurations including adaptive supersampling and alpha-to-coverage. Loop-Blinn produced cleaner results under strong perspective and oblique viewing angles, so that is what we use
265
456
 
266
457
  ## Library structure
267
458
 
@@ -269,20 +460,32 @@ three-text generates true 3D geometry from font files via HarfBuzz. It is sharpe
269
460
  three-text/
270
461
  ├── src/
271
462
  │ ├── core/ # Framework-agnostic text engine
272
- │ │ ├── Text.ts # Core API (returns raw arrays)
463
+ │ │ ├── Text.ts # Core API, font loading, shaping, layout
273
464
  │ │ ├── vectors.ts # Vec2, Vec3, Box3Core
274
465
  │ │ ├── types.ts # TypeScript interfaces
275
466
  │ │ ├── cache/ # Glyph caching system
276
467
  │ │ ├── font/ # Font loading and metrics
277
468
  │ │ ├── shaping/ # HarfBuzz text shaping
278
- │ │ ├── layout/ # Line breaking and text layout
279
- │ └── geometry/ # Tessellation and geometry processing
469
+ │ │ └── layout/ # Line breaking and text layout
470
+ ├── mesh/ # Mesh geometry pipeline
471
+ │ │ ├── MeshGeometryBuilder.ts # Orchestrates mesh output from layout
472
+ │ │ ├── GlyphGeometryBuilder.ts # Instanced geometry from glyph contours
473
+ │ │ ├── GlyphContourCollector.ts # Collects draw callbacks for mesh path
474
+ │ │ └── geometry/ # Tessellation, extrusion, optimization
280
475
  │ ├── three/ # Three.js adapter
281
476
  │ │ ├── index.ts # BufferGeometry wrapper
282
477
  │ │ ├── react.tsx # React component export
283
478
  │ │ └── ThreeText.tsx # React Three Fiber component
284
- │ ├── webgl/ # WebGL buffer utility
285
- │ ├── webgpu/ # WebGPU buffer utility
479
+ │ ├── vector/ # Vector rendering (Loop-Blinn)
480
+ ├── index.ts # Vector entry point and TSL re-exports
481
+ │ │ ├── loopBlinnTSL.ts # TSL adapter for Three.js WebGPURenderer
482
+ │ │ ├── LoopBlinnGeometry.ts # Fan triangulation + curve extraction
483
+ │ │ ├── GlyphVectorGeometryBuilder.ts # Outline collection and geometry packing
484
+ │ │ ├── GlyphOutlineCollector.ts # Collects draw callbacks for vector path
485
+ │ │ ├── webgl/ # WebGL2 stencil-based renderer
486
+ │ │ └── webgpu/ # WebGPU stencil-based renderer
487
+ │ ├── webgl/ # WebGL mesh buffer utility
488
+ │ ├── webgpu/ # WebGPU mesh buffer utility
286
489
  │ ├── p5/ # p5.js adapter
287
490
  │ ├── hyphenation/ # Language-specific hyphenation patterns
288
491
  │ └── utils/ # Performance logging, data structures
@@ -316,7 +519,7 @@ Hyphenation uses patterns derived from the Tex hyphenation project, converted in
316
519
 
317
520
  ### Geometry generation and optimization
318
521
 
319
- The geometry pipeline runs once per unique glyph (or glyph cluster), with intermediate results cached to avoid redundant work:
522
+ By default, three-text runs in mesh mode, generating triangulated geometry from glyph outlines that you can extrude, light, or deform. The mesh pipeline runs once per unique glyph (or glyph cluster), with intermediate results cached to avoid redundant work:
320
523
 
321
524
  1. **Path collection**: HarfBuzz callbacks provide low level drawing operations
322
525
  2. **Curve polygonization**: Flattens bezier curves into line segments, placing more points where curves are tight
@@ -328,6 +531,14 @@ The geometry pipeline runs once per unique glyph (or glyph cluster), with interm
328
531
 
329
532
  The multi-stage geometry approach (curve polygonization followed by cleanup, then triangulation) reduces triangle counts and removes overlaps in variable fonts
330
533
 
534
+ ### Vector rendering
535
+
536
+ The vector pipeline (`three-text/vector`) renders glyphs directly from their mathematical outlines without tessellation or curve flattening. Text stays sharp at any zoom level and the geometry footprint is small -- just the control points of each curve
537
+
538
+ Curves use the [Loop-Blinn](https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf) technique: each quadratic curve is rendered as a triangle whose fragment shader evaluates `u² - v` to resolve inside/outside, with screen-space derivatives producing a signed distance that feeds alpha-to-coverage for smooth MSAA edges. Glyph interiors use [Kokojima et al.](https://dl.acm.org/doi/10.1145/1179849.1179997) stencil filling: fan-triangulate, stencil XOR, fill where nonzero
539
+
540
+ An alternative for this sort of resolution-independent rendering is [Slug](https://github.com/EricLengyel/Slug) by Eric Lengyel, which casts rays against all curves per fragment to compute winding numbers. Loop-Blinn was chosen here because it integrates with hardware MSAA and alpha-to-coverage directly, without the overhead of adaptive supersampling that Slug requires for comparable antialiasing
541
+
331
542
  #### Glyph caching
332
543
 
333
544
  The library uses a hybrid caching strategy to maximize performance while ensuring visual correctness
@@ -339,7 +550,7 @@ For text with tight tracking, connected scripts, or complex kerning pairs, indiv
339
550
 
340
551
  #### Flat geometry mode
341
552
 
342
- When `depth` is 0, the library generates single-sided geometry, reducing triangles by approximately 50%
553
+ When `depth` is 0 in mesh mode, the library generates single-sided geometry, reducing triangles by approximately 50%
343
554
 
344
555
  - Use `THREE.DoubleSide` for flat text so it remains visible from both sides
345
556
  - For extruded text, `THREE.FrontSide` is typical since front and back faces are separate geometry
@@ -369,11 +580,11 @@ const text = await Text.create({
369
580
  },
370
581
  });
371
582
 
372
- // Fixed-step: 8 segments per curve
583
+ // Fixed-step: 32 segments per curve
373
584
  const text = await Text.create({
374
585
  text: 'Sample',
375
586
  font: '/fonts/Font.ttf',
376
- curveSteps: 8,
587
+ curveSteps: 32,
377
588
  });
378
589
  ```
379
590
 
@@ -385,6 +596,8 @@ After curve polygonization, the library applies Visvalingam-Whyatt simplificatio
385
596
  const text = await Text.create({
386
597
  text: 'Sample text',
387
598
  font: '/fonts/Font.ttf',
599
+ // Fixed-step: 32 segments per curve
600
+ curveSteps: 32,
388
601
  geometryOptimization: {
389
602
  areaThreshold: 1.0, // remove triangles < 1 font unit²
390
603
  },
@@ -533,7 +746,7 @@ Common tags include [`liga`](https://learn.microsoft.com/en-us/typography/openty
533
746
 
534
747
  ### Per-glyph attributes
535
748
 
536
- For shader-based animations and interactive effects, the library can generate per-vertex attributes that identify which glyph each vertex belongs to:
749
+ For shader-based animations and interactive effects, the library can generate per-vertex attributes that identify which glyph each vertex belongs to. Both mesh and vector entry points support this: pass `perGlyphAttributes: true` to `Text.create()`
537
750
 
538
751
  ```javascript
539
752
  const text = await Text.create({
@@ -550,7 +763,9 @@ const text = await Text.create({
550
763
  // - glyphBaselineY (float): Y coordinate of glyph baseline
551
764
  ```
552
765
 
553
- This option bypasses overlap-based clustering and adds vertex attributes suitable for per-character manipulation in vertex shaders. Each unique glyph is still tessellated only once and cached for reuse. The tradeoff is potential visual artifacts where glyphs actually overlap (tight kerning, cursive scripts)
766
+ **Mesh:** attributes live on the extruded `geometry`. **Vector:** the same attributes are emitted on interior, curve, and fill buffer geometries. When you need per-glyph draw ranges (for example stencil passes that must not XOR across overlapping glyphs), use `geometryData.glyphRanges`: each entry lists index/vertex ranges for that glyph’s interior, curve, and fill quads
767
+
768
+ This option bypasses overlap-based clustering and adds vertex attributes suitable for per-character manipulation in vertex shaders (or TSL `positionNode` displacements). Each unique glyph is still tessellated only once and cached for reuse. The tradeoff is potential visual artifacts where glyphs actually overlap (tight kerning, cursive scripts)
554
769
 
555
770
  ## Querying text content
556
771
 
@@ -945,7 +1160,7 @@ While `three-text` runs on all modern browsers, performance varies significantly
945
1160
 
946
1161
  **Safari** for macOS shows reduced performance, which is likely due to the platform's conservative resource management; 120FPS is not acheivable
947
1162
 
948
- The library was also tested on a Brightsign 223HD, which took a long time to generate the initial geometry but seemed fine after that
1163
+ The library was also tested on a Brightsign 223HD, which took a very long time to generate the initial geometry but ran fine after that. We did not push our luck with further testing
949
1164
 
950
1165
  ## Testing
951
1166
 
@@ -1023,8 +1238,12 @@ The build generates multiple module formats for core and all adapters:
1023
1238
  **Adapters:**
1024
1239
  - `dist/three/` - Three.js adapter
1025
1240
  - `dist/three/react.js` - React component
1026
- - `dist/webgl/` - WebGL utility
1027
- - `dist/webgpu/` - WebGPU utility
1241
+ - `dist/vector/` - Vector rendering (Loop-Blinn, Three.js adapter)
1242
+ - `dist/vector/react.js` - React Three Fiber vector component
1243
+ - `dist/webgl/` - WebGL mesh buffer utility
1244
+ - `dist/vector/webgl/` - WebGL vector renderer
1245
+ - `dist/webgpu/` - WebGPU mesh buffer utility
1246
+ - `dist/vector/webgpu/` - WebGPU vector renderer
1028
1247
  - `dist/p5/` - p5.js adapter
1029
1248
 
1030
1249
  **Patterns:**