meshwriter-cudu 3.0.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.md +11 -0
- package/README.md +349 -0
- package/dist/fonts/comic-sans.d.ts +1105 -0
- package/dist/fonts/helvetica.d.ts +1208 -0
- package/dist/fonts/hiruko-pro.d.ts +658 -0
- package/dist/fonts/jura.d.ts +750 -0
- package/dist/fonts/webgl-dings.d.ts +109 -0
- package/dist/index.d.ts +295 -0
- package/dist/meshwriter.cjs.js +2645 -0
- package/dist/meshwriter.cjs.js.map +1 -0
- package/dist/meshwriter.esm.js +2606 -0
- package/dist/meshwriter.esm.js.map +1 -0
- package/dist/meshwriter.min.js +2 -0
- package/dist/meshwriter.min.js.map +1 -0
- package/dist/meshwriter.umd.js +7146 -0
- package/dist/meshwriter.umd.js.map +1 -0
- package/dist/src/babylonImports.d.ts +11 -0
- package/dist/src/bakedFontLoader.d.ts +43 -0
- package/dist/src/colorContrast.d.ts +117 -0
- package/dist/src/csg.d.ts +55 -0
- package/dist/src/curves.d.ts +20 -0
- package/dist/src/fogPlugin.d.ts +32 -0
- package/dist/src/fontCompression.d.ts +12 -0
- package/dist/src/fontRegistry.d.ts +54 -0
- package/dist/src/index.d.ts +47 -0
- package/dist/src/letterMesh.d.ts +46 -0
- package/dist/src/material.d.ts +34 -0
- package/dist/src/meshSplitter.d.ts +10 -0
- package/dist/src/meshwriter.d.ts +46 -0
- package/dist/src/sps.d.ts +27 -0
- package/dist/src/umd-entry.d.ts +3 -0
- package/dist/src/utils.d.ts +12 -0
- package/dist/src/variableFontCache.d.ts +56 -0
- package/dist/src/variableFontConverter.d.ts +21 -0
- package/dist/src/variableFontLoader.d.ts +99 -0
- package/fonts/Figure1.png +0 -0
- package/fonts/LICENSE-OFL.txt +93 -0
- package/fonts/README.md +174 -0
- package/fonts/atkinson-hyperlegible-next.d.ts +8 -0
- package/fonts/atkinson-hyperlegible-next.js +6576 -0
- package/fonts/atkinson-hyperlegible.js +3668 -0
- package/fonts/baked/atkinson-hyperlegible-next-200.json +1 -0
- package/fonts/baked/atkinson-hyperlegible-next-250.json +1 -0
- package/fonts/baked/atkinson-hyperlegible-next-300.json +1 -0
- package/fonts/baked/atkinson-hyperlegible-next-350.json +1 -0
- package/fonts/baked/atkinson-hyperlegible-next-400.json +1 -0
- package/fonts/baked/atkinson-hyperlegible-next-450.json +1 -0
- package/fonts/baked/atkinson-hyperlegible-next-500.json +1 -0
- package/fonts/baked/atkinson-hyperlegible-next-550.json +1 -0
- package/fonts/baked/atkinson-hyperlegible-next-600.json +1 -0
- package/fonts/baked/atkinson-hyperlegible-next-650.json +1 -0
- package/fonts/baked/atkinson-hyperlegible-next-700.json +1 -0
- package/fonts/baked/atkinson-hyperlegible-next-750.json +1 -0
- package/fonts/baked/atkinson-hyperlegible-next-800.json +1 -0
- package/fonts/baked/manifest.json +41 -0
- package/fonts/comic-sans.js +1532 -0
- package/fonts/helvetica.js +1695 -0
- package/fonts/hiruko-pro.js +838 -0
- package/fonts/index.js +16 -0
- package/fonts/jura.js +994 -0
- package/fonts/variable/atkinson-hyperlegible-next-variable.ttf +0 -0
- package/fonts/webgl-dings.js +113 -0
- package/package.json +76 -0
- package/src/babylonImports.js +29 -0
- package/src/bakedFontLoader.js +125 -0
- package/src/colorContrast.js +528 -0
- package/src/csg.js +220 -0
- package/src/curves.js +67 -0
- package/src/fogPlugin.js +98 -0
- package/src/fontCompression.js +141 -0
- package/src/fontRegistry.js +98 -0
- package/src/globals.d.ts +20 -0
- package/src/index.js +136 -0
- package/src/letterMesh.js +417 -0
- package/src/material.js +103 -0
- package/src/meshSplitter.js +337 -0
- package/src/meshwriter.js +303 -0
- package/src/sps.js +106 -0
- package/src/types.d.ts +551 -0
- package/src/umd-entry.js +130 -0
- package/src/utils.js +57 -0
package/src/sps.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MeshWriter SPS (Solid Particle System) Helpers
|
|
3
|
+
* Converts letter meshes into an efficient SPS
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { SolidParticleSystem, Mesh } from './babylonImports.js';
|
|
7
|
+
|
|
8
|
+
/** @typedef {import('@babylonjs/core/scene').Scene} Scene */
|
|
9
|
+
/** @typedef {import('@babylonjs/core/Materials/material').Material} Material */
|
|
10
|
+
/** @typedef {import('@babylonjs/core/Meshes/mesh').Mesh} BabylonMesh */
|
|
11
|
+
/** @typedef {(any[] & { faceMeshes?: BabylonMesh[] })} MeshCollection */
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {[SolidParticleSystem | undefined, BabylonMesh | undefined] & {
|
|
14
|
+
* face: [SolidParticleSystem | undefined, BabylonMesh | undefined];
|
|
15
|
+
* }} SPSCombo
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Create an SPS from letter meshes
|
|
20
|
+
* @param {Scene} scene - Babylon scene
|
|
21
|
+
* @param {MeshCollection} meshesAndBoxes - [meshes, boxes, origins] with optional face geometry
|
|
22
|
+
* @param {Material} material - Material to apply to SPS mesh
|
|
23
|
+
* @returns {SPSCombo} - Combined SPS + emissive face SPS
|
|
24
|
+
*/
|
|
25
|
+
export function makeSPS(scene, meshesAndBoxes, material) {
|
|
26
|
+
const rimMeshes = meshesAndBoxes[0] || [];
|
|
27
|
+
const faceMeshes = meshesAndBoxes.faceMeshes || [];
|
|
28
|
+
const lettersOrigins = meshesAndBoxes[2] || [];
|
|
29
|
+
|
|
30
|
+
const rim = buildSystem("sps_rim", rimMeshes, lettersOrigins, scene, material);
|
|
31
|
+
|
|
32
|
+
// Use Mesh.MergeMeshes for face instead of SPS - SPS has issues with face geometry
|
|
33
|
+
const face = buildFaceMesh("sps_face", faceMeshes, lettersOrigins, scene);
|
|
34
|
+
|
|
35
|
+
/** @type {SPSCombo} */
|
|
36
|
+
const combo = /** @type {any} */ ([rim.sps, rim.mesh]);
|
|
37
|
+
combo.face = [undefined, face.mesh]; // No SPS for face, just merged mesh
|
|
38
|
+
return combo;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Build face mesh using Mesh.MergeMeshes instead of SPS
|
|
43
|
+
* @param {string} name - Mesh name
|
|
44
|
+
* @param {BabylonMesh[]} meshes - Face meshes to merge
|
|
45
|
+
* @param {Array} lettersOrigins - Letter origin positions
|
|
46
|
+
* @param {Scene} scene - Babylon scene
|
|
47
|
+
* @returns {{ mesh: BabylonMesh | undefined }}
|
|
48
|
+
*/
|
|
49
|
+
function buildFaceMesh(name, meshes, lettersOrigins, scene) {
|
|
50
|
+
const validMeshes = meshes.filter(m => m != null);
|
|
51
|
+
if (!validMeshes.length) {
|
|
52
|
+
return { mesh: undefined };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Position each mesh according to letter origins before merging
|
|
56
|
+
validMeshes.forEach((mesh, ix) => {
|
|
57
|
+
if (lettersOrigins[ix]) {
|
|
58
|
+
mesh.position.x = lettersOrigins[ix][0] + lettersOrigins[ix][1];
|
|
59
|
+
mesh.position.z = lettersOrigins[ix][2];
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Merge all face meshes into one
|
|
64
|
+
const merged = Mesh.MergeMeshes(validMeshes, true, true, undefined, false, true);
|
|
65
|
+
if (merged) {
|
|
66
|
+
merged.name = name;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { mesh: merged };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function buildSystem(name, meshes, lettersOrigins, scene, material) {
|
|
73
|
+
// Pre-filter null meshes to avoid repeated null checks in hot loop
|
|
74
|
+
const validMeshes = meshes
|
|
75
|
+
.map((mesh, ix) => mesh ? { mesh, origins: lettersOrigins[ix] } : null)
|
|
76
|
+
.filter(item => item !== null);
|
|
77
|
+
|
|
78
|
+
if (!validMeshes.length) {
|
|
79
|
+
return { sps: undefined, mesh: undefined };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const sps = new SolidParticleSystem(name, scene, {});
|
|
83
|
+
validMeshes.forEach(function(item) {
|
|
84
|
+
sps.addShape(item.mesh, 1, {
|
|
85
|
+
positionFunction: makePositionParticle(item.origins)
|
|
86
|
+
});
|
|
87
|
+
item.mesh.dispose();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const spsMesh = sps.buildMesh();
|
|
91
|
+
|
|
92
|
+
if (spsMesh && material) {
|
|
93
|
+
spsMesh.material = material;
|
|
94
|
+
}
|
|
95
|
+
sps.setParticles();
|
|
96
|
+
|
|
97
|
+
return { sps, mesh: spsMesh };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function makePositionParticle(letterOrigins) {
|
|
101
|
+
return function positionParticle(particle) {
|
|
102
|
+
if (!letterOrigins) return;
|
|
103
|
+
particle.position.x = letterOrigins[0] + letterOrigins[1];
|
|
104
|
+
particle.position.z = letterOrigins[2];
|
|
105
|
+
};
|
|
106
|
+
}
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MeshWriter Type Declarations
|
|
3
|
+
* Provides TypeScript types for MeshWriter library
|
|
4
|
+
*
|
|
5
|
+
* Requires: @babylonjs/core (peer dependency)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Scene } from '@babylonjs/core/scene';
|
|
9
|
+
import type { Mesh } from '@babylonjs/core/Meshes/mesh';
|
|
10
|
+
import type { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
|
|
11
|
+
import type { Material } from '@babylonjs/core/Materials/material';
|
|
12
|
+
import type { MaterialPluginBase } from '@babylonjs/core/Materials/materialPluginBase';
|
|
13
|
+
import type { SolidParticleSystem } from '@babylonjs/core/Particles/solidParticleSystem';
|
|
14
|
+
import type { Vector2 } from '@babylonjs/core/Maths/math.vector';
|
|
15
|
+
|
|
16
|
+
// ============ Options & Configuration Types ============
|
|
17
|
+
|
|
18
|
+
/** Position configuration for text placement */
|
|
19
|
+
export interface MeshWriterPosition {
|
|
20
|
+
x?: number;
|
|
21
|
+
y?: number;
|
|
22
|
+
z?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Color configuration for material properties */
|
|
26
|
+
export interface MeshWriterColors {
|
|
27
|
+
diffuse?: string;
|
|
28
|
+
specular?: string;
|
|
29
|
+
ambient?: string;
|
|
30
|
+
emissive?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Options for creating text with MeshWriter */
|
|
34
|
+
export interface MeshWriterOptions {
|
|
35
|
+
/** Position of the text in 3D space */
|
|
36
|
+
position?: MeshWriterPosition;
|
|
37
|
+
/** Material color properties */
|
|
38
|
+
colors?: MeshWriterColors;
|
|
39
|
+
/** Font family name (must be registered first) */
|
|
40
|
+
'font-family'?: string;
|
|
41
|
+
/** Text anchor point */
|
|
42
|
+
anchor?: 'left' | 'right' | 'center';
|
|
43
|
+
/** Height of letters in world units */
|
|
44
|
+
'letter-height'?: number;
|
|
45
|
+
/** Thickness (depth) of letters in world units */
|
|
46
|
+
'letter-thickness'?: number;
|
|
47
|
+
/** Emissive color as hex string (e.g., "#FF0000") */
|
|
48
|
+
color?: string;
|
|
49
|
+
/** Material alpha/transparency (0-1) */
|
|
50
|
+
alpha?: number;
|
|
51
|
+
/** If true, disables lighting (only emissive color shows) - gives self-lit appearance */
|
|
52
|
+
'emissive-only'?: boolean;
|
|
53
|
+
/** If true, the material is affected by scene fog (default: true) */
|
|
54
|
+
'fog-enabled'?: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Babylon namespace subset used for CSG injection */
|
|
58
|
+
export interface BabylonCSGNamespace {
|
|
59
|
+
CSG?: unknown;
|
|
60
|
+
CSG2?: unknown;
|
|
61
|
+
InitializeCSG2Async?: () => void | Promise<void>;
|
|
62
|
+
IsCSG2Ready?: () => boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Preferences for initializing MeshWriter */
|
|
66
|
+
export interface MeshWriterPreferences {
|
|
67
|
+
/** Default font family name */
|
|
68
|
+
defaultFont?: string;
|
|
69
|
+
/** Scale factor for all text */
|
|
70
|
+
scale?: number;
|
|
71
|
+
/** Origin point for mesh positioning */
|
|
72
|
+
meshOrigin?: 'letterCenter' | 'fontOrigin';
|
|
73
|
+
/** Enable debug logging */
|
|
74
|
+
debug?: boolean;
|
|
75
|
+
/** Babylon namespace providing CSG helpers (used for ES module builds) */
|
|
76
|
+
babylon?: BabylonCSGNamespace;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ============ Instance Types ============
|
|
80
|
+
|
|
81
|
+
/** A text instance created by MeshWriter */
|
|
82
|
+
export interface MeshWriterInstance {
|
|
83
|
+
/** Get the SolidParticleSystem containing letter meshes */
|
|
84
|
+
getSPS(): SolidParticleSystem | undefined;
|
|
85
|
+
/** Get the combined mesh containing all letters */
|
|
86
|
+
getMesh(): Mesh | undefined;
|
|
87
|
+
/** Get the emissive face mesh (if available) */
|
|
88
|
+
getFaceMesh(): Mesh | undefined;
|
|
89
|
+
/** Get the material applied to the text */
|
|
90
|
+
getMaterial(): StandardMaterial;
|
|
91
|
+
/** Get the emissive material used for the face mesh */
|
|
92
|
+
getFaceMaterial(): StandardMaterial | undefined;
|
|
93
|
+
/** Get the SolidParticleSystem that powers the emissive face mesh */
|
|
94
|
+
getFaceSPS(): SolidParticleSystem | undefined;
|
|
95
|
+
/** Get the X offset for anchoring */
|
|
96
|
+
getOffsetX(): number;
|
|
97
|
+
/** Get bounding boxes for each letter */
|
|
98
|
+
getLettersBoxes(): number[][];
|
|
99
|
+
/** Get origin positions for each letter */
|
|
100
|
+
getLettersOrigins(): number[][];
|
|
101
|
+
/** Get or set the emissive color */
|
|
102
|
+
color(c?: string): string;
|
|
103
|
+
/** Get or set the alpha value */
|
|
104
|
+
alpha(a?: number): number;
|
|
105
|
+
/** Update the emissive color */
|
|
106
|
+
setColor(color: string): void;
|
|
107
|
+
/** Update the alpha value */
|
|
108
|
+
setAlpha(alpha: number): void;
|
|
109
|
+
/** Temporarily override alpha */
|
|
110
|
+
overrideAlpha(alpha: number): void;
|
|
111
|
+
/** Reset alpha to original value */
|
|
112
|
+
resetAlpha(): void;
|
|
113
|
+
/** Get the center position of a letter by index */
|
|
114
|
+
getLetterCenter(ix: number): Vector2;
|
|
115
|
+
/** Check if this instance has been disposed */
|
|
116
|
+
isDisposed(): boolean;
|
|
117
|
+
/** Dispose of all meshes and materials */
|
|
118
|
+
dispose(): void;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Constructor function returned by MeshWriter factory */
|
|
122
|
+
export interface MeshWriterConstructor {
|
|
123
|
+
new (letters: string, options?: MeshWriterOptions): MeshWriterInstance;
|
|
124
|
+
(letters: string, options?: MeshWriterOptions): MeshWriterInstance;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ============ Font Types ============
|
|
128
|
+
|
|
129
|
+
/** Individual glyph specification */
|
|
130
|
+
export interface GlyphSpec {
|
|
131
|
+
/** Compressed shape command strings (pre-decompression) */
|
|
132
|
+
sC?: string[];
|
|
133
|
+
/** Compressed hole command strings - array of holes, each hole is array of command strings */
|
|
134
|
+
hC?: string[][];
|
|
135
|
+
/** Decompressed shape commands (post-decompression, internal use) */
|
|
136
|
+
shapeCmds?: number[][][];
|
|
137
|
+
/** Decompressed hole commands (post-decompression, internal use) */
|
|
138
|
+
holeCmds?: number[][][][];
|
|
139
|
+
/** Minimum X coordinate of bounding box */
|
|
140
|
+
xMin: number;
|
|
141
|
+
/** Maximum X coordinate of bounding box */
|
|
142
|
+
xMax: number;
|
|
143
|
+
/** Minimum Y coordinate of bounding box */
|
|
144
|
+
yMin: number;
|
|
145
|
+
/** Maximum Y coordinate of bounding box */
|
|
146
|
+
yMax: number;
|
|
147
|
+
/** Character advance width */
|
|
148
|
+
wdth: number;
|
|
149
|
+
/** X coordinate scale factor (optional) */
|
|
150
|
+
xFactor?: number;
|
|
151
|
+
/** Y coordinate scale factor (optional) */
|
|
152
|
+
yFactor?: number;
|
|
153
|
+
/** X coordinate shift (optional) */
|
|
154
|
+
xShift?: number;
|
|
155
|
+
/** Y coordinate shift (optional) */
|
|
156
|
+
yShift?: number;
|
|
157
|
+
/** Per-glyph reverse shape override (optional) */
|
|
158
|
+
reverseShape?: boolean;
|
|
159
|
+
/** Per-glyph reverse hole override (optional) */
|
|
160
|
+
reverseHole?: boolean;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Kerning table mapping character pairs to adjustment values */
|
|
164
|
+
export interface KerningTable {
|
|
165
|
+
/** Kerning adjustment indexed by "char1,char2" key */
|
|
166
|
+
[pair: string]: number;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Font specification object containing glyph data */
|
|
170
|
+
export interface FontSpec {
|
|
171
|
+
/** Whether to reverse hole winding (default for all glyphs) */
|
|
172
|
+
reverseHoles: boolean;
|
|
173
|
+
/** Whether to reverse shape winding (default for all glyphs) */
|
|
174
|
+
reverseShapes: boolean;
|
|
175
|
+
/** Kerning pairs table (optional) - maps "char1,char2" to adjustment value */
|
|
176
|
+
kern?: KerningTable;
|
|
177
|
+
/** Character glyph data - indexed by character */
|
|
178
|
+
[character: string]: GlyphSpec | boolean | KerningTable | undefined;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Function that creates font spec from codeList encoder
|
|
183
|
+
* @deprecated Use FontSpec directly instead of FontFactory
|
|
184
|
+
*/
|
|
185
|
+
export type FontFactory = (codeList: (list: number[][]) => string) => FontSpec;
|
|
186
|
+
|
|
187
|
+
/** Font data - either a FontSpec object or a FontFactory function (legacy) */
|
|
188
|
+
export type FontData = FontSpec | FontFactory;
|
|
189
|
+
|
|
190
|
+
// ============ Main API Types ============
|
|
191
|
+
|
|
192
|
+
/** CSG version used for boolean operations */
|
|
193
|
+
export type CSGVersion = 'CSG' | 'CSG2' | null;
|
|
194
|
+
|
|
195
|
+
/** MeshWriter static API */
|
|
196
|
+
export interface MeshWriterStatic {
|
|
197
|
+
/**
|
|
198
|
+
* Create a MeshWriter constructor asynchronously (required for Babylon 8+)
|
|
199
|
+
* Initializes CSG2 before returning
|
|
200
|
+
*/
|
|
201
|
+
createAsync(scene: Scene, preferences?: MeshWriterPreferences): Promise<MeshWriterConstructor>;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Create a MeshWriter constructor synchronously (legacy, Babylon < 7.31)
|
|
205
|
+
* @deprecated Use createAsync for Babylon 8+
|
|
206
|
+
*/
|
|
207
|
+
create(scene: Scene, preferences?: MeshWriterPreferences): MeshWriterConstructor;
|
|
208
|
+
|
|
209
|
+
/** Check if CSG is initialized and ready */
|
|
210
|
+
isReady(): boolean;
|
|
211
|
+
|
|
212
|
+
/** Get the CSG version being used */
|
|
213
|
+
getCSGVersion(): CSGVersion;
|
|
214
|
+
|
|
215
|
+
/** Set a custom CSG2 initializer function */
|
|
216
|
+
setCSGInitializer(init: () => void | Promise<void>): void;
|
|
217
|
+
|
|
218
|
+
/** Set a custom CSG ready check function */
|
|
219
|
+
setCSGReadyCheck(check: () => boolean): void;
|
|
220
|
+
|
|
221
|
+
/** Register a callback to run when CSG is ready */
|
|
222
|
+
onCSGReady(callback: () => void): void;
|
|
223
|
+
|
|
224
|
+
/** Manually mark CSG as ready */
|
|
225
|
+
markCSGReady(): void;
|
|
226
|
+
|
|
227
|
+
/** Initialize the internal CSG module with Babylon helpers */
|
|
228
|
+
initCSGModule(babylon: BabylonCSGNamespace): void;
|
|
229
|
+
|
|
230
|
+
/** Register a font for use with MeshWriter */
|
|
231
|
+
registerFont(name: string, fontData: FontData): void;
|
|
232
|
+
|
|
233
|
+
/** Register multiple font aliases pointing to the same font */
|
|
234
|
+
registerFontAliases(targetName: string, ...aliases: string[]): void;
|
|
235
|
+
|
|
236
|
+
/** Get a registered font by name */
|
|
237
|
+
getFont(name: string): FontSpec | undefined;
|
|
238
|
+
|
|
239
|
+
/** Check if a font is registered */
|
|
240
|
+
isFontRegistered(name: string): boolean;
|
|
241
|
+
|
|
242
|
+
/** Encode font coordinates to compressed string */
|
|
243
|
+
codeList(list: number[][]): string;
|
|
244
|
+
|
|
245
|
+
/** Decode compressed string to font coordinates */
|
|
246
|
+
decodeList(encoded: string): number[][];
|
|
247
|
+
|
|
248
|
+
/** Load a pre-baked font from a JSON file */
|
|
249
|
+
loadBakedFont(url: string): Promise<FontSpec>;
|
|
250
|
+
|
|
251
|
+
/** Load multiple pre-baked weights from a manifest */
|
|
252
|
+
loadBakedFontsFromManifest(manifestUrl: string, weights?: number[]): Promise<Map<number, FontSpec>>;
|
|
253
|
+
|
|
254
|
+
/** Find the nearest available weight from a set of baked weights */
|
|
255
|
+
findNearestWeight(targetWeight: number, availableWeights: number[]): number;
|
|
256
|
+
|
|
257
|
+
/** Get manifest info without loading fonts */
|
|
258
|
+
getBakedFontManifest(manifestUrl: string): Promise<BakedFontManifest>;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ============ Exports ============
|
|
262
|
+
|
|
263
|
+
/** Main MeshWriter object with all static methods */
|
|
264
|
+
export const MeshWriter: MeshWriterStatic;
|
|
265
|
+
|
|
266
|
+
/** Create a MeshWriter constructor asynchronously */
|
|
267
|
+
export function createMeshWriterAsync(scene: Scene, preferences?: MeshWriterPreferences): Promise<MeshWriterConstructor>;
|
|
268
|
+
|
|
269
|
+
/** Create a MeshWriter constructor synchronously (legacy) */
|
|
270
|
+
export function createMeshWriter(scene: Scene, preferences?: MeshWriterPreferences): MeshWriterConstructor;
|
|
271
|
+
|
|
272
|
+
/** Check if CSG is initialized and ready */
|
|
273
|
+
export function isCSGReady(): boolean;
|
|
274
|
+
|
|
275
|
+
/** Get the CSG version being used */
|
|
276
|
+
export function getCSGVersion(): CSGVersion;
|
|
277
|
+
|
|
278
|
+
/** Set a custom CSG2 initializer function */
|
|
279
|
+
export function setCSGInitializer(init: () => void | Promise<void>): void;
|
|
280
|
+
|
|
281
|
+
/** Set a custom CSG ready check function */
|
|
282
|
+
export function setCSGReadyCheck(check: () => boolean): void;
|
|
283
|
+
|
|
284
|
+
/** Register a callback to run when CSG is ready */
|
|
285
|
+
export function onCSGReady(callback: () => void): void;
|
|
286
|
+
|
|
287
|
+
/** Manually mark CSG as ready */
|
|
288
|
+
export function markCSGReady(): void;
|
|
289
|
+
|
|
290
|
+
/** Register a font for use with MeshWriter */
|
|
291
|
+
export function registerFont(name: string, fontData: FontData): void;
|
|
292
|
+
|
|
293
|
+
/** Register multiple font aliases */
|
|
294
|
+
export function registerFontAliases(targetName: string, ...aliases: string[]): void;
|
|
295
|
+
|
|
296
|
+
/** Get a registered font by name */
|
|
297
|
+
export function getFont(name: string): FontSpec | undefined;
|
|
298
|
+
|
|
299
|
+
/** Check if a font is registered */
|
|
300
|
+
export function isFontRegistered(name: string): boolean;
|
|
301
|
+
|
|
302
|
+
/** Encode font coordinates to compressed string */
|
|
303
|
+
export function codeList(list: number[][]): string;
|
|
304
|
+
|
|
305
|
+
/** Decode compressed string to font coordinates */
|
|
306
|
+
export function decodeList(encoded: string): number[][];
|
|
307
|
+
|
|
308
|
+
/** Get list of registered font names */
|
|
309
|
+
export function getRegisteredFonts(): string[];
|
|
310
|
+
|
|
311
|
+
/** Unregister a font (primarily for testing) */
|
|
312
|
+
export function unregisterFont(name: string): void;
|
|
313
|
+
|
|
314
|
+
/** Clear all registered fonts (primarily for testing) */
|
|
315
|
+
export function clearFonts(): void;
|
|
316
|
+
|
|
317
|
+
/** Encode font coordinates (alias of codeList) */
|
|
318
|
+
export function encodeFontData(list: number[][]): string;
|
|
319
|
+
|
|
320
|
+
/** Decode font coordinates (alias of decodeList) */
|
|
321
|
+
export function decodeFontData(encoded: string): number[][];
|
|
322
|
+
|
|
323
|
+
/** Initialize the internal CSG module with Babylon helpers */
|
|
324
|
+
export function initCSGModule(babylon: BabylonCSGNamespace): void;
|
|
325
|
+
|
|
326
|
+
// ============ Baked Font Types ============
|
|
327
|
+
|
|
328
|
+
/** Manifest for baked font weights */
|
|
329
|
+
export interface BakedFontManifest {
|
|
330
|
+
/** Full font name */
|
|
331
|
+
fontName: string;
|
|
332
|
+
/** Base name used for files */
|
|
333
|
+
baseName: string;
|
|
334
|
+
/** Character set included */
|
|
335
|
+
charset: string;
|
|
336
|
+
/** Number of characters in charset */
|
|
337
|
+
charsetLength: number;
|
|
338
|
+
/** Weight range of original font */
|
|
339
|
+
weightRange: { min: number; max: number };
|
|
340
|
+
/** Available baked weights */
|
|
341
|
+
weights: number[];
|
|
342
|
+
/** File names for each weight */
|
|
343
|
+
files: string[];
|
|
344
|
+
/** ISO timestamp of generation */
|
|
345
|
+
generatedAt: string;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Load a pre-baked font from a JSON file
|
|
350
|
+
* Zero dependencies - just fetch and use.
|
|
351
|
+
*
|
|
352
|
+
* @param url - URL to the baked FontSpec JSON file
|
|
353
|
+
* @returns Promise resolving to FontSpec object
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* const fontSpec = await loadBakedFont('/fonts/baked/atkinson-400.json');
|
|
357
|
+
* registerFont('Atkinson400', fontSpec);
|
|
358
|
+
*/
|
|
359
|
+
export function loadBakedFont(url: string): Promise<FontSpec>;
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Load multiple pre-baked weights from a manifest
|
|
363
|
+
*
|
|
364
|
+
* @param manifestUrl - URL to the manifest.json file
|
|
365
|
+
* @param weights - Specific weights to load (loads all if omitted)
|
|
366
|
+
* @returns Promise resolving to Map of weight -> FontSpec
|
|
367
|
+
*
|
|
368
|
+
* @example
|
|
369
|
+
* const fonts = await loadBakedFontsFromManifest('/fonts/baked/manifest.json', [400, 450]);
|
|
370
|
+
* const fontSpec = fonts.get(400);
|
|
371
|
+
*/
|
|
372
|
+
export function loadBakedFontsFromManifest(manifestUrl: string, weights?: number[]): Promise<Map<number, FontSpec>>;
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Find the nearest available weight from a set of baked weights
|
|
376
|
+
*
|
|
377
|
+
* @param targetWeight - Desired weight
|
|
378
|
+
* @param availableWeights - Array of available weights
|
|
379
|
+
* @returns Nearest available weight
|
|
380
|
+
*
|
|
381
|
+
* @example
|
|
382
|
+
* const nearest = findNearestWeight(425, [400, 450, 500]);
|
|
383
|
+
* // Returns 450 (closest to 425)
|
|
384
|
+
*/
|
|
385
|
+
export function findNearestWeight(targetWeight: number, availableWeights: number[]): number;
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Get manifest info without loading fonts
|
|
389
|
+
*
|
|
390
|
+
* @param manifestUrl - URL to the manifest.json file
|
|
391
|
+
* @returns Promise resolving to manifest object
|
|
392
|
+
*/
|
|
393
|
+
export function getBakedFontManifest(manifestUrl: string): Promise<BakedFontManifest>;
|
|
394
|
+
|
|
395
|
+
// ============ Material Plugins ============
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* TextFogPlugin - MaterialPluginBase that applies fog to emissive color
|
|
399
|
+
*
|
|
400
|
+
* Babylon's standard fog only affects diffuse/ambient channels.
|
|
401
|
+
* This plugin recalculates fog blending for the final color output,
|
|
402
|
+
* ensuring emissive text fades properly with distance fog.
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* // Automatically attached when fog-enabled is true
|
|
406
|
+
* const text = new Writer("Hello", { 'fog-enabled': true });
|
|
407
|
+
*
|
|
408
|
+
* // Or manually attach to any StandardMaterial
|
|
409
|
+
* import { TextFogPlugin } from 'meshwriter';
|
|
410
|
+
* new TextFogPlugin(myMaterial);
|
|
411
|
+
*/
|
|
412
|
+
export class TextFogPlugin extends MaterialPluginBase {
|
|
413
|
+
constructor(material: Material);
|
|
414
|
+
prepareDefines(defines: Record<string, boolean>, scene: Scene, mesh: Mesh): void;
|
|
415
|
+
getClassName(): string;
|
|
416
|
+
getUniforms(): { ubo: Array<{ name: string; size?: number; type?: string; arraySize?: number }> };
|
|
417
|
+
getCustomCode(shaderType: string): Record<string, string> | null;
|
|
418
|
+
dispose(): void;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// ============ Color Contrast Types ============
|
|
422
|
+
|
|
423
|
+
/** RGB color object with values in 0-1 range */
|
|
424
|
+
export interface RGBColor {
|
|
425
|
+
r: number;
|
|
426
|
+
g: number;
|
|
427
|
+
b: number;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/** HSL color object with h in degrees (0-360), s and l in 0-1 range */
|
|
431
|
+
export interface HSLColor {
|
|
432
|
+
h: number;
|
|
433
|
+
s: number;
|
|
434
|
+
l: number;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/** Colors for contrast adjustment */
|
|
438
|
+
export interface ContrastColors {
|
|
439
|
+
emissive: string;
|
|
440
|
+
diffuse: string;
|
|
441
|
+
ambient?: string;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/** Options for adjustForContrast function */
|
|
445
|
+
export interface AdjustContrastOptions {
|
|
446
|
+
/** Target WCAG contrast ratio (default: 4.5) */
|
|
447
|
+
targetContrast?: number;
|
|
448
|
+
/** Max edge color modification range 0-1 (default: 0.4) */
|
|
449
|
+
edgeRange?: number;
|
|
450
|
+
/** Max face color modification range 0-1 (default: 0.1) */
|
|
451
|
+
faceRange?: number;
|
|
452
|
+
/** Allow hue modifications for maximum contrast (default: true) */
|
|
453
|
+
allowHueShift?: boolean;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/** Result of contrast adjustment */
|
|
457
|
+
export interface ContrastResult {
|
|
458
|
+
emissive: string;
|
|
459
|
+
diffuse: string;
|
|
460
|
+
ambient: string;
|
|
461
|
+
/** Achieved contrast ratio */
|
|
462
|
+
achieved: number;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/** WCAG contrast level constants */
|
|
466
|
+
export const CONTRAST_LEVELS: {
|
|
467
|
+
/** WCAG AA for normal text: 4.5:1 */
|
|
468
|
+
AA_NORMAL: 4.5;
|
|
469
|
+
/** WCAG AA for large text: 3:1 */
|
|
470
|
+
AA_LARGE: 3.0;
|
|
471
|
+
/** WCAG AAA for normal text: 7:1 */
|
|
472
|
+
AAA_NORMAL: 7.0;
|
|
473
|
+
/** WCAG AAA for large text: 4.5:1 */
|
|
474
|
+
AAA_LARGE: 4.5;
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Convert hex color string to RGB object
|
|
479
|
+
* @param hex - Hex color string (e.g., "#FF0000" or "FF0000")
|
|
480
|
+
*/
|
|
481
|
+
export function hexToRgb(hex: string): RGBColor;
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Convert RGB object to hex color string
|
|
485
|
+
* @param rgb - RGB color with values in 0-1 range
|
|
486
|
+
*/
|
|
487
|
+
export function rgbToHex(rgb: RGBColor): string;
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Convert RGB to HSL
|
|
491
|
+
* @param r - Red (0-1)
|
|
492
|
+
* @param g - Green (0-1)
|
|
493
|
+
* @param b - Blue (0-1)
|
|
494
|
+
*/
|
|
495
|
+
export function rgbToHsl(r: number, g: number, b: number): HSLColor;
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Convert HSL to RGB
|
|
499
|
+
* @param h - Hue in degrees (0-360)
|
|
500
|
+
* @param s - Saturation (0-1)
|
|
501
|
+
* @param l - Lightness (0-1)
|
|
502
|
+
*/
|
|
503
|
+
export function hslToRgb(h: number, s: number, l: number): RGBColor;
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Calculate relative luminance per WCAG 2.1
|
|
507
|
+
* @param r - Red (0-1)
|
|
508
|
+
* @param g - Green (0-1)
|
|
509
|
+
* @param b - Blue (0-1)
|
|
510
|
+
* @returns Relative luminance (0-1)
|
|
511
|
+
*/
|
|
512
|
+
export function relativeLuminance(r: number, g: number, b: number): number;
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Calculate WCAG contrast ratio between two luminance values
|
|
516
|
+
* @param L1 - Luminance of first color (0-1)
|
|
517
|
+
* @param L2 - Luminance of second color (0-1)
|
|
518
|
+
* @returns Contrast ratio (1-21)
|
|
519
|
+
*/
|
|
520
|
+
export function contrastRatio(L1: number, L2: number): number;
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Auto-derive edge colors (diffuse/ambient) from emissive color
|
|
524
|
+
* Creates high-contrast edges for text legibility
|
|
525
|
+
* Uses inverted approach: bright diffuse for lit surfaces, dark emissive for base
|
|
526
|
+
*
|
|
527
|
+
* @param emissiveHex - Hex color string for desired face color
|
|
528
|
+
* @param targetContrast - Target WCAG contrast ratio (default: 4.5)
|
|
529
|
+
* @returns Object with diffuse, ambient, and emissive hex colors
|
|
530
|
+
*/
|
|
531
|
+
export function deriveEdgeColors(emissiveHex: string, targetContrast?: number): { diffuse: string; ambient: string; emissive: string };
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Adjust colors to achieve WCAG contrast while preserving user intent
|
|
535
|
+
* Priority: prefer edge modifications over face modifications
|
|
536
|
+
*
|
|
537
|
+
* @param colors - User-provided colors
|
|
538
|
+
* @param options - Adjustment options
|
|
539
|
+
* @returns Adjusted colors with achieved contrast ratio
|
|
540
|
+
*/
|
|
541
|
+
export function adjustForContrast(colors: ContrastColors, options?: AdjustContrastOptions): ContrastResult;
|
|
542
|
+
|
|
543
|
+
// ============ Module Augmentation ============
|
|
544
|
+
|
|
545
|
+
// Extend StandardMaterial to include fog plugin reference
|
|
546
|
+
declare module '@babylonjs/core/Materials/standardMaterial' {
|
|
547
|
+
interface StandardMaterial {
|
|
548
|
+
/** @internal TextFogPlugin instance attached by MeshWriter */
|
|
549
|
+
_textFogPlugin?: TextFogPlugin;
|
|
550
|
+
}
|
|
551
|
+
}
|