three-text 0.5.2 → 0.6.0
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/LICENSE_THIRD_PARTY +15 -0
- package/README.md +73 -42
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/index.min.cjs +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.min.js +1 -1
- package/dist/three/react.d.ts +2 -0
- package/dist/types/core/types.d.ts +2 -33
- package/dist/types/vector/{core.d.ts → core/index.d.ts} +8 -7
- package/dist/types/vector/index.d.ts +22 -25
- package/dist/types/vector/react.d.ts +4 -3
- package/dist/types/vector/slug/SlugPacker.d.ts +2 -0
- package/dist/types/vector/slug/curveUtils.d.ts +6 -0
- package/dist/types/vector/slug/index.d.ts +8 -0
- package/dist/types/vector/slug/shaderStrings.d.ts +4 -0
- package/dist/types/vector/slug/slugGLSL.d.ts +21 -0
- package/dist/types/vector/slug/slugTSL.d.ts +13 -0
- package/dist/types/vector/slug/types.d.ts +30 -0
- package/dist/types/vector/slug/unpackVertices.d.ts +11 -0
- package/dist/types/vector/webgl/index.d.ts +7 -3
- package/dist/types/vector/webgpu/index.d.ts +4 -4
- package/dist/vector/core/index.cjs +856 -0
- package/dist/vector/core/index.d.ts +63 -0
- package/dist/vector/core/index.js +854 -0
- package/dist/vector/core.cjs +4419 -240
- package/dist/vector/core.d.ts +361 -71
- package/dist/vector/core.js +4406 -226
- package/dist/vector/index.cjs +5 -229
- package/dist/vector/index.d.ts +45 -396
- package/dist/vector/index.js +3 -223
- package/dist/vector/index2.cjs +287 -0
- package/dist/vector/index2.js +264 -0
- package/dist/vector/react.cjs +37 -8
- package/dist/vector/react.d.ts +6 -3
- package/dist/vector/react.js +18 -8
- package/dist/vector/slugTSL.cjs +252 -0
- package/dist/vector/slugTSL.js +231 -0
- package/dist/vector/webgl/index.cjs +131 -201
- package/dist/vector/webgl/index.d.ts +19 -44
- package/dist/vector/webgl/index.js +131 -201
- package/dist/vector/webgpu/index.cjs +100 -283
- package/dist/vector/webgpu/index.d.ts +16 -45
- package/dist/vector/webgpu/index.js +100 -283
- package/package.json +6 -1
- package/dist/types/vector/GlyphVectorGeometryBuilder.d.ts +0 -26
- package/dist/types/vector/LoopBlinnGeometry.d.ts +0 -68
- package/dist/types/vector/loopBlinnTSL.d.ts +0 -22
- package/dist/vector/loopBlinnTSL.cjs +0 -229
- package/dist/vector/loopBlinnTSL.js +0 -207
package/LICENSE_THIRD_PARTY
CHANGED
|
@@ -107,6 +107,21 @@ complete source and licensing details: https://github.com/hyphenation/tex-hyphen
|
|
|
107
107
|
|
|
108
108
|
---
|
|
109
109
|
|
|
110
|
+
4. Slug Library
|
|
111
|
+
|
|
112
|
+
This software includes a port of the Slug library
|
|
113
|
+
(https://github.com/EricLengyel/Slug), a GPU-based vector graphics
|
|
114
|
+
rendering algorithm for text and shapes by Eric Lengyel. The original
|
|
115
|
+
GLSL shaders were ported to Three.js TSL (Three.js Shading Language)
|
|
116
|
+
with added adaptive supersampling
|
|
117
|
+
|
|
118
|
+
Copyright (c) 2017 Eric Lengyel
|
|
119
|
+
|
|
120
|
+
Slug is distributed under the MIT License.
|
|
121
|
+
(See Appendix A for MIT License text)
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
110
125
|
Appendix A: MIT License text
|
|
111
126
|
|
|
112
127
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
package/README.md
CHANGED
|
@@ -15,11 +15,11 @@ High fidelity 3D text rendering and layout for the web
|
|
|
15
15
|
> [!CAUTION]
|
|
16
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 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** (
|
|
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** (extrudable, deformable geometry) and **vector** (resolution-independent GPU outlines). Contours and geometries are cached per glyph for low CPU overhead in text-heavy scenes. Variable fonts are supported
|
|
19
19
|
|
|
20
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 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 [
|
|
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 [Slug](https://github.com/EricLengyel/Slug) by Eric Lengyel for resolution-independent curve rendering
|
|
23
23
|
|
|
24
24
|
## Table of contents
|
|
25
25
|
|
|
@@ -71,8 +71,9 @@ three-text has a framework-agnostic core that processes fonts and generates geom
|
|
|
71
71
|
- **`three-text/mesh/webgpu`** - WebGPU mesh buffer utility
|
|
72
72
|
- **`three-text/mesh/p5`** - p5.js adapter
|
|
73
73
|
- **`three-text/core`** - Framework-agnostic core (returns raw arrays)
|
|
74
|
-
- **`three-text/vector`** - Vector rendering (
|
|
74
|
+
- **`three-text/vector`** - Vector rendering (Slug per-fragment curve evaluation), `Text.create()` returns a `THREE.Group`
|
|
75
75
|
- **`three-text/vector/react`** - React Three Fiber component for vector text
|
|
76
|
+
- **`three-text/vector/core`** - Framework-agnostic vector core (returns raw `SlugGPUData`, no Three.js dependency)
|
|
76
77
|
- **`three-text/vector/webgl`** - Raw WebGL2 vector renderer (no Three.js dependency)
|
|
77
78
|
- **`three-text/vector/webgpu`** - Raw WebGPU vector renderer (no Three.js dependency)
|
|
78
79
|
- **`three-text/webgl`** - Deprecated, use `three-text/mesh/webgl`
|
|
@@ -86,7 +87,7 @@ Most users will just `import { Text } from 'three-text'` for Three.js projects w
|
|
|
86
87
|
The library offers two rendering modes that share the same core (HarfBuzz shaping, Knuth-Plass justification, glyph caching):
|
|
87
88
|
|
|
88
89
|
- **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
|
|
90
|
+
- **Vector** (`three-text/vector`): resolution-independent rendering on the GPU via per-fragment curve evaluation. No tessellation, no stencil buffer. Use for text that needs to stay sharp at arbitrary zoom
|
|
90
91
|
|
|
91
92
|
Both can be used in the same project from separate entry points
|
|
92
93
|
|
|
@@ -96,7 +97,7 @@ Both can be used in the same project from separate entry points
|
|
|
96
97
|
|
|
97
98
|
#### Mesh (Three.js)
|
|
98
99
|
|
|
99
|
-
Extruded `BufferGeometry`
|
|
100
|
+
Extruded `BufferGeometry` that you can light, shade, and deform like any mesh:
|
|
100
101
|
|
|
101
102
|
```javascript
|
|
102
103
|
import { Text } from 'three-text';
|
|
@@ -117,7 +118,7 @@ scene.add(mesh);
|
|
|
117
118
|
|
|
118
119
|
#### Vector (Three.js)
|
|
119
120
|
|
|
120
|
-
Resolution-independent outlines via
|
|
121
|
+
Resolution-independent outlines via per-fragment curve evaluation (see [Vector rendering](#vector-rendering)):
|
|
121
122
|
|
|
122
123
|
```javascript
|
|
123
124
|
import { Text } from 'three-text/vector';
|
|
@@ -127,16 +128,16 @@ const result = await Text.create({
|
|
|
127
128
|
text: 'Hello Vector',
|
|
128
129
|
font: '/fonts/Font.woff2',
|
|
129
130
|
size: 72,
|
|
130
|
-
color:
|
|
131
|
+
color: [1, 1, 1]
|
|
131
132
|
});
|
|
132
133
|
scene.add(result.group);
|
|
133
134
|
```
|
|
134
135
|
|
|
135
|
-
`Text.create()`
|
|
136
|
+
`Text.create()` returns a `THREE.Group` ready for `scene.add()`. Uses TSL node materials when the renderer supports them (Three.js r170+), otherwise falls back to a GLSL `RawShaderMaterial` that works with any WebGL2 renderer
|
|
136
137
|
|
|
137
138
|
#### Mesh + vector in one scene
|
|
138
139
|
|
|
139
|
-
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
|
|
140
|
+
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:
|
|
140
141
|
|
|
141
142
|
```javascript
|
|
142
143
|
import { Text as MeshText } from 'three-text';
|
|
@@ -155,7 +156,7 @@ const caption = await VectorText.create({
|
|
|
155
156
|
text: 'Caption text',
|
|
156
157
|
font: '/fonts/Font.woff2',
|
|
157
158
|
size: 24,
|
|
158
|
-
color:
|
|
159
|
+
color: [1, 1, 1]
|
|
159
160
|
});
|
|
160
161
|
scene.add(caption.group);
|
|
161
162
|
```
|
|
@@ -182,7 +183,7 @@ function App() {
|
|
|
182
183
|
|
|
183
184
|
#### React Three Fiber — vector
|
|
184
185
|
|
|
185
|
-
The vector `Text`
|
|
186
|
+
The vector `Text` component creates a single mesh with a TSL node material that evaluates curve coverage per fragment. Requires a renderer that supports `MeshBasicNodeMaterial` (Three.js r170+). With WebGPU, pass a `WebGPURenderer` and await `init()` (see the [three.js WebGPU examples](https://threejs.org/examples/?q=webgpu)):
|
|
186
187
|
|
|
187
188
|
```jsx
|
|
188
189
|
import { Canvas } from '@react-three/fiber';
|
|
@@ -197,7 +198,7 @@ function App() {
|
|
|
197
198
|
gl={async (props) => {
|
|
198
199
|
const renderer = new THREE.WebGPURenderer({
|
|
199
200
|
canvas: props.canvas,
|
|
200
|
-
|
|
201
|
+
antialias: true
|
|
201
202
|
});
|
|
202
203
|
await renderer.init();
|
|
203
204
|
return renderer;
|
|
@@ -229,7 +230,7 @@ function App() {
|
|
|
229
230
|
gl={async (props) => {
|
|
230
231
|
const renderer = new THREE.WebGPURenderer({
|
|
231
232
|
canvas: props.canvas,
|
|
232
|
-
|
|
233
|
+
antialias: true
|
|
233
234
|
});
|
|
234
235
|
await renderer.init();
|
|
235
236
|
return renderer;
|
|
@@ -291,12 +292,13 @@ import { woff2Decode } from 'woff-lib/woff2/decode';
|
|
|
291
292
|
Text.setHarfBuzzPath('/hb/hb.wasm');
|
|
292
293
|
Text.enableWoff2(woff2Decode);
|
|
293
294
|
|
|
294
|
-
const gl = canvas.getContext('webgl2', { antialias: true
|
|
295
|
-
const renderer = createWebGLVectorRenderer(gl
|
|
295
|
+
const gl = canvas.getContext('webgl2', { antialias: true });
|
|
296
|
+
const renderer = createWebGLVectorRenderer(gl, {
|
|
297
|
+
adaptiveSupersampling: true
|
|
298
|
+
});
|
|
296
299
|
|
|
297
300
|
const result = await Text.create({ text: 'Hello', font: '/fonts/Font.woff2', size: 72 });
|
|
298
|
-
|
|
299
|
-
renderer.setGeometry(vectorData);
|
|
301
|
+
renderer.setGeometry(result.gpuData);
|
|
300
302
|
|
|
301
303
|
// In render loop:
|
|
302
304
|
renderer.render(mvpMatrix, new Float32Array([1, 1, 1, 1]));
|
|
@@ -313,19 +315,52 @@ Text.setHarfBuzzPath('/hb/hb.wasm');
|
|
|
313
315
|
Text.enableWoff2(woff2Decode);
|
|
314
316
|
|
|
315
317
|
const renderer = createWebGPUVectorRenderer(device, format, {
|
|
316
|
-
depthStencilFormat: 'depth24plus-stencil8',
|
|
317
318
|
sampleCount: 4
|
|
318
319
|
});
|
|
319
320
|
|
|
320
321
|
const result = await Text.create({ text: 'Hello', font: '/fonts/Font.woff2', size: 72 });
|
|
321
|
-
|
|
322
|
-
renderer.setGeometry(vectorData);
|
|
322
|
+
renderer.setGeometry(result.gpuData);
|
|
323
323
|
|
|
324
324
|
// In render pass:
|
|
325
325
|
renderer.render(passEncoder, mvpMatrix, new Float32Array([1, 1, 1, 1]));
|
|
326
326
|
```
|
|
327
327
|
|
|
328
|
-
|
|
328
|
+
**Adaptive supersampling** is available on the GLSL code path (raw WebGL2 renderer, `createSlugGLSLMesh`, and Three.js vector when TSL is unavailable). It uses rotated-grid supersampling (RGSS, 4 samples per pixel) with a per-fragment rotation angle derived from interleaved gradient noise. This converts structured aliasing shimmer into uncorrelated grain that the eye naturally filters out. Pass `adaptiveSupersampling: true` to enable it. The TSL and WebGPU paths do not currently support this option
|
|
329
|
+
|
|
330
|
+
#### GLSL animation injection
|
|
331
|
+
|
|
332
|
+
For custom vertex animations, `createSlugGLSLMesh` gives direct access to the GLSL vertex shader. This is exported from `three-text/vector` and builds a Three.js `Mesh` backed by a `RawShaderMaterial`:
|
|
333
|
+
|
|
334
|
+
```javascript
|
|
335
|
+
import { Text, createSlugGLSLMesh } from 'three-text/vector';
|
|
336
|
+
|
|
337
|
+
const result = await Text.create({
|
|
338
|
+
text: 'Hello',
|
|
339
|
+
font: '/fonts/Font.woff2',
|
|
340
|
+
size: 72,
|
|
341
|
+
perGlyphAttributes: true
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
const { mesh, uniforms } = createSlugGLSLMesh(result.gpuData, {
|
|
345
|
+
color: { r: 1, g: 1, b: 1 },
|
|
346
|
+
adaptiveSupersampling: true,
|
|
347
|
+
animationDeclarations: `
|
|
348
|
+
uniform float waveAmplitude;
|
|
349
|
+
`,
|
|
350
|
+
animationBody: `
|
|
351
|
+
vec3 outPos = position;
|
|
352
|
+
outPos.y += sin(glyphIndex * 0.5 + time) * waveAmplitude;
|
|
353
|
+
`,
|
|
354
|
+
uniforms: {
|
|
355
|
+
waveAmplitude: { value: 10.0 }
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
scene.add(mesh);
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
The vertex shader provides `position` (vec3), `glyphCenter` (vec3), `glyphIndex` (float), and `time` (float) for use in your animation body. Your code must write a `vec3 outPos` that becomes the final vertex position
|
|
362
|
+
|
|
363
|
+
The main interactive demo (`examples/index.html`) uses `WebGPURenderer` with TSL node materials for both mesh and vector paths. A `WebGLRenderer` variant for mesh mode is available at `examples/index-webgl.html`
|
|
329
364
|
|
|
330
365
|
### Coordinate systems
|
|
331
366
|
|
|
@@ -435,8 +470,8 @@ Then navigate to `http://localhost:3000`
|
|
|
435
470
|
|
|
436
471
|
three-text renders text from real font files (TTF, OTF, WOFF, WOFF2) with two pipelines:
|
|
437
472
|
|
|
438
|
-
- **Mesh
|
|
439
|
-
- **Vector
|
|
473
|
+
- **Mesh**: tessellated 3D geometry that can be extruded, lit, and shaded like any model
|
|
474
|
+
- **Vector**: resolution-independent outlines rendered directly from curve data on the GPU, sharp at any zoom or angle
|
|
440
475
|
|
|
441
476
|
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
|
|
442
477
|
|
|
@@ -448,9 +483,9 @@ Existing solutions take different approaches:
|
|
|
448
483
|
|
|
449
484
|
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
|
|
450
485
|
|
|
451
|
-
### Why
|
|
486
|
+
### Why Slug
|
|
452
487
|
|
|
453
|
-
The vector path uses
|
|
488
|
+
The vector path uses the Slug algorithm by Eric Lengyel. Each glyph is a single quad; the fragment shader evaluates curve coverage analytically to compute a winding number. Because it operates on winding rather than geometry, it naturally handles the self-intersecting contours that variable fonts produce when axes like weight push outlines into each other
|
|
454
489
|
|
|
455
490
|
## Library structure
|
|
456
491
|
|
|
@@ -474,15 +509,12 @@ three-text/
|
|
|
474
509
|
│ │ ├── index.ts # BufferGeometry wrapper
|
|
475
510
|
│ │ ├── react.tsx # React component export
|
|
476
511
|
│ │ └── ThreeText.tsx # React Three Fiber component
|
|
477
|
-
│ ├── vector/ # Vector rendering (
|
|
478
|
-
│ │ ├── index.ts # Main entry point (
|
|
479
|
-
│ │ ├──
|
|
480
|
-
│ │ ├──
|
|
481
|
-
│ │ ├──
|
|
482
|
-
│ │
|
|
483
|
-
│ │ ├── GlyphOutlineCollector.ts # Collects draw callbacks for vector path
|
|
484
|
-
│ │ ├── webgl/ # WebGL2 stencil-based renderer
|
|
485
|
-
│ │ └── webgpu/ # WebGPU stencil-based renderer
|
|
512
|
+
│ ├── vector/ # Vector rendering (Slug)
|
|
513
|
+
│ │ ├── index.ts # Main entry point (Text.create → result.group)
|
|
514
|
+
│ │ ├── react.tsx # React Three Fiber component
|
|
515
|
+
│ │ ├── slug/ # Slug per-fragment curve evaluation
|
|
516
|
+
│ │ ├── core/ # Outline collection and Slug packing
|
|
517
|
+
│ │ └── GlyphOutlineCollector.ts # Collects draw callbacks for vector path
|
|
486
518
|
│ ├── webgl/ # WebGL mesh buffer utility
|
|
487
519
|
│ ├── webgpu/ # WebGPU mesh buffer utility
|
|
488
520
|
│ ├── p5/ # p5.js adapter
|
|
@@ -534,11 +566,9 @@ The multi-stage geometry approach (curve polygonization followed by cleanup, the
|
|
|
534
566
|
|
|
535
567
|
### Vector rendering
|
|
536
568
|
|
|
537
|
-
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
|
|
538
|
-
|
|
539
|
-
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 with a nonzero winding rule (`INCR_WRAP`/`DECR_WRAP`), which correctly handles overlapping contours in variable fonts and connected scripts
|
|
569
|
+
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: one quad per glyph
|
|
540
570
|
|
|
541
|
-
|
|
571
|
+
Each quad's fragment shader casts rays against band-indexed curve data to compute a winding number, resolving inside/outside analytically. This is the [Slug](https://jcgt.org/published/0006/02/02/) algorithm by Eric Lengyel. Because winding is evaluated per fragment from the original curves, self-intersecting contours in variable fonts are handled correctly without any special-case geometry processing
|
|
542
572
|
|
|
543
573
|
#### Glyph caching
|
|
544
574
|
|
|
@@ -764,7 +794,7 @@ const text = await Text.create({
|
|
|
764
794
|
// - glyphBaselineY (float): Y coordinate of glyph baseline
|
|
765
795
|
```
|
|
766
796
|
|
|
767
|
-
**Mesh:** attributes live on the extruded `geometry`. **Vector:** the same attributes are
|
|
797
|
+
**Mesh:** attributes live on the extruded `geometry`. **Vector:** the same attributes are present on the Slug quad mesh, where each glyph is a single quad with `glyphIndex` and `glyphCenter` attributes
|
|
768
798
|
|
|
769
799
|
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)
|
|
770
800
|
|
|
@@ -1239,12 +1269,13 @@ The build generates multiple module formats for core and all adapters:
|
|
|
1239
1269
|
**Adapters:**
|
|
1240
1270
|
- `dist/three/` - Three.js adapter
|
|
1241
1271
|
- `dist/three/react.js` - React component
|
|
1242
|
-
- `dist/vector/` - Vector rendering (
|
|
1272
|
+
- `dist/vector/` - Vector rendering (Slug per-fragment curve evaluation)
|
|
1243
1273
|
- `dist/vector/react.js` - React Three Fiber vector component
|
|
1274
|
+
- `dist/vector/core/` - Framework-agnostic vector core (raw SlugGPUData)
|
|
1275
|
+
- `dist/vector/webgl/` - Raw WebGL2 vector renderer
|
|
1276
|
+
- `dist/vector/webgpu/` - Raw WebGPU vector renderer
|
|
1244
1277
|
- `dist/webgl/` - WebGL mesh buffer utility
|
|
1245
|
-
- `dist/vector/webgl/` - WebGL vector renderer
|
|
1246
1278
|
- `dist/webgpu/` - WebGPU mesh buffer utility
|
|
1247
|
-
- `dist/vector/webgpu/` - WebGPU vector renderer
|
|
1248
1279
|
- `dist/p5/` - p5.js adapter
|
|
1249
1280
|
|
|
1250
1281
|
**Patterns:**
|
package/dist/index.cjs
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -410,6 +410,8 @@ interface TextOptions {
|
|
|
410
410
|
geometryOptimization?: GeometryOptimizationOptions;
|
|
411
411
|
layout?: LayoutOptions;
|
|
412
412
|
color?: [number, number, number] | ColorOptions;
|
|
413
|
+
/** Enable rotated RGSS-4 adaptive supersampling (4 samples per pixel). Takes effect when the GLSL rendering path is active. */
|
|
414
|
+
adaptiveSupersampling?: boolean;
|
|
413
415
|
}
|
|
414
416
|
interface HyphenationPatternsMap {
|
|
415
417
|
[language: string]: HyphenationTrieNode;
|
package/dist/index.js
CHANGED
package/dist/index.min.cjs
CHANGED
package/dist/index.min.js
CHANGED
package/dist/index.umd.js
CHANGED
package/dist/index.umd.min.js
CHANGED
package/dist/three/react.d.ts
CHANGED
|
@@ -208,6 +208,8 @@ interface TextOptions {
|
|
|
208
208
|
geometryOptimization?: GeometryOptimizationOptions;
|
|
209
209
|
layout?: LayoutOptions;
|
|
210
210
|
color?: [number, number, number] | ColorOptions;
|
|
211
|
+
/** Enable rotated RGSS-4 adaptive supersampling (4 samples per pixel). Takes effect when the GLSL rendering path is active. */
|
|
212
|
+
adaptiveSupersampling?: boolean;
|
|
211
213
|
}
|
|
212
214
|
interface HyphenationPatternsMap {
|
|
213
215
|
[language: string]: HyphenationTrieNode;
|
|
@@ -294,39 +294,6 @@ export interface VectorGlyphInfo extends GlyphGeometryInfo {
|
|
|
294
294
|
segmentStart: number;
|
|
295
295
|
segmentCount: number;
|
|
296
296
|
}
|
|
297
|
-
export interface PackedFloatTexture {
|
|
298
|
-
width: number;
|
|
299
|
-
height: number;
|
|
300
|
-
data: Float32Array;
|
|
301
|
-
}
|
|
302
|
-
export interface VectorTextGeometryInfo {
|
|
303
|
-
quadVertices: Float32Array;
|
|
304
|
-
quadIndices: Uint16Array;
|
|
305
|
-
instances: {
|
|
306
|
-
position: Float32Array;
|
|
307
|
-
bounds: Float32Array;
|
|
308
|
-
segmentRange: Uint32Array;
|
|
309
|
-
glyphDataIndex: Uint32Array;
|
|
310
|
-
glyphIndex: Uint32Array;
|
|
311
|
-
textIndex: Uint32Array;
|
|
312
|
-
lineIndex: Uint32Array;
|
|
313
|
-
};
|
|
314
|
-
segmentTexelsPerSegment: number;
|
|
315
|
-
segments: PackedFloatTexture;
|
|
316
|
-
segmentBounds?: PackedFloatTexture;
|
|
317
|
-
bandCount?: number;
|
|
318
|
-
bandRanges?: PackedFloatTexture;
|
|
319
|
-
bandIndices?: PackedFloatTexture;
|
|
320
|
-
xBandCount?: number;
|
|
321
|
-
xBandRanges?: PackedFloatTexture;
|
|
322
|
-
xBandIndices?: PackedFloatTexture;
|
|
323
|
-
tileCountX?: number;
|
|
324
|
-
tileCountY?: number;
|
|
325
|
-
tileRanges?: PackedFloatTexture;
|
|
326
|
-
tileIndices?: PackedFloatTexture;
|
|
327
|
-
glyphs: VectorGlyphInfo[];
|
|
328
|
-
planeBounds: BoundingBox;
|
|
329
|
-
}
|
|
330
297
|
export interface TextLayoutData {
|
|
331
298
|
lines: LineInfo[];
|
|
332
299
|
scaledLineHeight: number;
|
|
@@ -403,6 +370,8 @@ export interface TextOptions {
|
|
|
403
370
|
geometryOptimization?: GeometryOptimizationOptions;
|
|
404
371
|
layout?: LayoutOptions;
|
|
405
372
|
color?: [number, number, number] | ColorOptions;
|
|
373
|
+
/** Enable rotated RGSS-4 adaptive supersampling (4 samples per pixel). Takes effect when the GLSL rendering path is active. */
|
|
374
|
+
adaptiveSupersampling?: boolean;
|
|
406
375
|
}
|
|
407
376
|
export interface HyphenationPatternsMap {
|
|
408
377
|
[language: string]: HyphenationTrieNode;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { Text as TextCore } from '
|
|
2
|
-
import type { TextOptions, VectorGlyphInfo, LoadedFont, TextQueryOptions, TextRange } from '
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
1
|
+
import { Text as TextCore } from '../../core/Text';
|
|
2
|
+
import type { TextOptions, VectorGlyphInfo, LoadedFont, TextQueryOptions, TextRange } from '../../core/types';
|
|
3
|
+
import type { BoundingBox } from '../../utils/vectors';
|
|
4
|
+
import type { SlugGPUData } from '../slug/types';
|
|
5
|
+
import type { HyphenationTrieNode } from '../../hyphenation';
|
|
5
6
|
export interface VectorTextResult {
|
|
7
|
+
gpuData: SlugGPUData;
|
|
6
8
|
glyphs: VectorGlyphInfo[];
|
|
7
|
-
|
|
9
|
+
planeBounds: BoundingBox;
|
|
8
10
|
query(options: TextQueryOptions): TextRange[];
|
|
9
11
|
getLoadedFont(): LoadedFont | undefined;
|
|
10
12
|
measureTextWidth(text: string, letterSpacing?: number): number;
|
|
@@ -23,5 +25,4 @@ export declare class Text {
|
|
|
23
25
|
}
|
|
24
26
|
export type { TextOptions, VectorTextResult as TextGeometryInfo, VectorGlyphInfo, LoadedFont };
|
|
25
27
|
export type { HyphenationTrieNode };
|
|
26
|
-
export {
|
|
27
|
-
export type { VectorGeometryData, VectorGlyphAttributes, GlyphRange, VectorContour, LoopBlinnInput, LoopBlinnGlyphInput, QuadraticSegment } from './LoopBlinnGeometry';
|
|
28
|
+
export type { SlugGPUData } from '../slug/types';
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import type { TextOptions, VectorGlyphInfo, LoadedFont, TextQueryOptions, TextRange } from '../core/types';
|
|
2
|
+
import type { BoundingBox } from '../utils/vectors';
|
|
3
|
+
import type { SlugGPUData } from './slug/types';
|
|
4
|
+
import type { HyphenationTrieNode } from '../hyphenation';
|
|
5
|
+
import * as THREE from 'three';
|
|
6
|
+
export interface VectorTextResult {
|
|
7
|
+
group: THREE.Group;
|
|
8
|
+
mesh: THREE.Mesh;
|
|
9
|
+
gpuData: SlugGPUData;
|
|
10
|
+
glyphs: VectorGlyphInfo[];
|
|
11
|
+
planeBounds: BoundingBox;
|
|
12
|
+
query(options: TextQueryOptions): TextRange[];
|
|
13
|
+
getLoadedFont(): LoadedFont | undefined;
|
|
14
|
+
measureTextWidth(text: string, letterSpacing?: number): number;
|
|
15
|
+
update(options: Partial<TextOptions>): Promise<VectorTextResult>;
|
|
16
|
+
dispose(): void;
|
|
17
17
|
}
|
|
18
18
|
export declare class Text {
|
|
19
19
|
static setHarfBuzzPath: typeof import("..").Text.setHarfBuzzPath;
|
|
@@ -23,13 +23,10 @@ export declare class Text {
|
|
|
23
23
|
static preloadPatterns: typeof import("..").Text.preloadPatterns;
|
|
24
24
|
static setMaxFontCacheMemoryMB: typeof import("..").Text.setMaxFontCacheMemoryMB;
|
|
25
25
|
static enableWoff2: typeof import("..").Text.enableWoff2;
|
|
26
|
-
static create(options:
|
|
26
|
+
static create(options: TextOptions): Promise<VectorTextResult>;
|
|
27
27
|
}
|
|
28
|
-
export {
|
|
29
|
-
export type {
|
|
30
|
-
export
|
|
31
|
-
export {
|
|
32
|
-
export type {
|
|
33
|
-
export type { VectorGeometryData, VectorGlyphAttributes, GlyphRange, VectorContour, LoopBlinnInput, LoopBlinnGlyphInput, QuadraticSegment } from './LoopBlinnGeometry';
|
|
34
|
-
export type { VectorGlyphInfo, LoadedFont } from '../core/types';
|
|
35
|
-
export type { HyphenationTrieNode } from '../hyphenation';
|
|
28
|
+
export type { TextOptions, VectorTextResult as TextGeometryInfo, VectorGlyphInfo, LoadedFont };
|
|
29
|
+
export type { HyphenationTrieNode };
|
|
30
|
+
export { createSlugGLSLMesh } from './slug/slugGLSL';
|
|
31
|
+
export type { SlugGLSLMesh, SlugGLSLMeshOptions } from './slug/slugGLSL';
|
|
32
|
+
export type { SlugGPUData } from './slug/types';
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
-
import { Text as VectorText, type
|
|
3
|
-
export interface TextProps extends Omit<
|
|
2
|
+
import { Text as VectorText, type VectorTextResult, type TextOptions } from './index';
|
|
3
|
+
export interface TextProps extends Omit<TextOptions, 'text' | 'color'> {
|
|
4
4
|
children: string;
|
|
5
5
|
font: string | ArrayBuffer;
|
|
6
6
|
fillColor?: THREE.ColorRepresentation;
|
|
7
7
|
position?: [number, number, number];
|
|
8
8
|
rotation?: [number, number, number];
|
|
9
9
|
scale?: [number, number, number];
|
|
10
|
-
|
|
10
|
+
positionNode?: any;
|
|
11
|
+
onLoad?: (result: VectorTextResult) => void;
|
|
11
12
|
onError?: (error: Error) => void;
|
|
12
13
|
}
|
|
13
14
|
export declare const Text: import("react").ForwardRefExoticComponent<TextProps & import("react").RefAttributes<THREE.Group<THREE.Object3DEventMap>>> & {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { QuadCurve, SlugVec2 } from './types';
|
|
2
|
+
export declare function lineToQuadratic(p0: SlugVec2, p1: SlugVec2): QuadCurve;
|
|
3
|
+
export declare function cubicToQuadratics(p0: SlugVec2, p1: SlugVec2, p2: SlugVec2, p3: SlugVec2, options?: {
|
|
4
|
+
maxError?: number;
|
|
5
|
+
maxDepth?: number;
|
|
6
|
+
}): QuadCurve[];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { packSlugData } from './SlugPacker';
|
|
2
|
+
export { lineToQuadratic, cubicToQuadratics } from './curveUtils';
|
|
3
|
+
export { unpackSlugVertices } from './unpackVertices';
|
|
4
|
+
export { vertexShaderGLSL300, fragmentShaderGLSL300, vertexShaderWGSL, fragmentShaderWGSL } from './shaderStrings';
|
|
5
|
+
export type { QuadCurve, SlugVec2, SlugShape, SlugPackedTexture, SlugGPUData, SlugPackOptions } from './types';
|
|
6
|
+
export type { SlugVertexArrays } from './unpackVertices';
|
|
7
|
+
export { createSlugTSLMesh } from './slugTSL';
|
|
8
|
+
export type { SlugTSLMesh } from './slugTSL';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import type { SlugGPUData } from './types';
|
|
3
|
+
export interface SlugGLSLMeshOptions {
|
|
4
|
+
color?: {
|
|
5
|
+
r: number;
|
|
6
|
+
g: number;
|
|
7
|
+
b: number;
|
|
8
|
+
};
|
|
9
|
+
animationDeclarations?: string;
|
|
10
|
+
animationBody?: string;
|
|
11
|
+
uniforms?: Record<string, THREE.IUniform>;
|
|
12
|
+
adaptiveSupersampling?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface SlugGLSLMesh {
|
|
15
|
+
mesh: THREE.Mesh;
|
|
16
|
+
uniforms: Record<string, THREE.IUniform>;
|
|
17
|
+
setOffset(x: number, y: number, z?: number): void;
|
|
18
|
+
setColor(r: number, g: number, b: number): void;
|
|
19
|
+
dispose(): void;
|
|
20
|
+
}
|
|
21
|
+
export declare function createSlugGLSLMesh(gpuData: SlugGPUData, options?: SlugGLSLMeshOptions): SlugGLSLMesh;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import type { SlugGPUData } from './types';
|
|
3
|
+
export interface SlugTSLMesh {
|
|
4
|
+
mesh: THREE.Mesh;
|
|
5
|
+
setOffset(x: number, y: number, z?: number): void;
|
|
6
|
+
setColor(r: number, g: number, b: number): void;
|
|
7
|
+
dispose(): void;
|
|
8
|
+
}
|
|
9
|
+
export declare function createSlugTSLMesh(gpuData: SlugGPUData, color?: {
|
|
10
|
+
r: number;
|
|
11
|
+
g: number;
|
|
12
|
+
b: number;
|
|
13
|
+
}): SlugTSLMesh;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface QuadCurve {
|
|
2
|
+
p1: [number, number];
|
|
3
|
+
p2: [number, number];
|
|
4
|
+
p3: [number, number];
|
|
5
|
+
}
|
|
6
|
+
export type SlugVec2 = [number, number];
|
|
7
|
+
export interface SlugShape {
|
|
8
|
+
curves: QuadCurve[];
|
|
9
|
+
bounds: [number, number, number, number];
|
|
10
|
+
}
|
|
11
|
+
export interface SlugPackedTexture {
|
|
12
|
+
data: Float32Array | Uint32Array;
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
}
|
|
16
|
+
export interface SlugGPUData {
|
|
17
|
+
curveTexture: SlugPackedTexture & {
|
|
18
|
+
data: Float32Array;
|
|
19
|
+
};
|
|
20
|
+
bandTexture: SlugPackedTexture & {
|
|
21
|
+
data: Uint32Array;
|
|
22
|
+
};
|
|
23
|
+
vertices: Float32Array;
|
|
24
|
+
indices: Uint16Array;
|
|
25
|
+
shapeCount: number;
|
|
26
|
+
}
|
|
27
|
+
export interface SlugPackOptions {
|
|
28
|
+
bandCount?: number;
|
|
29
|
+
evenOdd?: boolean;
|
|
30
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SlugGPUData } from './types';
|
|
2
|
+
export interface SlugVertexArrays {
|
|
3
|
+
positions: Float32Array;
|
|
4
|
+
texcoords: Float32Array;
|
|
5
|
+
bandings: Float32Array;
|
|
6
|
+
glyphData: Float32Array;
|
|
7
|
+
colors: Float32Array;
|
|
8
|
+
glyphCenters: Float32Array;
|
|
9
|
+
glyphIndices: Float32Array;
|
|
10
|
+
}
|
|
11
|
+
export declare function unpackSlugVertices(gpuData: SlugGPUData): SlugVertexArrays;
|