three-text 0.2.18 → 0.3.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.
@@ -19,6 +19,8 @@ function convertToThree(result) {
19
19
  geometry.setAttribute('glyphCenter', new three.Float32BufferAttribute(result.glyphAttributes.glyphCenter, 3));
20
20
  geometry.setAttribute('glyphIndex', new three.Float32BufferAttribute(result.glyphAttributes.glyphIndex, 1));
21
21
  geometry.setAttribute('glyphLineIndex', new three.Float32BufferAttribute(result.glyphAttributes.glyphLineIndex, 1));
22
+ geometry.setAttribute('glyphProgress', new three.Float32BufferAttribute(result.glyphAttributes.glyphProgress, 1));
23
+ geometry.setAttribute('glyphBaselineY', new three.Float32BufferAttribute(result.glyphAttributes.glyphBaselineY, 1));
22
24
  }
23
25
  geometry.computeBoundingBox();
24
26
  // Return Three.js specific interface with utility methods
@@ -31,7 +33,7 @@ function convertToThree(result) {
31
33
  coloredRanges: result.coloredRanges,
32
34
  // Pass through utility methods from core
33
35
  getLoadedFont: result.getLoadedFont,
34
- getCacheStatistics: result.getCacheStatistics,
36
+ getCacheSize: result.getCacheSize,
35
37
  clearCache: result.clearCache,
36
38
  measureTextWidth: result.measureTextWidth,
37
39
  update: async (newOptions) => {
@@ -47,6 +49,7 @@ class Text {
47
49
  static { this.init = Text$1.Text.init; }
48
50
  static { this.registerPattern = Text$1.Text.registerPattern; }
49
51
  static { this.preloadPatterns = Text$1.Text.preloadPatterns; }
52
+ static { this.setMaxFontCacheMemoryMB = Text$1.Text.setMaxFontCacheMemoryMB; }
50
53
  // Main API - wraps core result in BufferGeometry
51
54
  static async create(options) {
52
55
  const coreResult = await Text$1.Text.create(options);
@@ -13,7 +13,7 @@ interface HyphenationTrieNode {
13
13
  interface ThreeTextGeometryInfo extends Omit<TextGeometryInfo, 'vertices' | 'normals' | 'indices' | 'colors' | 'glyphAttributes'> {
14
14
  geometry: BufferGeometry;
15
15
  getLoadedFont(): LoadedFont | undefined;
16
- getCacheStatistics(): any;
16
+ getCacheSize(): number;
17
17
  clearCache(): void;
18
18
  measureTextWidth(text: string, letterSpacing?: number): number;
19
19
  update(options: Partial<TextOptions>): Promise<ThreeTextGeometryInfo>;
@@ -24,6 +24,7 @@ declare class Text {
24
24
  static init: typeof Text$1.init;
25
25
  static registerPattern: typeof Text$1.registerPattern;
26
26
  static preloadPatterns: typeof Text$1.preloadPatterns;
27
+ static setMaxFontCacheMemoryMB: typeof Text$1.setMaxFontCacheMemoryMB;
27
28
  static create(options: TextOptions): Promise<ThreeTextGeometryInfo>;
28
29
  }
29
30
 
@@ -17,6 +17,8 @@ function convertToThree(result) {
17
17
  geometry.setAttribute('glyphCenter', new Float32BufferAttribute(result.glyphAttributes.glyphCenter, 3));
18
18
  geometry.setAttribute('glyphIndex', new Float32BufferAttribute(result.glyphAttributes.glyphIndex, 1));
19
19
  geometry.setAttribute('glyphLineIndex', new Float32BufferAttribute(result.glyphAttributes.glyphLineIndex, 1));
20
+ geometry.setAttribute('glyphProgress', new Float32BufferAttribute(result.glyphAttributes.glyphProgress, 1));
21
+ geometry.setAttribute('glyphBaselineY', new Float32BufferAttribute(result.glyphAttributes.glyphBaselineY, 1));
20
22
  }
21
23
  geometry.computeBoundingBox();
22
24
  // Return Three.js specific interface with utility methods
@@ -29,7 +31,7 @@ function convertToThree(result) {
29
31
  coloredRanges: result.coloredRanges,
30
32
  // Pass through utility methods from core
31
33
  getLoadedFont: result.getLoadedFont,
32
- getCacheStatistics: result.getCacheStatistics,
34
+ getCacheSize: result.getCacheSize,
33
35
  clearCache: result.clearCache,
34
36
  measureTextWidth: result.measureTextWidth,
35
37
  update: async (newOptions) => {
@@ -45,6 +47,7 @@ class Text {
45
47
  static { this.init = Text$1.init; }
46
48
  static { this.registerPattern = Text$1.registerPattern; }
47
49
  static { this.preloadPatterns = Text$1.preloadPatterns; }
50
+ static { this.setMaxFontCacheMemoryMB = Text$1.setMaxFontCacheMemoryMB; }
48
51
  // Main API - wraps core result in BufferGeometry
49
52
  static async create(options) {
50
53
  const coreResult = await Text$1.create(options);
@@ -3,7 +3,7 @@
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var react = require('react');
5
5
  var THREE = require('three');
6
- var index = require('./index');
6
+ var index = require('./index.cjs');
7
7
 
8
8
  function _interopNamespaceDefault(e) {
9
9
  var n = Object.create(null);
@@ -142,6 +142,7 @@ const Text = Object.assign(Text$1, {
142
142
  init: index.Text.init,
143
143
  registerPattern: index.Text.registerPattern,
144
144
  preloadPatterns: index.Text.preloadPatterns,
145
+ setMaxFontCacheMemoryMB: index.Text.setMaxFontCacheMemoryMB,
145
146
  create: index.Text.create
146
147
  });
147
148
 
@@ -9,6 +9,10 @@ interface HyphenationTrieNode {
9
9
  };
10
10
  }
11
11
 
12
+ interface CacheStats {
13
+ size: number;
14
+ }
15
+
12
16
  interface BoundingBox {
13
17
  min: {
14
18
  x: number;
@@ -174,6 +178,8 @@ interface TextGeometryInfo {
174
178
  glyphCenter: Float32Array;
175
179
  glyphIndex: Float32Array;
176
180
  glyphLineIndex: Float32Array;
181
+ glyphProgress: Float32Array;
182
+ glyphBaselineY: Float32Array;
177
183
  };
178
184
  glyphs: GlyphGeometryInfo[];
179
185
  planeBounds: BoundingBox;
@@ -183,13 +189,16 @@ interface TextGeometryInfo {
183
189
  pointsRemovedByVisvalingam: number;
184
190
  pointsRemovedByColinear: number;
185
191
  originalPointCount: number;
186
- };
192
+ } & Partial<CacheStats & {
193
+ hitRate: number;
194
+ memoryUsageMB: number;
195
+ }>;
187
196
  query(options: TextQueryOptions): TextRange[];
188
197
  coloredRanges?: ColoredRange[];
189
198
  }
190
199
  interface TextHandle extends TextGeometryInfo {
191
200
  getLoadedFont(): LoadedFont | undefined;
192
- getCacheStatistics(): any;
201
+ getCacheSize(): number;
193
202
  clearCache(): void;
194
203
  measureTextWidth(text: string, letterSpacing?: number): number;
195
204
  update(options: Partial<TextOptions>): Promise<TextHandle>;
@@ -228,12 +237,12 @@ interface ColoredRange {
228
237
  }
229
238
  interface TextOptions {
230
239
  text: string;
231
- font?: string | ArrayBuffer;
240
+ font: string | ArrayBuffer;
232
241
  size?: number;
233
242
  depth?: number;
234
243
  lineHeight?: number;
235
244
  letterSpacing?: number;
236
- separateGlyphsWithAttributes?: boolean;
245
+ perGlyphAttributes?: boolean;
237
246
  fontVariations?: {
238
247
  [key: string]: number;
239
248
  };
@@ -329,28 +338,16 @@ declare class Text$1 {
329
338
  getFontMetrics(): FontMetrics;
330
339
  static preloadPatterns(languages: string[], patternsPath?: string): Promise<void>;
331
340
  static registerPattern(language: string, pattern: HyphenationTrieNode): void;
332
- static clearFontCache(): void;
333
341
  static setMaxFontCacheMemoryMB(limitMB: number): void;
334
342
  getLoadedFont(): LoadedFont | undefined;
335
343
  measureTextWidth(text: string, letterSpacing?: number): number;
336
- getCacheStatistics(): (CacheStats & {
337
- hitRate: number;
338
- memoryUsageMB: number;
339
- }) | null;
344
+ getCacheSize(): number;
340
345
  clearCache(): void;
341
346
  private createGlyphAttributes;
342
347
  private resetHelpers;
343
348
  destroy(): void;
344
349
  }
345
350
 
346
- interface CacheStats {
347
- hits: number;
348
- misses: number;
349
- evictions: number;
350
- size: number;
351
- memoryUsage: number;
352
- }
353
-
354
351
  interface ThreeTextProps extends Omit<TextOptions$1, 'text'> {
355
352
  children: string;
356
353
  font: string | ArrayBuffer;
@@ -369,6 +366,7 @@ declare const Text: react.ForwardRefExoticComponent<ThreeTextProps & react.RefAt
369
366
  init: typeof Text$1.init;
370
367
  registerPattern: typeof Text$1.registerPattern;
371
368
  preloadPatterns: typeof Text$1.preloadPatterns;
369
+ setMaxFontCacheMemoryMB: typeof Text$1.setMaxFontCacheMemoryMB;
372
370
  create: typeof Text$2.create;
373
371
  };
374
372
 
@@ -1,7 +1,7 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { forwardRef, useState, useRef, useMemo, useEffect } from 'react';
3
3
  import * as THREE from 'three';
4
- import { Text as Text$2 } from './index';
4
+ import { Text as Text$2 } from './index.js';
5
5
 
6
6
  function deepEqual(a, b) {
7
7
  if (a === b)
@@ -121,6 +121,7 @@ const Text = Object.assign(Text$1, {
121
121
  init: Text$2.init,
122
122
  registerPattern: Text$2.registerPattern,
123
123
  preloadPatterns: Text$2.preloadPatterns,
124
+ setMaxFontCacheMemoryMB: Text$2.setMaxFontCacheMemoryMB,
124
125
  create: Text$2.create
125
126
  });
126
127
 
@@ -43,14 +43,10 @@ export declare class Text {
43
43
  getFontMetrics(): FontMetrics;
44
44
  static preloadPatterns(languages: string[], patternsPath?: string): Promise<void>;
45
45
  static registerPattern(language: string, pattern: HyphenationTrieNode): void;
46
- static clearFontCache(): void;
47
46
  static setMaxFontCacheMemoryMB(limitMB: number): void;
48
47
  getLoadedFont(): LoadedFont | undefined;
49
48
  measureTextWidth(text: string, letterSpacing?: number): number;
50
- getCacheStatistics(): (import("..").CacheStats & {
51
- hitRate: number;
52
- memoryUsageMB: number;
53
- }) | null;
49
+ getCacheSize(): number;
54
50
  clearCache(): void;
55
51
  private createGlyphAttributes;
56
52
  private resetHelpers;
@@ -1,6 +1,6 @@
1
1
  import { GlyphGeometryInfo, LoadedFont, GlyphCluster, GlyphData } from '../types';
2
2
  import { CurveFidelityConfig, GeometryOptimizationOptions } from '../types';
3
- import { LRUCache } from '../../utils/LRUCache';
3
+ import { Cache } from '../../utils/Cache';
4
4
  export interface InstancedTextGeometry {
5
5
  vertices: Float32Array;
6
6
  normals: Float32Array;
@@ -35,14 +35,14 @@ export declare class GlyphGeometryBuilder {
35
35
  private contourCache;
36
36
  private clusteringCache;
37
37
  private emptyGlyphs;
38
- constructor(cache: LRUCache<string, GlyphData>, loadedFont: LoadedFont);
38
+ constructor(cache: Cache<string, GlyphData>, loadedFont: LoadedFont);
39
39
  getOptimizationStats(): import("../geometry/PathOptimizer").OptimizationStats;
40
40
  setCurveFidelityConfig(config?: CurveFidelityConfig): void;
41
41
  setGeometryOptimization(options?: GeometryOptimizationOptions): void;
42
42
  setFontId(fontId: string): void;
43
43
  private updateCacheKeyPrefix;
44
44
  private getGeometryConfigSignature;
45
- buildInstancedGeometry(clustersByLine: GlyphCluster[][], depth: number, removeOverlaps: boolean, isCFF: boolean, separateGlyphs?: boolean, coloredTextIndices?: Set<number>): InstancedTextGeometry;
45
+ buildInstancedGeometry(clustersByLine: GlyphCluster[][], depth: number, removeOverlaps: boolean, isCFF: boolean, scale: number, separateGlyphs?: boolean, coloredTextIndices?: Set<number>): InstancedTextGeometry;
46
46
  private getClusterKey;
47
47
  private createGlyphInfo;
48
48
  private getContoursForGlyph;
@@ -50,9 +50,6 @@ export declare class GlyphGeometryBuilder {
50
50
  private extrudeAndPackage;
51
51
  private tessellateGlyph;
52
52
  private updatePlaneBounds;
53
- getCacheStats(): import("../../utils/LRUCache").CacheStats & {
54
- hitRate: number;
55
- memoryUsageMB: number;
56
- };
53
+ getCacheStats(): import("../../utils/Cache").CacheStats;
57
54
  clearCache(): void;
58
55
  }
@@ -1,12 +1,11 @@
1
- import { LRUCache } from '../../utils/LRUCache';
1
+ import { Cache } from '../../utils/Cache';
2
2
  import type { GlyphData, GlyphContours } from '../types';
3
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, {
4
+ export declare const globalGlyphCache: Cache<string, GlyphData>;
5
+ export declare function createGlyphCache(): Cache<string, GlyphData>;
6
+ export declare const globalContourCache: Cache<string, GlyphContours>;
7
+ export declare const globalWordCache: Cache<string, GlyphData>;
8
+ export declare const globalClusteringCache: Cache<string, {
10
9
  glyphIds: number[];
11
10
  groups: number[][];
12
11
  }>;
@@ -6,6 +6,5 @@ export interface ExtrusionResult {
6
6
  }
7
7
  export declare class Extruder {
8
8
  constructor();
9
- private packEdge;
10
9
  extrude(geometry: ProcessedGeometry, depth: number | undefined, unitsPerEm: number): ExtrusionResult;
11
10
  }
@@ -31,8 +31,5 @@ export declare class TextShaper {
31
31
  private calculateSpaceAdjustment;
32
32
  private calculateCJKAdjustment;
33
33
  clearCache(): void;
34
- getCacheStats(): import("../..").CacheStats & {
35
- hitRate: number;
36
- memoryUsageMB: number;
37
- };
34
+ getCacheStats(): import("../..").CacheStats;
38
35
  }
@@ -1,4 +1,5 @@
1
1
  import type { HyphenationTrieNode } from '../hyphenation';
2
+ import type { CacheStats } from '../utils/Cache';
2
3
  import type { Vec2, Vec3, BoundingBox } from './vectors';
3
4
  export type { HyphenationTrieNode };
4
5
  export interface Path {
@@ -240,6 +241,8 @@ export interface TextGeometryInfo {
240
241
  glyphCenter: Float32Array;
241
242
  glyphIndex: Float32Array;
242
243
  glyphLineIndex: Float32Array;
244
+ glyphProgress: Float32Array;
245
+ glyphBaselineY: Float32Array;
243
246
  };
244
247
  glyphs: GlyphGeometryInfo[];
245
248
  planeBounds: BoundingBox;
@@ -249,13 +252,16 @@ export interface TextGeometryInfo {
249
252
  pointsRemovedByVisvalingam: number;
250
253
  pointsRemovedByColinear: number;
251
254
  originalPointCount: number;
252
- };
255
+ } & Partial<CacheStats & {
256
+ hitRate: number;
257
+ memoryUsageMB: number;
258
+ }>;
253
259
  query(options: TextQueryOptions): TextRange[];
254
260
  coloredRanges?: ColoredRange[];
255
261
  }
256
262
  export interface TextHandle extends TextGeometryInfo {
257
263
  getLoadedFont(): LoadedFont | undefined;
258
- getCacheStatistics(): any;
264
+ getCacheSize(): number;
259
265
  clearCache(): void;
260
266
  measureTextWidth(text: string, letterSpacing?: number): number;
261
267
  update(options: Partial<TextOptions>): Promise<TextHandle>;
@@ -294,12 +300,12 @@ export interface ColoredRange {
294
300
  }
295
301
  export interface TextOptions {
296
302
  text: string;
297
- font?: string | ArrayBuffer;
303
+ font: string | ArrayBuffer;
298
304
  size?: number;
299
305
  depth?: number;
300
306
  lineHeight?: number;
301
307
  letterSpacing?: number;
302
- separateGlyphsWithAttributes?: boolean;
308
+ perGlyphAttributes?: boolean;
303
309
  fontVariations?: {
304
310
  [key: string]: number;
305
311
  };
@@ -2,6 +2,6 @@ export { Text } from './core/Text';
2
2
  export { DEFAULT_CURVE_FIDELITY } from './core/geometry/Polygonizer';
3
3
  export { FontMetadataExtractor } from './core/font/FontMetadata';
4
4
  export { globalGlyphCache, createGlyphCache } from './core/cache/sharedCaches';
5
- export type { CacheStats } from './utils/LRUCache';
5
+ export type { CacheStats } from './utils/Cache';
6
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';
@@ -5,7 +5,7 @@ import type { HyphenationTrieNode } from '../hyphenation';
5
5
  export interface ThreeTextGeometryInfo extends Omit<CoreTextGeometryInfo, 'vertices' | 'normals' | 'indices' | 'colors' | 'glyphAttributes'> {
6
6
  geometry: BufferGeometry;
7
7
  getLoadedFont(): LoadedFont | undefined;
8
- getCacheStatistics(): any;
8
+ getCacheSize(): number;
9
9
  clearCache(): void;
10
10
  measureTextWidth(text: string, letterSpacing?: number): number;
11
11
  update(options: Partial<TextOptions>): Promise<ThreeTextGeometryInfo>;
@@ -16,6 +16,7 @@ export declare class Text {
16
16
  static init: typeof TextCore.init;
17
17
  static registerPattern: typeof TextCore.registerPattern;
18
18
  static preloadPatterns: typeof TextCore.preloadPatterns;
19
+ static setMaxFontCacheMemoryMB: typeof TextCore.setMaxFontCacheMemoryMB;
19
20
  static create(options: TextOptions): Promise<ThreeTextGeometryInfo>;
20
21
  }
21
22
  export type { TextOptions, ThreeTextGeometryInfo as TextGeometryInfo, LoadedFont };
@@ -6,5 +6,6 @@ export declare const Text: import("react").ForwardRefExoticComponent<import("./T
6
6
  init: typeof import("..").Text.init;
7
7
  registerPattern: typeof import("..").Text.registerPattern;
8
8
  preloadPatterns: typeof import("..").Text.preloadPatterns;
9
+ setMaxFontCacheMemoryMB: typeof import("..").Text.setMaxFontCacheMemoryMB;
9
10
  create: typeof ThreeTextCore.create;
10
11
  };
@@ -0,0 +1,14 @@
1
+ export interface CacheStats {
2
+ size: number;
3
+ }
4
+ export declare class Cache<K, V> {
5
+ private cache;
6
+ get(key: K): V | undefined;
7
+ has(key: K): boolean;
8
+ set(key: K, value: V): void;
9
+ delete(key: K): boolean;
10
+ clear(): void;
11
+ get size(): number;
12
+ keys(): K[];
13
+ getStats(): CacheStats;
14
+ }
@@ -8,6 +8,8 @@ export interface WebGLBufferSet {
8
8
  glyphCenter?: WebGLBuffer;
9
9
  glyphIndex?: WebGLBuffer;
10
10
  glyphLineIndex?: WebGLBuffer;
11
+ glyphProgress?: WebGLBuffer;
12
+ glyphBaselineY?: WebGLBuffer;
11
13
  };
12
14
  attributes: {
13
15
  position: {
@@ -40,6 +42,16 @@ export interface WebGLBufferSet {
40
42
  type: GLenum;
41
43
  normalized: boolean;
42
44
  };
45
+ glyphProgress?: {
46
+ size: number;
47
+ type: GLenum;
48
+ normalized: boolean;
49
+ };
50
+ glyphBaselineY?: {
51
+ size: number;
52
+ type: GLenum;
53
+ normalized: boolean;
54
+ };
43
55
  };
44
56
  drawCount: number;
45
57
  mode: GLenum;
@@ -4,10 +4,20 @@ export interface WebGPUBufferSet {
4
4
  vertex: GPUBuffer;
5
5
  color?: GPUBuffer;
6
6
  indices: GPUBuffer;
7
+ glyphCenter?: GPUBuffer;
8
+ glyphIndex?: GPUBuffer;
9
+ glyphLineIndex?: GPUBuffer;
10
+ glyphProgress?: GPUBuffer;
11
+ glyphBaselineY?: GPUBuffer;
7
12
  };
8
13
  layout: {
9
14
  vertex: GPUVertexBufferLayout;
10
15
  color?: GPUVertexBufferLayout;
16
+ glyphCenter?: GPUVertexBufferLayout;
17
+ glyphIndex?: GPUVertexBufferLayout;
18
+ glyphLineIndex?: GPUVertexBufferLayout;
19
+ glyphProgress?: GPUVertexBufferLayout;
20
+ glyphBaselineY?: GPUVertexBufferLayout;
11
21
  };
12
22
  indexCount: number;
13
23
  indexFormat: GPUIndexFormat;
@@ -63,6 +63,20 @@ function createWebGLBuffers(gl, textGeometry) {
63
63
  gl.bufferData(gl.ARRAY_BUFFER, glyphAttributes.glyphLineIndex, gl.STATIC_DRAW);
64
64
  buffers.glyphLineIndex = glyphLineIndexBuffer;
65
65
  attributes.glyphLineIndex = { size: 1, type: gl.FLOAT, normalized: false };
66
+ const glyphProgressBuffer = gl.createBuffer();
67
+ if (!glyphProgressBuffer)
68
+ throw new Error('Failed to create glyphProgress buffer');
69
+ gl.bindBuffer(gl.ARRAY_BUFFER, glyphProgressBuffer);
70
+ gl.bufferData(gl.ARRAY_BUFFER, glyphAttributes.glyphProgress, gl.STATIC_DRAW);
71
+ buffers.glyphProgress = glyphProgressBuffer;
72
+ attributes.glyphProgress = { size: 1, type: gl.FLOAT, normalized: false };
73
+ const glyphBaselineYBuffer = gl.createBuffer();
74
+ if (!glyphBaselineYBuffer)
75
+ throw new Error('Failed to create glyphBaselineY buffer');
76
+ gl.bindBuffer(gl.ARRAY_BUFFER, glyphBaselineYBuffer);
77
+ gl.bufferData(gl.ARRAY_BUFFER, glyphAttributes.glyphBaselineY, gl.STATIC_DRAW);
78
+ buffers.glyphBaselineY = glyphBaselineYBuffer;
79
+ attributes.glyphBaselineY = { size: 1, type: gl.FLOAT, normalized: false };
66
80
  }
67
81
  return {
68
82
  buffers,
@@ -81,6 +95,10 @@ function createWebGLBuffers(gl, textGeometry) {
81
95
  gl.deleteBuffer(buffers.glyphIndex);
82
96
  if (buffers.glyphLineIndex)
83
97
  gl.deleteBuffer(buffers.glyphLineIndex);
98
+ if (buffers.glyphProgress)
99
+ gl.deleteBuffer(buffers.glyphProgress);
100
+ if (buffers.glyphBaselineY)
101
+ gl.deleteBuffer(buffers.glyphBaselineY);
84
102
  }
85
103
  };
86
104
  }
@@ -9,6 +9,8 @@ interface WebGLBufferSet {
9
9
  glyphCenter?: WebGLBuffer;
10
10
  glyphIndex?: WebGLBuffer;
11
11
  glyphLineIndex?: WebGLBuffer;
12
+ glyphProgress?: WebGLBuffer;
13
+ glyphBaselineY?: WebGLBuffer;
12
14
  };
13
15
  attributes: {
14
16
  position: {
@@ -41,6 +43,16 @@ interface WebGLBufferSet {
41
43
  type: GLenum;
42
44
  normalized: boolean;
43
45
  };
46
+ glyphProgress?: {
47
+ size: number;
48
+ type: GLenum;
49
+ normalized: boolean;
50
+ };
51
+ glyphBaselineY?: {
52
+ size: number;
53
+ type: GLenum;
54
+ normalized: boolean;
55
+ };
44
56
  };
45
57
  drawCount: number;
46
58
  mode: GLenum;
@@ -61,6 +61,20 @@ function createWebGLBuffers(gl, textGeometry) {
61
61
  gl.bufferData(gl.ARRAY_BUFFER, glyphAttributes.glyphLineIndex, gl.STATIC_DRAW);
62
62
  buffers.glyphLineIndex = glyphLineIndexBuffer;
63
63
  attributes.glyphLineIndex = { size: 1, type: gl.FLOAT, normalized: false };
64
+ const glyphProgressBuffer = gl.createBuffer();
65
+ if (!glyphProgressBuffer)
66
+ throw new Error('Failed to create glyphProgress buffer');
67
+ gl.bindBuffer(gl.ARRAY_BUFFER, glyphProgressBuffer);
68
+ gl.bufferData(gl.ARRAY_BUFFER, glyphAttributes.glyphProgress, gl.STATIC_DRAW);
69
+ buffers.glyphProgress = glyphProgressBuffer;
70
+ attributes.glyphProgress = { size: 1, type: gl.FLOAT, normalized: false };
71
+ const glyphBaselineYBuffer = gl.createBuffer();
72
+ if (!glyphBaselineYBuffer)
73
+ throw new Error('Failed to create glyphBaselineY buffer');
74
+ gl.bindBuffer(gl.ARRAY_BUFFER, glyphBaselineYBuffer);
75
+ gl.bufferData(gl.ARRAY_BUFFER, glyphAttributes.glyphBaselineY, gl.STATIC_DRAW);
76
+ buffers.glyphBaselineY = glyphBaselineYBuffer;
77
+ attributes.glyphBaselineY = { size: 1, type: gl.FLOAT, normalized: false };
64
78
  }
65
79
  return {
66
80
  buffers,
@@ -79,6 +93,10 @@ function createWebGLBuffers(gl, textGeometry) {
79
93
  gl.deleteBuffer(buffers.glyphIndex);
80
94
  if (buffers.glyphLineIndex)
81
95
  gl.deleteBuffer(buffers.glyphLineIndex);
96
+ if (buffers.glyphProgress)
97
+ gl.deleteBuffer(buffers.glyphProgress);
98
+ if (buffers.glyphBaselineY)
99
+ gl.deleteBuffer(buffers.glyphBaselineY);
82
100
  }
83
101
  };
84
102
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  // WebGPU adapter - lightweight utility to create GPU buffers from core geometry
4
4
  function createWebGPUBuffers(device, textGeometry) {
5
- const { vertices, normals, indices, colors } = textGeometry;
5
+ const { vertices, normals, indices, colors, glyphAttributes } = textGeometry;
6
6
  const indexCount = indices.length;
7
7
  const indexFormat = indices instanceof Uint16Array ? 'uint16' : 'uint32';
8
8
  // Interleave position and normal data for better cache coherency
@@ -83,6 +83,75 @@ function createWebGPUBuffers(device, textGeometry) {
83
83
  buffers.color = colorBuffer;
84
84
  layout.color = colorLayout;
85
85
  }
86
+ // Optional glyph attribute buffers
87
+ let glyphCenterBuffer;
88
+ let glyphIndexBuffer;
89
+ let glyphLineIndexBuffer;
90
+ let glyphProgressBuffer;
91
+ let glyphBaselineYBuffer;
92
+ if (glyphAttributes) {
93
+ let nextShaderLocation = colors ? 3 : 2;
94
+ glyphCenterBuffer = device.createBuffer({
95
+ size: glyphAttributes.glyphCenter.byteLength,
96
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
97
+ mappedAtCreation: true
98
+ });
99
+ new Float32Array(glyphCenterBuffer.getMappedRange()).set(glyphAttributes.glyphCenter);
100
+ glyphCenterBuffer.unmap();
101
+ buffers.glyphCenter = glyphCenterBuffer;
102
+ layout.glyphCenter = {
103
+ arrayStride: 12,
104
+ attributes: [{ shaderLocation: nextShaderLocation++, offset: 0, format: 'float32x3' }]
105
+ };
106
+ glyphIndexBuffer = device.createBuffer({
107
+ size: glyphAttributes.glyphIndex.byteLength,
108
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
109
+ mappedAtCreation: true
110
+ });
111
+ new Float32Array(glyphIndexBuffer.getMappedRange()).set(glyphAttributes.glyphIndex);
112
+ glyphIndexBuffer.unmap();
113
+ buffers.glyphIndex = glyphIndexBuffer;
114
+ layout.glyphIndex = {
115
+ arrayStride: 4,
116
+ attributes: [{ shaderLocation: nextShaderLocation++, offset: 0, format: 'float32' }]
117
+ };
118
+ glyphLineIndexBuffer = device.createBuffer({
119
+ size: glyphAttributes.glyphLineIndex.byteLength,
120
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
121
+ mappedAtCreation: true
122
+ });
123
+ new Float32Array(glyphLineIndexBuffer.getMappedRange()).set(glyphAttributes.glyphLineIndex);
124
+ glyphLineIndexBuffer.unmap();
125
+ buffers.glyphLineIndex = glyphLineIndexBuffer;
126
+ layout.glyphLineIndex = {
127
+ arrayStride: 4,
128
+ attributes: [{ shaderLocation: nextShaderLocation++, offset: 0, format: 'float32' }]
129
+ };
130
+ glyphProgressBuffer = device.createBuffer({
131
+ size: glyphAttributes.glyphProgress.byteLength,
132
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
133
+ mappedAtCreation: true
134
+ });
135
+ new Float32Array(glyphProgressBuffer.getMappedRange()).set(glyphAttributes.glyphProgress);
136
+ glyphProgressBuffer.unmap();
137
+ buffers.glyphProgress = glyphProgressBuffer;
138
+ layout.glyphProgress = {
139
+ arrayStride: 4,
140
+ attributes: [{ shaderLocation: nextShaderLocation++, offset: 0, format: 'float32' }]
141
+ };
142
+ glyphBaselineYBuffer = device.createBuffer({
143
+ size: glyphAttributes.glyphBaselineY.byteLength,
144
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
145
+ mappedAtCreation: true
146
+ });
147
+ new Float32Array(glyphBaselineYBuffer.getMappedRange()).set(glyphAttributes.glyphBaselineY);
148
+ glyphBaselineYBuffer.unmap();
149
+ buffers.glyphBaselineY = glyphBaselineYBuffer;
150
+ layout.glyphBaselineY = {
151
+ arrayStride: 4,
152
+ attributes: [{ shaderLocation: nextShaderLocation++, offset: 0, format: 'float32' }]
153
+ };
154
+ }
86
155
  return {
87
156
  buffers,
88
157
  layout,
@@ -93,6 +162,16 @@ function createWebGPUBuffers(device, textGeometry) {
93
162
  indexBuffer.destroy();
94
163
  if (colorBuffer)
95
164
  colorBuffer.destroy();
165
+ if (glyphCenterBuffer)
166
+ glyphCenterBuffer.destroy();
167
+ if (glyphIndexBuffer)
168
+ glyphIndexBuffer.destroy();
169
+ if (glyphLineIndexBuffer)
170
+ glyphLineIndexBuffer.destroy();
171
+ if (glyphProgressBuffer)
172
+ glyphProgressBuffer.destroy();
173
+ if (glyphBaselineYBuffer)
174
+ glyphBaselineYBuffer.destroy();
96
175
  }
97
176
  };
98
177
  }
@@ -5,10 +5,20 @@ interface WebGPUBufferSet {
5
5
  vertex: GPUBuffer;
6
6
  color?: GPUBuffer;
7
7
  indices: GPUBuffer;
8
+ glyphCenter?: GPUBuffer;
9
+ glyphIndex?: GPUBuffer;
10
+ glyphLineIndex?: GPUBuffer;
11
+ glyphProgress?: GPUBuffer;
12
+ glyphBaselineY?: GPUBuffer;
8
13
  };
9
14
  layout: {
10
15
  vertex: GPUVertexBufferLayout;
11
16
  color?: GPUVertexBufferLayout;
17
+ glyphCenter?: GPUVertexBufferLayout;
18
+ glyphIndex?: GPUVertexBufferLayout;
19
+ glyphLineIndex?: GPUVertexBufferLayout;
20
+ glyphProgress?: GPUVertexBufferLayout;
21
+ glyphBaselineY?: GPUVertexBufferLayout;
12
22
  };
13
23
  indexCount: number;
14
24
  indexFormat: GPUIndexFormat;