three-text 0.2.12 → 0.2.14
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 +4 -4
- package/dist/index.cjs +904 -723
- package/dist/index.d.ts +88 -76
- package/dist/index.js +904 -724
- package/dist/index.min.cjs +861 -2
- package/dist/index.min.js +860 -2
- package/dist/index.umd.js +904 -723
- package/dist/index.umd.min.js +862 -2
- package/dist/three/react.cjs +44 -20
- package/dist/three/react.d.ts +36 -24
- package/dist/three/react.js +45 -21
- package/dist/types/core/Text.d.ts +14 -7
- package/dist/types/core/cache/GlyphGeometryBuilder.d.ts +14 -5
- package/dist/types/core/cache/sharedCaches.d.ts +12 -0
- package/dist/types/core/font/TableDirectory.d.ts +7 -0
- package/dist/types/core/font/constants.d.ts +0 -1
- package/dist/types/core/geometry/Extruder.d.ts +3 -6
- package/dist/types/core/layout/LineBreak.d.ts +2 -0
- package/dist/types/core/shaping/DrawCallbacks.d.ts +2 -0
- package/dist/types/core/shaping/TextShaper.d.ts +4 -1
- package/dist/types/core/types.d.ts +26 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/types/three/ThreeText.d.ts +3 -3
- package/dist/types/utils/LRUCache.d.ts +2 -2
- package/dist/types/webgpu/index.d.ts +1 -2
- package/dist/webgpu/index.cjs +3 -4
- package/dist/webgpu/index.d.ts +1 -2
- package/dist/webgpu/index.js +3 -4
- package/package.json +1 -1
- package/dist/types/core/cache/GlyphCache.d.ts +0 -50
package/dist/three/react.cjs
CHANGED
|
@@ -31,12 +31,24 @@ function deepEqual(a, b) {
|
|
|
31
31
|
return false;
|
|
32
32
|
if (typeof a !== 'object' || typeof b !== 'object')
|
|
33
33
|
return false;
|
|
34
|
+
// Arrays (common in options like color, byCharRange, etc.)
|
|
35
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
36
|
+
if (!Array.isArray(a) || !Array.isArray(b))
|
|
37
|
+
return false;
|
|
38
|
+
if (a.length !== b.length)
|
|
39
|
+
return false;
|
|
40
|
+
for (let i = 0; i < a.length; i++) {
|
|
41
|
+
if (!deepEqual(a[i], b[i]))
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
34
46
|
const keysA = Object.keys(a);
|
|
35
47
|
const keysB = Object.keys(b);
|
|
36
48
|
if (keysA.length !== keysB.length)
|
|
37
49
|
return false;
|
|
38
50
|
for (const key of keysA) {
|
|
39
|
-
if (!
|
|
51
|
+
if (!Object.prototype.hasOwnProperty.call(b, key))
|
|
40
52
|
return false;
|
|
41
53
|
if (!deepEqual(a[key], b[key]))
|
|
42
54
|
return false;
|
|
@@ -54,10 +66,14 @@ const Text$1 = react.forwardRef(function Text(props, ref) {
|
|
|
54
66
|
const { children, font, material, position = [0, 0, 0], rotation = [0, 0, 0], scale = [1, 1, 1], onLoad, onError, vertexColors = true, ...restOptions } = props;
|
|
55
67
|
const [geometry, setGeometry] = react.useState(null);
|
|
56
68
|
const [error, setError] = react.useState(null);
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
const geometryRef = react.useRef(null);
|
|
70
|
+
const defaultMaterial = react.useMemo(() => {
|
|
71
|
+
return new THREE__namespace.MeshBasicMaterial({
|
|
72
|
+
color: 0xffffff,
|
|
73
|
+
side: THREE__namespace.DoubleSide,
|
|
74
|
+
vertexColors
|
|
75
|
+
});
|
|
76
|
+
}, [vertexColors]);
|
|
61
77
|
const finalMaterial = material || defaultMaterial;
|
|
62
78
|
const memoizedTextOptions = useDeepCompareMemo(restOptions);
|
|
63
79
|
react.useEffect(() => {
|
|
@@ -70,13 +86,19 @@ const Text$1 = react.forwardRef(function Text(props, ref) {
|
|
|
70
86
|
const text = await index.Text.create({
|
|
71
87
|
text: children,
|
|
72
88
|
font,
|
|
73
|
-
...memoizedTextOptions
|
|
89
|
+
...memoizedTextOptions
|
|
74
90
|
});
|
|
75
|
-
if (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
91
|
+
if (cancelled) {
|
|
92
|
+
// If a newer render superseded this request, avoid leaking geometry
|
|
93
|
+
text.geometry.dispose();
|
|
94
|
+
return;
|
|
79
95
|
}
|
|
96
|
+
// Dispose previous geometry (if any) before swapping
|
|
97
|
+
geometryRef.current?.dispose();
|
|
98
|
+
geometryRef.current = text.geometry;
|
|
99
|
+
setGeometry(text.geometry);
|
|
100
|
+
if (onLoad)
|
|
101
|
+
onLoad(text.geometry, text);
|
|
80
102
|
}
|
|
81
103
|
catch (err) {
|
|
82
104
|
const error = err;
|
|
@@ -85,7 +107,7 @@ const Text$1 = react.forwardRef(function Text(props, ref) {
|
|
|
85
107
|
if (onError)
|
|
86
108
|
onError(error);
|
|
87
109
|
else
|
|
88
|
-
console.error(
|
|
110
|
+
console.error('ThreeText error:', error);
|
|
89
111
|
}
|
|
90
112
|
}
|
|
91
113
|
}
|
|
@@ -93,18 +115,20 @@ const Text$1 = react.forwardRef(function Text(props, ref) {
|
|
|
93
115
|
return () => {
|
|
94
116
|
cancelled = true;
|
|
95
117
|
};
|
|
96
|
-
}, [font, children, memoizedTextOptions, onLoad, onError
|
|
97
|
-
//
|
|
118
|
+
}, [font, children, memoizedTextOptions, onLoad, onError]);
|
|
119
|
+
// Cleanup geometry on unmount
|
|
98
120
|
react.useEffect(() => {
|
|
99
121
|
return () => {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
122
|
+
geometryRef.current?.dispose();
|
|
123
|
+
geometryRef.current = null;
|
|
124
|
+
};
|
|
125
|
+
}, []);
|
|
126
|
+
// Cleanup default material when it changes or on unmount
|
|
127
|
+
react.useEffect(() => {
|
|
128
|
+
return () => {
|
|
129
|
+
defaultMaterial.dispose();
|
|
106
130
|
};
|
|
107
|
-
}, [
|
|
131
|
+
}, [defaultMaterial]);
|
|
108
132
|
if (error || !geometry) {
|
|
109
133
|
return null;
|
|
110
134
|
}
|
package/dist/three/react.d.ts
CHANGED
|
@@ -2,6 +2,13 @@ import * as react from 'react';
|
|
|
2
2
|
import * as THREE from 'three';
|
|
3
3
|
import { TextOptions as TextOptions$1, ThreeTextGeometryInfo, Text as Text$2 } from './index';
|
|
4
4
|
|
|
5
|
+
interface HyphenationTrieNode {
|
|
6
|
+
patterns: number[] | null;
|
|
7
|
+
children: {
|
|
8
|
+
[char: string]: HyphenationTrieNode;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
5
12
|
interface BoundingBox {
|
|
6
13
|
min: {
|
|
7
14
|
x: number;
|
|
@@ -15,13 +22,6 @@ interface BoundingBox {
|
|
|
15
22
|
};
|
|
16
23
|
}
|
|
17
24
|
|
|
18
|
-
interface HyphenationTrieNode {
|
|
19
|
-
patterns: number[] | null;
|
|
20
|
-
children: {
|
|
21
|
-
[char: string]: HyphenationTrieNode;
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
25
|
type TextAlign = 'left' | 'center' | 'right' | 'justify';
|
|
26
26
|
type TextDirection = 'ltr' | 'rtl';
|
|
27
27
|
interface LoadedFont {
|
|
@@ -187,6 +187,13 @@ interface TextGeometryInfo {
|
|
|
187
187
|
query(options: TextQueryOptions): TextRange[];
|
|
188
188
|
coloredRanges?: ColoredRange[];
|
|
189
189
|
}
|
|
190
|
+
interface TextHandle extends TextGeometryInfo {
|
|
191
|
+
getLoadedFont(): LoadedFont | undefined;
|
|
192
|
+
getCacheStatistics(): any;
|
|
193
|
+
clearCache(): void;
|
|
194
|
+
measureTextWidth(text: string, letterSpacing?: number): number;
|
|
195
|
+
update(options: Partial<TextOptions>): Promise<TextHandle>;
|
|
196
|
+
}
|
|
190
197
|
interface ColorByRange {
|
|
191
198
|
start: number;
|
|
192
199
|
end: number;
|
|
@@ -279,16 +286,6 @@ interface LayoutOptions {
|
|
|
279
286
|
shortLineThreshold?: number;
|
|
280
287
|
}
|
|
281
288
|
|
|
282
|
-
interface GlyphCacheStats {
|
|
283
|
-
hits: number;
|
|
284
|
-
misses: number;
|
|
285
|
-
totalGlyphs: number;
|
|
286
|
-
uniqueGlyphs: number;
|
|
287
|
-
cacheSize: number;
|
|
288
|
-
saved: number;
|
|
289
|
-
memoryUsage: number;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
289
|
declare global {
|
|
293
290
|
interface Window {
|
|
294
291
|
hbjs?: any;
|
|
@@ -299,7 +296,10 @@ declare class Text$1 {
|
|
|
299
296
|
private static patternCache;
|
|
300
297
|
private static hbInitPromise;
|
|
301
298
|
private static fontCache;
|
|
299
|
+
private static fontCacheMemoryBytes;
|
|
300
|
+
private static maxFontCacheMemoryBytes;
|
|
302
301
|
private static fontIdCounter;
|
|
302
|
+
private static stableStringify;
|
|
303
303
|
private fontLoader;
|
|
304
304
|
private loadedFont?;
|
|
305
305
|
private currentFontId;
|
|
@@ -310,13 +310,12 @@ declare class Text$1 {
|
|
|
310
310
|
static setHarfBuzzPath(path: string): void;
|
|
311
311
|
static setHarfBuzzBuffer(wasmBuffer: ArrayBuffer): void;
|
|
312
312
|
static init(): Promise<HarfBuzzInstance>;
|
|
313
|
-
static create(options: TextOptions): Promise<
|
|
314
|
-
update: (options: Partial<TextOptions>) => Promise<TextGeometryInfo & Pick<Text$1, 'getLoadedFont' | 'getCacheStatistics' | 'clearCache' | 'measureTextWidth'> & {
|
|
315
|
-
update: (options: Partial<TextOptions>) => Promise<any>;
|
|
316
|
-
}>;
|
|
317
|
-
}>;
|
|
313
|
+
static create(options: TextOptions): Promise<TextHandle>;
|
|
318
314
|
private static resolveFont;
|
|
319
315
|
private static loadAndCacheFont;
|
|
316
|
+
private static trackFontCacheAdd;
|
|
317
|
+
private static trackFontCacheRemove;
|
|
318
|
+
private static enforceFontCacheMemoryLimit;
|
|
320
319
|
private static generateFontContentHash;
|
|
321
320
|
private setLoadedFont;
|
|
322
321
|
private loadFont;
|
|
@@ -330,16 +329,29 @@ declare class Text$1 {
|
|
|
330
329
|
getFontMetrics(): FontMetrics;
|
|
331
330
|
static preloadPatterns(languages: string[], patternsPath?: string): Promise<void>;
|
|
332
331
|
static registerPattern(language: string, pattern: HyphenationTrieNode): void;
|
|
332
|
+
static clearFontCache(): void;
|
|
333
|
+
static setMaxFontCacheMemoryMB(limitMB: number): void;
|
|
333
334
|
getLoadedFont(): LoadedFont | undefined;
|
|
334
335
|
measureTextWidth(text: string, letterSpacing?: number): number;
|
|
335
|
-
getCacheStatistics():
|
|
336
|
+
getCacheStatistics(): (CacheStats & {
|
|
337
|
+
hitRate: number;
|
|
338
|
+
memoryUsageMB: number;
|
|
339
|
+
}) | null;
|
|
336
340
|
clearCache(): void;
|
|
337
341
|
private createGlyphAttributes;
|
|
338
342
|
private resetHelpers;
|
|
339
343
|
destroy(): void;
|
|
340
344
|
}
|
|
341
345
|
|
|
342
|
-
interface
|
|
346
|
+
interface CacheStats {
|
|
347
|
+
hits: number;
|
|
348
|
+
misses: number;
|
|
349
|
+
evictions: number;
|
|
350
|
+
size: number;
|
|
351
|
+
memoryUsage: number;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
interface ThreeTextProps extends Omit<TextOptions$1, 'text'> {
|
|
343
355
|
children: string;
|
|
344
356
|
font: string | ArrayBuffer;
|
|
345
357
|
material?: THREE.Material;
|
package/dist/three/react.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { forwardRef, useState, useMemo, useEffect
|
|
2
|
+
import { forwardRef, useState, useRef, useMemo, useEffect } from 'react';
|
|
3
3
|
import * as THREE from 'three';
|
|
4
4
|
import { Text as Text$2 } from './index';
|
|
5
5
|
|
|
@@ -10,12 +10,24 @@ function deepEqual(a, b) {
|
|
|
10
10
|
return false;
|
|
11
11
|
if (typeof a !== 'object' || typeof b !== 'object')
|
|
12
12
|
return false;
|
|
13
|
+
// Arrays (common in options like color, byCharRange, etc.)
|
|
14
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
15
|
+
if (!Array.isArray(a) || !Array.isArray(b))
|
|
16
|
+
return false;
|
|
17
|
+
if (a.length !== b.length)
|
|
18
|
+
return false;
|
|
19
|
+
for (let i = 0; i < a.length; i++) {
|
|
20
|
+
if (!deepEqual(a[i], b[i]))
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
13
25
|
const keysA = Object.keys(a);
|
|
14
26
|
const keysB = Object.keys(b);
|
|
15
27
|
if (keysA.length !== keysB.length)
|
|
16
28
|
return false;
|
|
17
29
|
for (const key of keysA) {
|
|
18
|
-
if (!
|
|
30
|
+
if (!Object.prototype.hasOwnProperty.call(b, key))
|
|
19
31
|
return false;
|
|
20
32
|
if (!deepEqual(a[key], b[key]))
|
|
21
33
|
return false;
|
|
@@ -33,10 +45,14 @@ const Text$1 = forwardRef(function Text(props, ref) {
|
|
|
33
45
|
const { children, font, material, position = [0, 0, 0], rotation = [0, 0, 0], scale = [1, 1, 1], onLoad, onError, vertexColors = true, ...restOptions } = props;
|
|
34
46
|
const [geometry, setGeometry] = useState(null);
|
|
35
47
|
const [error, setError] = useState(null);
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
const geometryRef = useRef(null);
|
|
49
|
+
const defaultMaterial = useMemo(() => {
|
|
50
|
+
return new THREE.MeshBasicMaterial({
|
|
51
|
+
color: 0xffffff,
|
|
52
|
+
side: THREE.DoubleSide,
|
|
53
|
+
vertexColors
|
|
54
|
+
});
|
|
55
|
+
}, [vertexColors]);
|
|
40
56
|
const finalMaterial = material || defaultMaterial;
|
|
41
57
|
const memoizedTextOptions = useDeepCompareMemo(restOptions);
|
|
42
58
|
useEffect(() => {
|
|
@@ -49,13 +65,19 @@ const Text$1 = forwardRef(function Text(props, ref) {
|
|
|
49
65
|
const text = await Text$2.create({
|
|
50
66
|
text: children,
|
|
51
67
|
font,
|
|
52
|
-
...memoizedTextOptions
|
|
68
|
+
...memoizedTextOptions
|
|
53
69
|
});
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
70
|
+
if (cancelled) {
|
|
71
|
+
// If a newer render superseded this request, avoid leaking geometry
|
|
72
|
+
text.geometry.dispose();
|
|
73
|
+
return;
|
|
58
74
|
}
|
|
75
|
+
// Dispose previous geometry (if any) before swapping
|
|
76
|
+
geometryRef.current?.dispose();
|
|
77
|
+
geometryRef.current = text.geometry;
|
|
78
|
+
setGeometry(text.geometry);
|
|
79
|
+
if (onLoad)
|
|
80
|
+
onLoad(text.geometry, text);
|
|
59
81
|
}
|
|
60
82
|
catch (err) {
|
|
61
83
|
const error = err;
|
|
@@ -64,7 +86,7 @@ const Text$1 = forwardRef(function Text(props, ref) {
|
|
|
64
86
|
if (onError)
|
|
65
87
|
onError(error);
|
|
66
88
|
else
|
|
67
|
-
console.error(
|
|
89
|
+
console.error('ThreeText error:', error);
|
|
68
90
|
}
|
|
69
91
|
}
|
|
70
92
|
}
|
|
@@ -72,18 +94,20 @@ const Text$1 = forwardRef(function Text(props, ref) {
|
|
|
72
94
|
return () => {
|
|
73
95
|
cancelled = true;
|
|
74
96
|
};
|
|
75
|
-
}, [font, children, memoizedTextOptions, onLoad, onError
|
|
76
|
-
//
|
|
97
|
+
}, [font, children, memoizedTextOptions, onLoad, onError]);
|
|
98
|
+
// Cleanup geometry on unmount
|
|
77
99
|
useEffect(() => {
|
|
78
100
|
return () => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
101
|
+
geometryRef.current?.dispose();
|
|
102
|
+
geometryRef.current = null;
|
|
103
|
+
};
|
|
104
|
+
}, []);
|
|
105
|
+
// Cleanup default material when it changes or on unmount
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
return () => {
|
|
108
|
+
defaultMaterial.dispose();
|
|
85
109
|
};
|
|
86
|
-
}, [
|
|
110
|
+
}, [defaultMaterial]);
|
|
87
111
|
if (error || !geometry) {
|
|
88
112
|
return null;
|
|
89
113
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TextOptions,
|
|
1
|
+
import type { TextOptions, TextHandle, FontMetrics, LoadedFont, HarfBuzzInstance } from './types';
|
|
2
2
|
import type { HyphenationTrieNode } from '../hyphenation';
|
|
3
3
|
declare global {
|
|
4
4
|
interface Window {
|
|
@@ -10,7 +10,10 @@ export declare class Text {
|
|
|
10
10
|
private static patternCache;
|
|
11
11
|
private static hbInitPromise;
|
|
12
12
|
private static fontCache;
|
|
13
|
+
private static fontCacheMemoryBytes;
|
|
14
|
+
private static maxFontCacheMemoryBytes;
|
|
13
15
|
private static fontIdCounter;
|
|
16
|
+
private static stableStringify;
|
|
14
17
|
private fontLoader;
|
|
15
18
|
private loadedFont?;
|
|
16
19
|
private currentFontId;
|
|
@@ -21,13 +24,12 @@ export declare class Text {
|
|
|
21
24
|
static setHarfBuzzPath(path: string): void;
|
|
22
25
|
static setHarfBuzzBuffer(wasmBuffer: ArrayBuffer): void;
|
|
23
26
|
static init(): Promise<HarfBuzzInstance>;
|
|
24
|
-
static create(options: TextOptions): Promise<
|
|
25
|
-
update: (options: Partial<TextOptions>) => Promise<TextGeometryInfo & Pick<Text, 'getLoadedFont' | 'getCacheStatistics' | 'clearCache' | 'measureTextWidth'> & {
|
|
26
|
-
update: (options: Partial<TextOptions>) => Promise<any>;
|
|
27
|
-
}>;
|
|
28
|
-
}>;
|
|
27
|
+
static create(options: TextOptions): Promise<TextHandle>;
|
|
29
28
|
private static resolveFont;
|
|
30
29
|
private static loadAndCacheFont;
|
|
30
|
+
private static trackFontCacheAdd;
|
|
31
|
+
private static trackFontCacheRemove;
|
|
32
|
+
private static enforceFontCacheMemoryLimit;
|
|
31
33
|
private static generateFontContentHash;
|
|
32
34
|
private setLoadedFont;
|
|
33
35
|
private loadFont;
|
|
@@ -41,9 +43,14 @@ export declare class Text {
|
|
|
41
43
|
getFontMetrics(): FontMetrics;
|
|
42
44
|
static preloadPatterns(languages: string[], patternsPath?: string): Promise<void>;
|
|
43
45
|
static registerPattern(language: string, pattern: HyphenationTrieNode): void;
|
|
46
|
+
static clearFontCache(): void;
|
|
47
|
+
static setMaxFontCacheMemoryMB(limitMB: number): void;
|
|
44
48
|
getLoadedFont(): LoadedFont | undefined;
|
|
45
49
|
measureTextWidth(text: string, letterSpacing?: number): number;
|
|
46
|
-
getCacheStatistics(): import("
|
|
50
|
+
getCacheStatistics(): (import("..").CacheStats & {
|
|
51
|
+
hitRate: number;
|
|
52
|
+
memoryUsageMB: number;
|
|
53
|
+
}) | null;
|
|
47
54
|
clearCache(): void;
|
|
48
55
|
private createGlyphAttributes;
|
|
49
56
|
private resetHelpers;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { GlyphGeometryInfo, LoadedFont, GlyphCluster } from '../types';
|
|
1
|
+
import { GlyphGeometryInfo, LoadedFont, GlyphCluster, GlyphData } from '../types';
|
|
3
2
|
import { CurveFidelityConfig, GeometryOptimizationOptions } from '../types';
|
|
3
|
+
import { LRUCache } from '../../utils/LRUCache';
|
|
4
4
|
export interface InstancedTextGeometry {
|
|
5
5
|
vertices: Float32Array;
|
|
6
6
|
normals: Float32Array;
|
|
@@ -24,25 +24,34 @@ export declare class GlyphGeometryBuilder {
|
|
|
24
24
|
private tessellator;
|
|
25
25
|
private extruder;
|
|
26
26
|
private fontId;
|
|
27
|
+
private cacheKeyPrefix;
|
|
28
|
+
private curveFidelityConfig?;
|
|
29
|
+
private geometryOptimizationOptions?;
|
|
27
30
|
private clusterer;
|
|
28
31
|
private collector;
|
|
29
32
|
private drawCallbacks;
|
|
30
33
|
private loadedFont;
|
|
31
34
|
private wordCache;
|
|
32
35
|
private contourCache;
|
|
33
|
-
|
|
36
|
+
private clusteringCache;
|
|
37
|
+
constructor(cache: LRUCache<string, GlyphData>, loadedFont: LoadedFont);
|
|
34
38
|
getOptimizationStats(): import("../geometry/PathOptimizer").OptimizationStats;
|
|
35
39
|
setCurveFidelityConfig(config?: CurveFidelityConfig): void;
|
|
36
40
|
setGeometryOptimization(options?: GeometryOptimizationOptions): void;
|
|
37
41
|
setFontId(fontId: string): void;
|
|
42
|
+
private updateCacheKeyPrefix;
|
|
43
|
+
private getGeometryConfigSignature;
|
|
38
44
|
buildInstancedGeometry(clustersByLine: GlyphCluster[][], depth: number, removeOverlaps: boolean, isCFF: boolean, separateGlyphs?: boolean, coloredTextIndices?: Set<number>): InstancedTextGeometry;
|
|
39
|
-
private
|
|
45
|
+
private getClusterKey;
|
|
40
46
|
private createGlyphInfo;
|
|
41
47
|
private getContoursForGlyph;
|
|
42
48
|
private tessellateGlyphCluster;
|
|
43
49
|
private extrudeAndPackage;
|
|
44
50
|
private tessellateGlyph;
|
|
45
51
|
private updatePlaneBounds;
|
|
46
|
-
getCacheStats(): import("
|
|
52
|
+
getCacheStats(): import("../../utils/LRUCache").CacheStats & {
|
|
53
|
+
hitRate: number;
|
|
54
|
+
memoryUsageMB: number;
|
|
55
|
+
};
|
|
47
56
|
clearCache(): void;
|
|
48
57
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { LRUCache } from '../../utils/LRUCache';
|
|
2
|
+
import type { GlyphData, GlyphContours } from '../types';
|
|
3
|
+
export declare function getGlyphCacheKey(fontId: string, glyphId: number, depth: number, removeOverlaps: boolean): string;
|
|
4
|
+
export declare function calculateGlyphMemoryUsage(glyph: GlyphData): number;
|
|
5
|
+
export declare const globalGlyphCache: LRUCache<string, GlyphData>;
|
|
6
|
+
export declare function createGlyphCache(maxCacheSizeMB?: number): LRUCache<string, GlyphData>;
|
|
7
|
+
export declare const globalContourCache: LRUCache<string, GlyphContours>;
|
|
8
|
+
export declare const globalWordCache: LRUCache<string, GlyphData>;
|
|
9
|
+
export declare const globalClusteringCache: LRUCache<string, {
|
|
10
|
+
glyphIds: number[];
|
|
11
|
+
groups: number[][];
|
|
12
|
+
}>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export declare const FONT_SIGNATURE_TRUE_TYPE = 65536;
|
|
2
2
|
export declare const FONT_SIGNATURE_OPEN_TYPE_CFF = 1330926671;
|
|
3
|
-
export declare const FONT_SIGNATURE_TRUE_TYPE_COLLECTION = 1953784678;
|
|
4
3
|
export declare const FONT_SIGNATURE_WOFF = 2001684038;
|
|
5
4
|
export declare const FONT_SIGNATURE_WOFF2 = 2001684018;
|
|
6
5
|
export declare const TABLE_TAG_HEAD = 1751474532;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import type { ProcessedGeometry } from '../types';
|
|
2
2
|
export interface ExtrusionResult {
|
|
3
|
-
vertices:
|
|
4
|
-
normals:
|
|
5
|
-
indices:
|
|
3
|
+
vertices: Float32Array;
|
|
4
|
+
normals: Float32Array;
|
|
5
|
+
indices: Uint32Array;
|
|
6
6
|
}
|
|
7
7
|
export declare class Extruder {
|
|
8
8
|
constructor();
|
|
9
9
|
extrude(geometry: ProcessedGeometry, depth: number | undefined, unitsPerEm: number): ExtrusionResult;
|
|
10
|
-
private addFlatFaces;
|
|
11
|
-
private addFrontAndBackFaces;
|
|
12
|
-
private addSideWalls;
|
|
13
10
|
}
|
|
@@ -50,6 +50,7 @@ export interface LineBreakOptions {
|
|
|
50
50
|
respectExistingBreaks?: boolean;
|
|
51
51
|
hyphenationPatterns?: HyphenationPatternsMap;
|
|
52
52
|
unitsPerEm?: number;
|
|
53
|
+
letterSpacing?: number;
|
|
53
54
|
tolerance?: number;
|
|
54
55
|
pretolerance?: number;
|
|
55
56
|
emergencyStretch?: number;
|
|
@@ -73,6 +74,7 @@ interface LineBreakContext {
|
|
|
73
74
|
exHyphenPenalty: number;
|
|
74
75
|
currentAlign: TextAlign;
|
|
75
76
|
unitsPerEm?: number;
|
|
77
|
+
letterSpacingFU?: number;
|
|
76
78
|
}
|
|
77
79
|
export declare class LineBreak {
|
|
78
80
|
private static badness;
|
|
@@ -11,7 +11,9 @@ export declare class DrawCallbackHandler {
|
|
|
11
11
|
private position;
|
|
12
12
|
setPosition(x: number, y: number): void;
|
|
13
13
|
updatePosition(dx: number, dy: number): void;
|
|
14
|
+
setCollector(collector: GlyphContourCollector): void;
|
|
14
15
|
createDrawFuncs(font: LoadedFont, collector: GlyphContourCollector): void;
|
|
15
16
|
getDrawFuncsPtr(): number;
|
|
16
17
|
destroy(font: LoadedFont): void;
|
|
17
18
|
}
|
|
19
|
+
export declare function getSharedDrawCallbackHandler(font: LoadedFont): DrawCallbackHandler;
|
|
@@ -31,5 +31,8 @@ export declare class TextShaper {
|
|
|
31
31
|
private calculateSpaceAdjustment;
|
|
32
32
|
private calculateCJKAdjustment;
|
|
33
33
|
clearCache(): void;
|
|
34
|
-
getCacheStats(): import("../..").
|
|
34
|
+
getCacheStats(): import("../..").CacheStats & {
|
|
35
|
+
hitRate: number;
|
|
36
|
+
memoryUsageMB: number;
|
|
37
|
+
};
|
|
35
38
|
}
|
|
@@ -163,6 +163,25 @@ export interface ProcessedGeometry {
|
|
|
163
163
|
triangles: Triangles;
|
|
164
164
|
contours: number[][];
|
|
165
165
|
}
|
|
166
|
+
export interface GlyphData {
|
|
167
|
+
geometry: ProcessedGeometry;
|
|
168
|
+
vertices: Float32Array;
|
|
169
|
+
normals: Float32Array;
|
|
170
|
+
indices: Uint32Array;
|
|
171
|
+
bounds: {
|
|
172
|
+
min: {
|
|
173
|
+
x: number;
|
|
174
|
+
y: number;
|
|
175
|
+
z: number;
|
|
176
|
+
};
|
|
177
|
+
max: {
|
|
178
|
+
x: number;
|
|
179
|
+
y: number;
|
|
180
|
+
z: number;
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
useCount: number;
|
|
184
|
+
}
|
|
166
185
|
export interface PathInfo {
|
|
167
186
|
start: number;
|
|
168
187
|
count: number;
|
|
@@ -234,6 +253,13 @@ export interface TextGeometryInfo {
|
|
|
234
253
|
query(options: TextQueryOptions): TextRange[];
|
|
235
254
|
coloredRanges?: ColoredRange[];
|
|
236
255
|
}
|
|
256
|
+
export interface TextHandle extends TextGeometryInfo {
|
|
257
|
+
getLoadedFont(): LoadedFont | undefined;
|
|
258
|
+
getCacheStatistics(): any;
|
|
259
|
+
clearCache(): void;
|
|
260
|
+
measureTextWidth(text: string, letterSpacing?: number): number;
|
|
261
|
+
update(options: Partial<TextOptions>): Promise<TextHandle>;
|
|
262
|
+
}
|
|
237
263
|
export interface ColorByRange {
|
|
238
264
|
start: number;
|
|
239
265
|
end: number;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { Text } from './core/Text';
|
|
2
2
|
export { DEFAULT_CURVE_FIDELITY } from './core/geometry/Polygonizer';
|
|
3
3
|
export { FontMetadataExtractor } from './core/font/FontMetadata';
|
|
4
|
-
export { globalGlyphCache } from './core/cache/
|
|
5
|
-
export type {
|
|
6
|
-
export type { TextAlign, TextDirection, LineInfo, LoadedFont, HarfBuzzModule, HarfBuzzAPI, HarfBuzzBlob, HarfBuzzFace, HarfBuzzFont, HarfBuzzBuffer, HarfBuzzInstance, VariationAxis, ExtractedMetrics, VerticalMetrics, FontMetrics, ProcessedGeometry, Triangles, GlyphGeometryInfo, TextGeometryInfo, TextOptions, ColorOptions, ColorByRange, ColoredRange, PathInfo, HyphenationPatternsMap, CurveFidelityConfig, LayoutOptions, GeometryOptimizationOptions, TextRange, TextQueryOptions } from './core/types';
|
|
4
|
+
export { globalGlyphCache, createGlyphCache } from './core/cache/sharedCaches';
|
|
5
|
+
export type { CacheStats } from './utils/LRUCache';
|
|
6
|
+
export type { TextAlign, TextDirection, LineInfo, LoadedFont, HarfBuzzModule, HarfBuzzAPI, HarfBuzzBlob, HarfBuzzFace, HarfBuzzFont, HarfBuzzBuffer, HarfBuzzInstance, VariationAxis, ExtractedMetrics, VerticalMetrics, FontMetrics, ProcessedGeometry, Triangles, GlyphData, GlyphGeometryInfo, TextGeometryInfo, TextHandle, TextOptions, ColorOptions, ColorByRange, ColoredRange, PathInfo, HyphenationPatternsMap, CurveFidelityConfig, LayoutOptions, GeometryOptimizationOptions, TextRange, TextQueryOptions } from './core/types';
|
|
7
7
|
export type { HyphenationTrieNode } from './hyphenation';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as THREE from
|
|
2
|
-
import type { TextOptions, ThreeTextGeometryInfo as TextGeometryInfo } from
|
|
3
|
-
export interface ThreeTextProps extends Omit<TextOptions,
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import type { TextOptions, ThreeTextGeometryInfo as TextGeometryInfo } from './index';
|
|
3
|
+
export interface ThreeTextProps extends Omit<TextOptions, 'text'> {
|
|
4
4
|
children: string;
|
|
5
5
|
font: string | ArrayBuffer;
|
|
6
6
|
material?: THREE.Material;
|
|
@@ -4,7 +4,7 @@ export interface LRUCacheOptions<K, V> {
|
|
|
4
4
|
calculateSize?: (value: V) => number;
|
|
5
5
|
onEvict?: (key: K, value: V) => void;
|
|
6
6
|
}
|
|
7
|
-
export interface
|
|
7
|
+
export interface CacheStats {
|
|
8
8
|
hits: number;
|
|
9
9
|
misses: number;
|
|
10
10
|
evictions: number;
|
|
@@ -23,7 +23,7 @@ export declare class LRUCache<K, V> {
|
|
|
23
23
|
set(key: K, value: V): void;
|
|
24
24
|
delete(key: K): boolean;
|
|
25
25
|
clear(): void;
|
|
26
|
-
getStats():
|
|
26
|
+
getStats(): CacheStats & {
|
|
27
27
|
hitRate: number;
|
|
28
28
|
memoryUsageMB: number;
|
|
29
29
|
};
|
|
@@ -9,8 +9,7 @@ export interface WebGPUBufferSet {
|
|
|
9
9
|
vertex: GPUVertexBufferLayout;
|
|
10
10
|
color?: GPUVertexBufferLayout;
|
|
11
11
|
};
|
|
12
|
-
|
|
13
|
-
vertexCount: number;
|
|
12
|
+
indexCount: number;
|
|
14
13
|
dispose(): void;
|
|
15
14
|
}
|
|
16
15
|
export declare function createWebGPUBuffers(device: GPUDevice, textGeometry: TextGeometryInfo): WebGPUBufferSet;
|
package/dist/webgpu/index.cjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// WebGPU adapter - lightweight utility to create GPU buffers from core geometry
|
|
4
4
|
function createWebGPUBuffers(device, textGeometry) {
|
|
5
5
|
const { vertices, normals, indices, colors } = textGeometry;
|
|
6
|
-
const
|
|
6
|
+
const indexCount = indices.length;
|
|
7
7
|
// Interleave position and normal data for better cache coherency
|
|
8
8
|
// Layout: [px, py, pz, nx, ny, nz, px, py, pz, nx, ny, nz, ...]
|
|
9
9
|
const interleavedData = new Float32Array((vertices.length / 3) * 6);
|
|
@@ -27,7 +27,7 @@ function createWebGPUBuffers(device, textGeometry) {
|
|
|
27
27
|
});
|
|
28
28
|
new Float32Array(vertexBuffer.getMappedRange()).set(interleavedData);
|
|
29
29
|
vertexBuffer.unmap();
|
|
30
|
-
// Create index buffer
|
|
30
|
+
// Create index buffer
|
|
31
31
|
const indexBuffer = device.createBuffer({
|
|
32
32
|
size: indices.byteLength,
|
|
33
33
|
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
|
|
@@ -85,8 +85,7 @@ function createWebGPUBuffers(device, textGeometry) {
|
|
|
85
85
|
return {
|
|
86
86
|
buffers,
|
|
87
87
|
layout,
|
|
88
|
-
|
|
89
|
-
vertexCount,
|
|
88
|
+
indexCount,
|
|
90
89
|
dispose() {
|
|
91
90
|
vertexBuffer.destroy();
|
|
92
91
|
indexBuffer.destroy();
|
package/dist/webgpu/index.d.ts
CHANGED
|
@@ -10,8 +10,7 @@ interface WebGPUBufferSet {
|
|
|
10
10
|
vertex: GPUVertexBufferLayout;
|
|
11
11
|
color?: GPUVertexBufferLayout;
|
|
12
12
|
};
|
|
13
|
-
|
|
14
|
-
vertexCount: number;
|
|
13
|
+
indexCount: number;
|
|
15
14
|
dispose(): void;
|
|
16
15
|
}
|
|
17
16
|
declare function createWebGPUBuffers(device: GPUDevice, textGeometry: TextGeometryInfo): WebGPUBufferSet;
|