@layoutit/polycss-core 0.0.1
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 +21 -0
- package/README.md +112 -0
- package/dist/index.cjs +3 -0
- package/dist/index.d.cts +914 -0
- package/dist/index.d.ts +914 -0
- package/dist/index.js +3 -0
- package/package.json +53 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,914 @@
|
|
|
1
|
+
declare const DEFAULT_PROJECTION: "cubic";
|
|
2
|
+
/**
|
|
3
|
+
* How polygon lighting is applied by DOM renderers.
|
|
4
|
+
* - "baked": multiply the light tint into the off-DOM canvas before the
|
|
5
|
+
* polygon becomes an atlas sprite. Best fidelity (full RGB tint) but
|
|
6
|
+
* the atlas re-rasterizes whenever the light changes.
|
|
7
|
+
* - "dynamic": lighting computed entirely in CSS via per-polygon normals
|
|
8
|
+
* embedded in calc() and scene-root light vars (background-color +
|
|
9
|
+
* background-blend-mode multiply, masked by the atlas alpha). Atlas
|
|
10
|
+
* stays light-independent — sliding the light only writes a few CSS
|
|
11
|
+
* variables, no JS work, no atlas re-rasterization.
|
|
12
|
+
*/
|
|
13
|
+
type PolyTextureLightingMode = "baked" | "dynamic";
|
|
14
|
+
/**
|
|
15
|
+
* 3D point/vector, stored as a `[x, y, z]` tuple. Tuple (rather than
|
|
16
|
+
* `{x, y, z}`) for compact JSON: meshes serialize to thousands of vertices
|
|
17
|
+
* and the difference adds up. Destructure with `const [x, y, z] = v` when
|
|
18
|
+
* you need named axes.
|
|
19
|
+
*
|
|
20
|
+
* Polycss world space convention: +X right, +Y forward, +Z up.
|
|
21
|
+
*/
|
|
22
|
+
type Vec3 = [number, number, number];
|
|
23
|
+
/**
|
|
24
|
+
* 2D point/vector — `[u, v]`. Used for texture-atlas UV coordinates on
|
|
25
|
+
* polygons. Convention follows OBJ: u is horizontal (0=left, 1=right),
|
|
26
|
+
* v is vertical (0=bottom, 1=top). Renderers flip v when binding to raster
|
|
27
|
+
* image space whose Y-axis points down.
|
|
28
|
+
*/
|
|
29
|
+
type Vec2 = [number, number];
|
|
30
|
+
interface TextureTriangle {
|
|
31
|
+
vertices: [Vec3, Vec3, Vec3];
|
|
32
|
+
uvs: [Vec2, Vec2, Vec2];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Directional light — simulates a single distant source (sun, key light).
|
|
36
|
+
* Contributes Lambert shading scaled by `intensity`. `direction` is in
|
|
37
|
+
* scene-local CSS-pixel coords and does not need to be pre-normalized.
|
|
38
|
+
* Mirrors three.js's `DirectionalLight`.
|
|
39
|
+
*/
|
|
40
|
+
interface PolyDirectionalLight {
|
|
41
|
+
/** Direction the light shines TOWARD (typical convention). */
|
|
42
|
+
direction: Vec3;
|
|
43
|
+
/** Light tint, hex string. White by default. */
|
|
44
|
+
color?: string;
|
|
45
|
+
/** Scalar multiplier on the directional contribution. Default 1. */
|
|
46
|
+
intensity?: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Ambient light — uniform fill that adds to every polygon regardless of
|
|
50
|
+
* orientation. Mirrors three.js's `AmbientLight`. Decoupled from the
|
|
51
|
+
* directional contribution: the two add independently rather than
|
|
52
|
+
* splitting a fixed energy budget.
|
|
53
|
+
*/
|
|
54
|
+
interface PolyAmbientLight {
|
|
55
|
+
/** Tint, hex string. White by default. */
|
|
56
|
+
color?: string;
|
|
57
|
+
/** Scalar multiplier on the ambient contribution. Default 0.4. */
|
|
58
|
+
intensity?: number;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Material — paint configuration shareable across many polygons.
|
|
62
|
+
*
|
|
63
|
+
* In CSS terms, a material bundles the `background-image` source plus paint
|
|
64
|
+
* config. When a polygon references a material AND its UVs form an
|
|
65
|
+
* axis-aligned rectangle, polycss renders the polygon as an <i> with
|
|
66
|
+
* `background-image: url(material.texture)` directly — no per-polygon canvas
|
|
67
|
+
* rasterization, browser-cached texture, mounting / unmounting one polygon
|
|
68
|
+
* does not affect any other.
|
|
69
|
+
*
|
|
70
|
+
* Three.js parallel: combines THREE.Texture + a basic Material in one. CSS
|
|
71
|
+
* has no shader/sampler concerns, so the texture/material split from
|
|
72
|
+
* Three.js doesn't pay rent here.
|
|
73
|
+
*/
|
|
74
|
+
interface PolyMaterial {
|
|
75
|
+
/** Image source. Anything `background-image: url(...)` can use. */
|
|
76
|
+
texture: string;
|
|
77
|
+
/** Optional unique key (used by polycss to dedupe / cache). Caller can
|
|
78
|
+
* pass a stable string; if omitted, the material's identity is its object
|
|
79
|
+
* reference. */
|
|
80
|
+
key?: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The single polygon type for polycss. N coplanar vertices in 3D space,
|
|
84
|
+
* CCW winding from outside. No bbox field, no shape discriminator, no
|
|
85
|
+
* input/output distinction — one type, used by parsers, by the merge
|
|
86
|
+
* pass, and by the renderer.
|
|
87
|
+
*/
|
|
88
|
+
interface Polygon {
|
|
89
|
+
/** N coplanar vertices in 3D space, CCW winding from outside. */
|
|
90
|
+
vertices: Vec3[];
|
|
91
|
+
/**
|
|
92
|
+
* Solid base color. Falls back to "#cccccc" when neither color nor
|
|
93
|
+
* texture is set.
|
|
94
|
+
*/
|
|
95
|
+
color?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Texture URL. When set with `uvs`, UV-mapped via affine; without
|
|
98
|
+
* `uvs`, single-tile fill. If the load fails, renderer falls back to
|
|
99
|
+
* `color` (or default gray).
|
|
100
|
+
*/
|
|
101
|
+
texture?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Shared material. When set, `material.texture` takes precedence over the
|
|
104
|
+
* inline `texture` field. If the polygon's UVs form an axis-aligned
|
|
105
|
+
* rectangle, polycss uses the direct CSS background-image path (no per-
|
|
106
|
+
* polygon canvas rasterization). Falls back to the atlas path otherwise.
|
|
107
|
+
*/
|
|
108
|
+
material?: PolyMaterial;
|
|
109
|
+
/**
|
|
110
|
+
* Per-vertex UV coords (0..1, OBJ convention with v=0 at bottom).
|
|
111
|
+
* Length MUST equal vertices.length when set; mismatched UVs are
|
|
112
|
+
* stripped by `normalizePolygons`.
|
|
113
|
+
*/
|
|
114
|
+
uvs?: Vec2[];
|
|
115
|
+
/**
|
|
116
|
+
* Renderer-internal source triangles for UV textures. Merge passes use this
|
|
117
|
+
* to reduce DOM planes while preserving per-triangle texture mapping in the
|
|
118
|
+
* generated atlas.
|
|
119
|
+
* @internal
|
|
120
|
+
*/
|
|
121
|
+
textureTriangles?: TextureTriangle[];
|
|
122
|
+
/**
|
|
123
|
+
* User-controlled metadata. Reflected to DOM as `data-*` attributes via
|
|
124
|
+
* stringification by the framework wrappers. Only string|number|boolean
|
|
125
|
+
* values are kept; other shapes are dropped by `normalizePolygons`.
|
|
126
|
+
*/
|
|
127
|
+
data?: Record<string, string | number | boolean>;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* normalizePolygons — validates a polygon list, drops degenerate inputs,
|
|
132
|
+
* triangulates non-coplanar N-gons, strips bad UVs, sanitizes data, and
|
|
133
|
+
* returns the cleaned polygons + a list of human-readable warnings.
|
|
134
|
+
*
|
|
135
|
+
* Validation rules are encoded here and covered by the normalization tests.
|
|
136
|
+
*
|
|
137
|
+
* Pure: no DOM, no I/O, deterministic. Bbox is NOT computed here — that's
|
|
138
|
+
* derived on demand by `buildSceneContext` / consumers.
|
|
139
|
+
*/
|
|
140
|
+
|
|
141
|
+
interface NormalizeResult {
|
|
142
|
+
polygons: Polygon[];
|
|
143
|
+
warnings: string[];
|
|
144
|
+
}
|
|
145
|
+
declare function normalizePolygons(input: Polygon[]): NormalizeResult;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Scene context — the top-level entry point that takes a polygon mesh
|
|
149
|
+
* (already normalized) and returns the data the framework wrappers need
|
|
150
|
+
* to render.
|
|
151
|
+
*
|
|
152
|
+
* No cube grid, no per-Z layer bucketing, no wall mask, no neighbor-based
|
|
153
|
+
* occlusion. Just a polygon list and a scene bbox.
|
|
154
|
+
*/
|
|
155
|
+
|
|
156
|
+
interface SceneBbox {
|
|
157
|
+
/** Minimum corner of the axis-aligned bounding box (inclusive). */
|
|
158
|
+
min: Vec3;
|
|
159
|
+
/** Maximum corner of the axis-aligned bounding box (inclusive). */
|
|
160
|
+
max: Vec3;
|
|
161
|
+
}
|
|
162
|
+
interface SceneContext {
|
|
163
|
+
/** Validated polygon list — the renderer iterates this. */
|
|
164
|
+
polygons: Polygon[];
|
|
165
|
+
/** Polygon-mesh bbox in world space. Used to size the scene container. */
|
|
166
|
+
sceneBbox: SceneBbox;
|
|
167
|
+
/** Warnings raised during normalization (already-applied fixes). */
|
|
168
|
+
warnings: string[];
|
|
169
|
+
}
|
|
170
|
+
interface SceneContextBuildArgs {
|
|
171
|
+
/**
|
|
172
|
+
* Polygon list. Pass parser output directly — `buildSceneContext` runs
|
|
173
|
+
* `normalizePolygons` for you.
|
|
174
|
+
*/
|
|
175
|
+
polygons: Polygon[];
|
|
176
|
+
/**
|
|
177
|
+
* If true, skip the normalize pass (caller has already validated). Useful
|
|
178
|
+
* when chaining `mergePolygons` after a manual `normalizePolygons` call.
|
|
179
|
+
*/
|
|
180
|
+
skipNormalize?: boolean;
|
|
181
|
+
}
|
|
182
|
+
interface SceneContextBuildResult {
|
|
183
|
+
context: SceneContext;
|
|
184
|
+
/**
|
|
185
|
+
* Mesh-bbox dimensions. Convenience copy of `context.sceneBbox` plus a
|
|
186
|
+
* `size` field (max - min) for callers that want a single number per axis.
|
|
187
|
+
*/
|
|
188
|
+
dimensions: {
|
|
189
|
+
sceneBbox: SceneBbox;
|
|
190
|
+
size: Vec3;
|
|
191
|
+
};
|
|
192
|
+
/** Warnings raised during normalization. Mirrors `context.warnings`. */
|
|
193
|
+
warnings: string[];
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Compute the axis-aligned bounding box across every vertex of every polygon.
|
|
197
|
+
* Returns a zero-extent bbox at origin for empty input — callers that care
|
|
198
|
+
* about that case should check `polygons.length` first.
|
|
199
|
+
*/
|
|
200
|
+
declare function computeSceneBbox(polygons: Polygon[]): SceneBbox;
|
|
201
|
+
declare function buildSceneContext(args: SceneContextBuildArgs): SceneContextBuildResult;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Polygon geometry helpers — pure math operating on Polygon vertices.
|
|
205
|
+
*
|
|
206
|
+
* After cube removal in Phase 2, this module carries small polygon-level
|
|
207
|
+
* helpers for downstream consumers (lighting, debug metrics, etc.). The
|
|
208
|
+
* cube / ramp / wedge / spike face emitters lived here in voxcss; they're gone.
|
|
209
|
+
*/
|
|
210
|
+
|
|
211
|
+
interface PolygonFace {
|
|
212
|
+
/** Vertices in CCW-from-outside order. Same as Polygon.vertices. */
|
|
213
|
+
v: Vec3[];
|
|
214
|
+
/** Original polygon's color, if any (for lighting helpers). */
|
|
215
|
+
color?: string;
|
|
216
|
+
}
|
|
217
|
+
interface TexturePaintMetricsOptions {
|
|
218
|
+
/** CSS pixels per world X/Y unit. Matches renderer default. */
|
|
219
|
+
tileSize?: number;
|
|
220
|
+
/** CSS pixels per world Z unit. Defaults to tileSize. */
|
|
221
|
+
layerElevation?: number;
|
|
222
|
+
/** When true, skip untextured polygons. Defaults to true. */
|
|
223
|
+
texturedOnly?: boolean;
|
|
224
|
+
}
|
|
225
|
+
interface TexturePaintMetrics {
|
|
226
|
+
/** Input polygon count before filtering. */
|
|
227
|
+
totalPolygons: number;
|
|
228
|
+
/** Polygons included in the metric after filtering and degeneracy checks. */
|
|
229
|
+
measuredPolygons: number;
|
|
230
|
+
/** Included polygons with a texture URL. */
|
|
231
|
+
texturedPolygons: number;
|
|
232
|
+
/** Sum of rectangular element areas in CSS px^2. */
|
|
233
|
+
elementArea: number;
|
|
234
|
+
/** Sum of projected polygon areas in CSS px^2. */
|
|
235
|
+
polygonArea: number;
|
|
236
|
+
/** elementArea - polygonArea, clamped at 0. */
|
|
237
|
+
transparentArea: number;
|
|
238
|
+
/** transparentArea / elementArea. */
|
|
239
|
+
transparentRatio: number;
|
|
240
|
+
/** elementArea / polygonArea. */
|
|
241
|
+
overdrawRatio: number;
|
|
242
|
+
/** Highest per-polygon transparentRatio. */
|
|
243
|
+
worstTransparentRatio: number;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Surface a polygon as a single face. The returned array always has length 1;
|
|
247
|
+
* the indirection exists so callers that historically iterated faces (e.g.
|
|
248
|
+
* the manifold check, the canvas validator) can keep their loop shape.
|
|
249
|
+
*
|
|
250
|
+
* Returns an empty array for degenerate polygons (< 3 vertices).
|
|
251
|
+
*/
|
|
252
|
+
declare function polygonFaces(p: Polygon): PolygonFace[];
|
|
253
|
+
declare function computeTexturePaintMetrics(polygons: Polygon[], options?: TexturePaintMetricsOptions): TexturePaintMetrics;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Apply CSS-style chained `rotateX(rx) rotateY(ry) rotateZ(rz)` rotation
|
|
257
|
+
* to a 3D vector. Matches the matrix composition used by polycss mesh
|
|
258
|
+
* wrapper transforms (see `buildTransform` in each PolyMesh implementation).
|
|
259
|
+
*
|
|
260
|
+
* CSS composes `transform: rotateX(rx) rotateY(ry) rotateZ(rz)` as the
|
|
261
|
+
* matrix `M = Rx · Ry · Rz`, applied to a point as `M · p` — so Rz acts
|
|
262
|
+
* first on the point, then Ry, then Rx. Compound rotations only commute
|
|
263
|
+
* when axes coincide; getting the order wrong silently corrupts results
|
|
264
|
+
* for any two-axis combination.
|
|
265
|
+
*
|
|
266
|
+
* Angles in degrees.
|
|
267
|
+
*/
|
|
268
|
+
declare function rotateVec3(v: Vec3, rxDeg: number, ryDeg: number, rzDeg: number): Vec3;
|
|
269
|
+
/**
|
|
270
|
+
* Inverse of `rotateVec3` for the same rotation tuple — transforms a
|
|
271
|
+
* world-space vector into the mesh's local frame. Used by the baked
|
|
272
|
+
* atlas pipeline to inverse-rotate the directional light so the
|
|
273
|
+
* pre-multiplied Lambert shading stays correct after the mesh rotates,
|
|
274
|
+
* and by the dynamic-mode CSS-var override for the same reason.
|
|
275
|
+
*
|
|
276
|
+
* The inverse of `M = Rx · Ry · Rz` is `M⁻¹ = Rz⁻¹ · Ry⁻¹ · Rx⁻¹`, so
|
|
277
|
+
* Rx⁻¹ acts first on the vector, then Ry⁻¹, then Rz⁻¹.
|
|
278
|
+
*
|
|
279
|
+
* `rot` is `[rxDeg, ryDeg, rzDeg]` matching the mesh's CSS rotation prop.
|
|
280
|
+
*/
|
|
281
|
+
declare function inverseRotateVec3(v: Vec3, rot: Vec3): Vec3;
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Base tile size in CSS pixels. One polycss world unit = BASE_TILE CSS
|
|
285
|
+
* pixels (pre-scale). Used to convert world-coordinate target values to
|
|
286
|
+
* CSS translations in the transform string.
|
|
287
|
+
*/
|
|
288
|
+
declare const BASE_TILE = 50;
|
|
289
|
+
interface AutoRotateConfig {
|
|
290
|
+
axis?: "x" | "y";
|
|
291
|
+
speed?: number;
|
|
292
|
+
pauseOnInteraction?: boolean;
|
|
293
|
+
}
|
|
294
|
+
type AutoRotateOption = boolean | number | AutoRotateConfig;
|
|
295
|
+
/**
|
|
296
|
+
* World-coordinate camera state (Three.js-style).
|
|
297
|
+
*
|
|
298
|
+
* `target` is the world point that should appear at the viewport centre.
|
|
299
|
+
* Polycss world axes: [0]=X (rows/south), [1]=Y (cols/east), [2]=Z (up).
|
|
300
|
+
*
|
|
301
|
+
* `pan`, `tilt`, and `depthOffset` are gone. Translations now live inside
|
|
302
|
+
* `target` so they happen BEFORE rotations — enabling correct world-space
|
|
303
|
+
* pan at any tilt angle.
|
|
304
|
+
*
|
|
305
|
+
* `distance` is the camera's pull-back from the target in CSS pixels.
|
|
306
|
+
* Increasing distance moves the camera farther from the target along the
|
|
307
|
+
* view axis (dolly out) — analogous to three.js's spherical radius.
|
|
308
|
+
* Default 0 keeps the legacy behaviour unchanged.
|
|
309
|
+
*/
|
|
310
|
+
interface CameraState {
|
|
311
|
+
target: Vec3;
|
|
312
|
+
rotX: number;
|
|
313
|
+
rotY: number;
|
|
314
|
+
zoom: number;
|
|
315
|
+
/** Camera pull-back from target in CSS pixels. Default 0. */
|
|
316
|
+
distance: number;
|
|
317
|
+
}
|
|
318
|
+
interface CameraStyleInput {
|
|
319
|
+
rows?: number;
|
|
320
|
+
cols?: number;
|
|
321
|
+
}
|
|
322
|
+
interface CameraHandle {
|
|
323
|
+
state: CameraState;
|
|
324
|
+
update(next: Partial<CameraState>): void;
|
|
325
|
+
getStyle(input?: CameraStyleInput): {
|
|
326
|
+
transform: string;
|
|
327
|
+
width: string;
|
|
328
|
+
height: string;
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
declare function normalizeInvertMultiplier(value: number | boolean | undefined): number | undefined;
|
|
332
|
+
declare const DEFAULT_CAMERA_STATE: CameraState;
|
|
333
|
+
declare function createIsometricCamera(initial?: Partial<CameraState>): CameraHandle;
|
|
334
|
+
|
|
335
|
+
interface ParsedColor {
|
|
336
|
+
rgb: [number, number, number];
|
|
337
|
+
alpha: number;
|
|
338
|
+
}
|
|
339
|
+
declare function parseHexColor(value: string): ParsedColor | null;
|
|
340
|
+
declare function parseRgbColor(value: string): ParsedColor | null;
|
|
341
|
+
/** Parse hex or rgb/rgba color strings. Pure — no DOM. */
|
|
342
|
+
declare function parsePureColor(input: string): ParsedColor | null;
|
|
343
|
+
declare function clampChannel(value: number): number;
|
|
344
|
+
declare function formatColor(color: ParsedColor): string;
|
|
345
|
+
|
|
346
|
+
declare function parseColor(input: string): ParsedColor | null;
|
|
347
|
+
/**
|
|
348
|
+
* Lighten/darken a color by a flat per-channel delta. Used by the framework
|
|
349
|
+
* wrappers for tinted-overlay debug renderers; per-polygon Lambert shading
|
|
350
|
+
* goes through `computeShapeLighting` instead.
|
|
351
|
+
*/
|
|
352
|
+
declare function shadeColor(base: string, delta: number): string;
|
|
353
|
+
/**
|
|
354
|
+
* Per-polygon Lambert shading. Given a polygon's outward normal and the
|
|
355
|
+
* scene's lights, returns the shaded color as a CSS rgb string.
|
|
356
|
+
*
|
|
357
|
+
* Math (decoupled, three.js convention):
|
|
358
|
+
* tint = ambient.color · ambient.intensity
|
|
359
|
+
* + directional.color · directional.intensity · max(0, n · (−L))
|
|
360
|
+
* final = baseColor × tint
|
|
361
|
+
*
|
|
362
|
+
* Pass `directional` and/or `ambient` undefined to fall back to defaults
|
|
363
|
+
* (top-down white directional with intensity 1, white ambient with
|
|
364
|
+
* intensity 0.4) — useful for static SSR/validator renders.
|
|
365
|
+
*/
|
|
366
|
+
declare function computeShapeLighting(normal: Vec3, baseColor: string, directional?: PolyDirectionalLight, ambient?: PolyAmbientLight): string;
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Merge coplanar same-color adjacent triangles into N-vertex polygons.
|
|
370
|
+
*
|
|
371
|
+
* Each polygon is rendered as one atlas-backed DOM element — so a mesh whose
|
|
372
|
+
* triangles came from quads or pentagons collapses back into its original
|
|
373
|
+
* face count.
|
|
374
|
+
*
|
|
375
|
+
* - Geodesic spheres: ~half the triangles came from quad subdivisions
|
|
376
|
+
* - OBJ imports: many were quads/n-gons fan-triangulated by the importer
|
|
377
|
+
* - Hand-built dodecahedra: 36 triangles → 12 pentagons
|
|
378
|
+
*
|
|
379
|
+
* Algorithm:
|
|
380
|
+
* 1. For each input polygon, compute its plane (unit normal + signed
|
|
381
|
+
* distance from origin).
|
|
382
|
+
* 2. Build an undirected edge graph: every edge of every polygon indexes
|
|
383
|
+
* the polygons it belongs to.
|
|
384
|
+
* 3. Repeatedly walk shared edges and merge the two polygons sharing that
|
|
385
|
+
* edge if they pass the merge predicate (same color, near-coplanar,
|
|
386
|
+
* result is convex, edge is interior). Each merge replaces two
|
|
387
|
+
* polygons with one larger polygon and updates the edge index.
|
|
388
|
+
* 4. Iterate until no more merges fire — the fixed point grows triangles
|
|
389
|
+
* → quads → pentagons → … as far as the geometry allows.
|
|
390
|
+
*
|
|
391
|
+
* Polygons with < 3 vertices are passed through unchanged (the caller is
|
|
392
|
+
* expected to have run `normalizePolygons` first; this is a defensive copy).
|
|
393
|
+
*/
|
|
394
|
+
|
|
395
|
+
declare function mergePolygons(input: Polygon[]): Polygon[];
|
|
396
|
+
|
|
397
|
+
interface CoverPlanarPolygonsOptions {
|
|
398
|
+
/** Smallest connected coplanar group worth attempting. Default 4. */
|
|
399
|
+
minGroupPolygons?: number;
|
|
400
|
+
/** Maximum candidate 2D axes tested per group. Default 8. */
|
|
401
|
+
maxCandidateAxes?: number;
|
|
402
|
+
/** Plane normal/distance tolerance in scene units. Default 1e-3. */
|
|
403
|
+
planeEpsilon?: number;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Re-cover flat same-color mesh regions with generated convex polygons.
|
|
407
|
+
*
|
|
408
|
+
* `mergePolygons` preserves source topology: it can only combine existing
|
|
409
|
+
* neighboring faces. This pass is more aggressive for solid-color planar
|
|
410
|
+
* regions: it projects each connected coplanar patch into 2D, covers the
|
|
411
|
+
* patch from its outer boundary, then lets `mergePolygons` collapse the
|
|
412
|
+
* generated cover into large rects/quads where possible.
|
|
413
|
+
*/
|
|
414
|
+
declare function coverPlanarPolygons(input: Polygon[], options?: CoverPlanarPolygonsOptions): Polygon[];
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* cullInteriorPolygons — remove polygons that are fully enclosed by other
|
|
418
|
+
* polygons of the same mesh and therefore never visible from any external
|
|
419
|
+
* camera direction.
|
|
420
|
+
*
|
|
421
|
+
* Algorithm: for each polygon p,
|
|
422
|
+
* 1. Sample K unit directions on the hemisphere above p's normal.
|
|
423
|
+
* 2. Cast a ray from a point just above p's centroid in each direction.
|
|
424
|
+
* 3. If at least one ray escapes without hitting any other polygon → p
|
|
425
|
+
* is potentially visible from some external camera → keep it.
|
|
426
|
+
* 4. If every ray hits another polygon → p is fully surrounded → cull it.
|
|
427
|
+
*
|
|
428
|
+
* Acceleration: flat-array SAH-built binary BVH with slab-test AABB traversal.
|
|
429
|
+
* All BVH data is stored in typed Float64Array / Int32Array for cache efficiency.
|
|
430
|
+
* Ray traversal visits only the subtrees whose AABBs the ray intersects.
|
|
431
|
+
*
|
|
432
|
+
* Runs once at parse time inside `loadMesh`, before `mergePolygons`. Zero
|
|
433
|
+
* runtime cost. Conservative by design — false negatives (failing to cull
|
|
434
|
+
* a truly hidden poly) are safe; false positives would be a visual bug.
|
|
435
|
+
*/
|
|
436
|
+
|
|
437
|
+
interface CullInteriorOptions {
|
|
438
|
+
/** Hemisphere ray samples per polygon. Higher = fewer false positives, slower. Default 12. */
|
|
439
|
+
samples?: number;
|
|
440
|
+
}
|
|
441
|
+
declare function cullInteriorPolygons(polygons: Polygon[], options?: CullInteriorOptions): Polygon[];
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Geometry for the three.js-style debug axes gizmo: three thin colored
|
|
445
|
+
* cuboids stretching along world-X, world-Y and world-Z. Mirrors the
|
|
446
|
+
* convention `red=X, green=Y, blue=Z`.
|
|
447
|
+
*
|
|
448
|
+
* Returned polygons are in the standard polycss world-space convention
|
|
449
|
+
* (`+X right, +Y forward, +Z up`). Wrap with the framework's PolyMesh /
|
|
450
|
+
* PolyScene equivalent to render.
|
|
451
|
+
*/
|
|
452
|
+
|
|
453
|
+
interface AxesHelperOptions {
|
|
454
|
+
/** Length of each axis bar in world units. */
|
|
455
|
+
size?: number;
|
|
456
|
+
/** Bar cross-section width as a fraction of `size`. */
|
|
457
|
+
thickness?: number;
|
|
458
|
+
/** When true, also draws bars in the −X / −Y / −Z direction. */
|
|
459
|
+
negative?: boolean;
|
|
460
|
+
/** X-axis bar color. */
|
|
461
|
+
xColor?: string;
|
|
462
|
+
/** Y-axis bar color. */
|
|
463
|
+
yColor?: string;
|
|
464
|
+
/** Z-axis bar color. */
|
|
465
|
+
zColor?: string;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Build the polygons for an AxesHelper-style gizmo. Three thin cuboids,
|
|
469
|
+
* one per world axis. Defaults match `<PolyAxesHelper>` in the framework
|
|
470
|
+
* packages.
|
|
471
|
+
*/
|
|
472
|
+
declare function axesHelperPolygons(options?: AxesHelperOptions): Polygon[];
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Geometry for a single 3D arrow: a thin axis-aligned cuboid shaft
|
|
476
|
+
* stretching from the origin along one signed axis, capped with a
|
|
477
|
+
* 4-sided pyramid head pointing further in that direction. Used as the
|
|
478
|
+
* drag handle for `<TransformControls>` — same primitive recipe as
|
|
479
|
+
* `axesHelperPolygons`, plus an arrowhead.
|
|
480
|
+
*
|
|
481
|
+
* Returned polygons are in standard polycss world space and intended
|
|
482
|
+
* to be wrapped in the framework's PolyMesh equivalent for rendering.
|
|
483
|
+
*/
|
|
484
|
+
|
|
485
|
+
interface ArrowPolygonsOptions {
|
|
486
|
+
/** World axis the arrow extends along: 0=X, 1=Y, 2=Z. */
|
|
487
|
+
axis: 0 | 1 | 2;
|
|
488
|
+
/** Direction along the axis: +1 (positive) or -1 (negative). Default +1. */
|
|
489
|
+
sign?: 1 | -1;
|
|
490
|
+
/** Length of the rectangular shaft along the axis. */
|
|
491
|
+
shaftLength?: number;
|
|
492
|
+
/** Half cross-section of the shaft (perpendicular to the axis). */
|
|
493
|
+
shaftHalfThickness?: number;
|
|
494
|
+
/** Length of the pyramid head along the axis (extends past the shaft). */
|
|
495
|
+
headLength?: number;
|
|
496
|
+
/** Half-extent of the pyramid base. */
|
|
497
|
+
headHalfThickness?: number;
|
|
498
|
+
/** Fill color. */
|
|
499
|
+
color?: string;
|
|
500
|
+
}
|
|
501
|
+
/** Build the polygons for one signed-axis arrow. */
|
|
502
|
+
declare function arrowPolygons(options: ArrowPolygonsOptions): Polygon[];
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Geometry for a flat ring (annulus) lying in the plane perpendicular
|
|
506
|
+
* to a chosen axis. Used as the rotation handle in
|
|
507
|
+
* `<TransformControls mode="rotate">` — three rings, one per axis,
|
|
508
|
+
* each draggable to rotate the target around that axis.
|
|
509
|
+
*
|
|
510
|
+
* The ring is a sequence of quad segments around a circle. We don't
|
|
511
|
+
* model a true torus (tube) — a flat annulus reads cleanly as a
|
|
512
|
+
* "rotation circle" and keeps the polygon count proportional to the
|
|
513
|
+
* `segments` knob.
|
|
514
|
+
*
|
|
515
|
+
* Returned polygons are in standard polycss world space and intended
|
|
516
|
+
* to be wrapped in the framework's PolyMesh equivalent for rendering.
|
|
517
|
+
*/
|
|
518
|
+
|
|
519
|
+
interface RingPolygonsOptions {
|
|
520
|
+
/** World axis the ring is perpendicular to: 0=X, 1=Y, 2=Z. The ring
|
|
521
|
+
* itself lies in the plane spanned by the other two axes. */
|
|
522
|
+
axis: 0 | 1 | 2;
|
|
523
|
+
/** Mid-radius of the ring (distance from center to the middle of
|
|
524
|
+
* the annulus band). */
|
|
525
|
+
radius: number;
|
|
526
|
+
/** Half-width of the annulus band — the ring spans `radius - half`
|
|
527
|
+
* to `radius + half`. */
|
|
528
|
+
halfThickness?: number;
|
|
529
|
+
/** Number of quad segments around the circle. Higher = smoother. */
|
|
530
|
+
segments?: number;
|
|
531
|
+
/** Fill color. */
|
|
532
|
+
color?: string;
|
|
533
|
+
}
|
|
534
|
+
/** Build the polygons for a flat ring (annulus). */
|
|
535
|
+
declare function ringPolygons(options: RingPolygonsOptions): Polygon[];
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Geometry for a small solid-color octahedron — the marker shape used by
|
|
539
|
+
* `PolyDirectionalLightHelper` to indicate where a directional light is
|
|
540
|
+
* shining from. Eight CCW-from-outside triangular faces, vertices at
|
|
541
|
+
* `center ± (size, 0, 0)` etc.
|
|
542
|
+
*/
|
|
543
|
+
|
|
544
|
+
interface OctahedronPolygonsOptions {
|
|
545
|
+
/** Center of the octahedron in world space. */
|
|
546
|
+
center: Vec3;
|
|
547
|
+
/** Half-extent (distance from center to each pole vertex). */
|
|
548
|
+
size: number;
|
|
549
|
+
/** Fill color applied to all eight faces. */
|
|
550
|
+
color?: string;
|
|
551
|
+
}
|
|
552
|
+
declare function octahedronPolygons(options: OctahedronPolygonsOptions): Polygon[];
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Unified parser return type. All polygon-emitting parsers (parseObj,
|
|
556
|
+
* parseGltf, the loadMesh dispatcher) return this exact shape.
|
|
557
|
+
*
|
|
558
|
+
* The asymmetric helper `parseMtl` returns its own `MtlParseResult` (it
|
|
559
|
+
* emits materials, not polygons) — see parseMtl.ts for the rationale.
|
|
560
|
+
*
|
|
561
|
+
* Lifecycle contract: callers MUST call `dispose()` when the result is no
|
|
562
|
+
* longer needed. Idempotent — safe to call on unmount even if `objectUrls`
|
|
563
|
+
* is empty (e.g. `parseObj`, where it's a no-op).
|
|
564
|
+
*/
|
|
565
|
+
|
|
566
|
+
interface ParseAnimationClip {
|
|
567
|
+
/** Stable numeric index in the source file's animation array. */
|
|
568
|
+
index: number;
|
|
569
|
+
/** Human-readable clip name. Falls back to `animation_N` when omitted. */
|
|
570
|
+
name: string;
|
|
571
|
+
/** Clip duration in seconds, derived from its sampler input accessors. */
|
|
572
|
+
duration: number;
|
|
573
|
+
/** Number of glTF animation channels in the clip. */
|
|
574
|
+
channelCount: number;
|
|
575
|
+
}
|
|
576
|
+
interface ParseAnimationController {
|
|
577
|
+
/** Animation clips exposed by the parsed mesh. Empty when none are usable. */
|
|
578
|
+
clips: ParseAnimationClip[];
|
|
579
|
+
/**
|
|
580
|
+
* Sample a clip at `timeSeconds` and return a fresh polygon list.
|
|
581
|
+
* `clip` accepts either the clip index or its name. Time wraps by duration.
|
|
582
|
+
*/
|
|
583
|
+
sample: (clip: number | string, timeSeconds: number) => Polygon[];
|
|
584
|
+
}
|
|
585
|
+
interface ParseResult {
|
|
586
|
+
/** The mesh, as a flat polygon list. Already vertex-permuted to polycss space. */
|
|
587
|
+
polygons: Polygon[];
|
|
588
|
+
/** Optional animation sampler for formats that carry timeline data. */
|
|
589
|
+
animation?: ParseAnimationController;
|
|
590
|
+
/**
|
|
591
|
+
* Blob/object URLs minted during parse (e.g. embedded GLB images). Pass-by-
|
|
592
|
+
* reference — the same array is exposed on the result for visibility, and
|
|
593
|
+
* `dispose()` revokes each one. Do NOT mutate this array externally.
|
|
594
|
+
*/
|
|
595
|
+
objectUrls: string[];
|
|
596
|
+
/**
|
|
597
|
+
* Idempotent — revokes object URLs. Safe to call on unmount, safe to call
|
|
598
|
+
* twice. Parsers without minted URLs (parseObj, parseMtl) supply a no-op.
|
|
599
|
+
*/
|
|
600
|
+
dispose: () => void;
|
|
601
|
+
/**
|
|
602
|
+
* Non-fatal warnings raised during parse. Empty for parsers that don't
|
|
603
|
+
* have a warning channel; populated when downstream `normalizePolygons`
|
|
604
|
+
* is invoked through the high-level pipeline.
|
|
605
|
+
*/
|
|
606
|
+
warnings: string[];
|
|
607
|
+
/** Optional format-specific metadata. */
|
|
608
|
+
metadata?: {
|
|
609
|
+
/** Triangle count after fan-triangulation (parseObj) or post-triangulation (parseGltf). */
|
|
610
|
+
triangleCount?: number;
|
|
611
|
+
/** Mesh names from the file (for glTF, from doc.meshes[].name). */
|
|
612
|
+
meshes?: string[];
|
|
613
|
+
/** Material names (in first-seen order). */
|
|
614
|
+
materials?: string[];
|
|
615
|
+
/** Animation clips from the file, mirrored from `animation.clips`. */
|
|
616
|
+
animations?: ParseAnimationClip[];
|
|
617
|
+
/** Source file size in bytes (for diagnostics). */
|
|
618
|
+
sourceBytes?: number;
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* PolyAnimationMixer — three.js-shaped animation API for polycss.
|
|
624
|
+
*
|
|
625
|
+
* Mirrors three.js's AnimationMixer + AnimationAction surface closely enough
|
|
626
|
+
* that users familiar with drei's `useAnimations` can migrate without friction.
|
|
627
|
+
*
|
|
628
|
+
* Loop mode constants match three.js numeric values exactly:
|
|
629
|
+
* LoopOnce = 2200, LoopRepeat = 2201, LoopPingPong = 2202
|
|
630
|
+
*/
|
|
631
|
+
|
|
632
|
+
declare const LoopOnce: 2200;
|
|
633
|
+
declare const LoopRepeat: 2201;
|
|
634
|
+
declare const LoopPingPong: 2202;
|
|
635
|
+
type LoopMode = typeof LoopOnce | typeof LoopRepeat | typeof LoopPingPong;
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Minimal target interface the mixer requires. `PolyMeshHandle` from both
|
|
639
|
+
* the polycss vanilla API and the React/Vue frameworks satisfies this
|
|
640
|
+
* structurally — no import needed.
|
|
641
|
+
*/
|
|
642
|
+
interface PolyAnimationTarget {
|
|
643
|
+
setPolygons(polygons: Polygon[]): void;
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Per-clip playback action. Mirrors three.js `AnimationAction` method surface.
|
|
647
|
+
* All mutating methods return `this` for chaining.
|
|
648
|
+
*/
|
|
649
|
+
interface PolyAnimationAction {
|
|
650
|
+
/** Start playing (sets weight=1, resets time if not already playing). */
|
|
651
|
+
play(): PolyAnimationAction;
|
|
652
|
+
/** Stop playing and reset time to 0. */
|
|
653
|
+
stop(): PolyAnimationAction;
|
|
654
|
+
/** Reset time to 0 without stopping. */
|
|
655
|
+
reset(): PolyAnimationAction;
|
|
656
|
+
/** Fade weight from 0 to 1 over `durationSeconds`. */
|
|
657
|
+
fadeIn(durationSeconds: number): PolyAnimationAction;
|
|
658
|
+
/** Fade weight from current to 0 over `durationSeconds`. */
|
|
659
|
+
fadeOut(durationSeconds: number): PolyAnimationAction;
|
|
660
|
+
/**
|
|
661
|
+
* Cross-fade from this action to `target` over `durationSeconds`.
|
|
662
|
+
* Fades this out and target in simultaneously.
|
|
663
|
+
*/
|
|
664
|
+
crossFadeTo(target: PolyAnimationAction, durationSeconds: number): PolyAnimationAction;
|
|
665
|
+
/**
|
|
666
|
+
* Cross-fade from `from` into this action over `durationSeconds`.
|
|
667
|
+
* Sugar for `from.fadeOut(d); this.fadeIn(d)`.
|
|
668
|
+
*/
|
|
669
|
+
crossFadeFrom(from: PolyAnimationAction, durationSeconds: number): PolyAnimationAction;
|
|
670
|
+
/** Set loop mode and repetition count. */
|
|
671
|
+
setLoop(mode: LoopMode, repetitions: number): PolyAnimationAction;
|
|
672
|
+
/** Override the effective time scale. */
|
|
673
|
+
setEffectiveTimeScale(scale: number): PolyAnimationAction;
|
|
674
|
+
/** Override the effective weight. */
|
|
675
|
+
setEffectiveWeight(weight: number): PolyAnimationAction;
|
|
676
|
+
/** When true, the action freezes on the last frame after finishing. */
|
|
677
|
+
clampWhenFinished: boolean;
|
|
678
|
+
/** Playback speed multiplier. Default 1. */
|
|
679
|
+
timeScale: number;
|
|
680
|
+
/** Blend weight [0, 1]. Default 1. */
|
|
681
|
+
weight: number;
|
|
682
|
+
/** Current playback position in seconds. */
|
|
683
|
+
time: number;
|
|
684
|
+
/**
|
|
685
|
+
* When false, the action contributes 0 weight to the blend even if
|
|
686
|
+
* `weight > 0`. Time still advances. Default true.
|
|
687
|
+
*/
|
|
688
|
+
enabled: boolean;
|
|
689
|
+
/**
|
|
690
|
+
* When true, time does NOT advance on `mixer.update()` but the action
|
|
691
|
+
* remains active and contributes its current weight to the blend. Default false.
|
|
692
|
+
*/
|
|
693
|
+
paused: boolean;
|
|
694
|
+
/** Whether the action is currently playing. */
|
|
695
|
+
readonly isRunning: boolean;
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Drives one or more `PolyAnimationAction`s against a single mesh target.
|
|
699
|
+
* Mirrors the three.js `AnimationMixer` API.
|
|
700
|
+
*/
|
|
701
|
+
interface PolyAnimationMixer {
|
|
702
|
+
/**
|
|
703
|
+
* Return the action for a clip (by index or name). Creates the action if it
|
|
704
|
+
* doesn't exist yet (lazy instantiation, same as three.js).
|
|
705
|
+
*/
|
|
706
|
+
clipAction(clip: number | string): PolyAnimationAction;
|
|
707
|
+
/**
|
|
708
|
+
* Return an existing action without creating one. Returns null if the
|
|
709
|
+
* action hasn't been instantiated yet.
|
|
710
|
+
*/
|
|
711
|
+
existingAction(clip: number | string): PolyAnimationAction | null;
|
|
712
|
+
/**
|
|
713
|
+
* Advance all active actions by `deltaSeconds` and apply the resulting
|
|
714
|
+
* polygon frame to the root target. Call this once per animation frame.
|
|
715
|
+
*/
|
|
716
|
+
update(deltaSeconds: number): void;
|
|
717
|
+
/** Stop all active actions. */
|
|
718
|
+
stopAllAction(): void;
|
|
719
|
+
/** Remove a cached action for `clip`. */
|
|
720
|
+
uncacheClip(clip: number | string): void;
|
|
721
|
+
/** Remove all cached actions for this mixer's root. */
|
|
722
|
+
uncacheRoot(): void;
|
|
723
|
+
}
|
|
724
|
+
declare function createPolyAnimationMixer(root: PolyAnimationTarget, controller: ParseAnimationController): PolyAnimationMixer;
|
|
725
|
+
|
|
726
|
+
interface ObjParseOptions {
|
|
727
|
+
/**
|
|
728
|
+
* Largest mesh extent (in scene-space units). The mesh is uniformly
|
|
729
|
+
* scaled so its longest bbox dimension equals this. Default: 60.
|
|
730
|
+
*/
|
|
731
|
+
targetSize?: number;
|
|
732
|
+
/**
|
|
733
|
+
* Padding added to the bbox of every emitted polygon so they don't land
|
|
734
|
+
* at coordinate "0". Default: 1.
|
|
735
|
+
*/
|
|
736
|
+
gridShift?: number;
|
|
737
|
+
/**
|
|
738
|
+
* Color used for faces that have no `usemtl` in scope, or whose material
|
|
739
|
+
* name doesn't resolve via `materialColors`. Default: "#888888".
|
|
740
|
+
*/
|
|
741
|
+
defaultColor?: string;
|
|
742
|
+
/**
|
|
743
|
+
* Override map: material name → CSS color string. Falls back to:
|
|
744
|
+
* 1. The material name interpreted as a 6-char hex (e.g. "FF9800" → "#FF9800"),
|
|
745
|
+
* 2. Otherwise a slot from `palette` indexed by first-seen material order,
|
|
746
|
+
* 3. Otherwise `defaultColor`.
|
|
747
|
+
*/
|
|
748
|
+
materialColors?: Record<string, string>;
|
|
749
|
+
/**
|
|
750
|
+
* Optional map: material name → texture URL. When set, every triangle
|
|
751
|
+
* emitted under that material gets `texture` populated. The renderer
|
|
752
|
+
* stamps the image across the triangle's local 2D plane.
|
|
753
|
+
*/
|
|
754
|
+
materialTextures?: Record<string, string>;
|
|
755
|
+
/**
|
|
756
|
+
* Palette used to assign colors to materials whose names aren't hex.
|
|
757
|
+
* Each new non-hex material name takes the next palette slot.
|
|
758
|
+
*/
|
|
759
|
+
palette?: string[];
|
|
760
|
+
/**
|
|
761
|
+
* Names of `o <name>` objects to KEEP. When set, faces outside these
|
|
762
|
+
* objects are dropped.
|
|
763
|
+
*/
|
|
764
|
+
includeObjects?: string[];
|
|
765
|
+
/**
|
|
766
|
+
* Names of `o <name>` objects to DROP. Applied after `includeObjects`.
|
|
767
|
+
* Faces with no enclosing `o` line are kept unless `includeObjects` is set.
|
|
768
|
+
*/
|
|
769
|
+
excludeObjects?: string[];
|
|
770
|
+
}
|
|
771
|
+
declare function parseObj(text: string, options?: ObjParseOptions): ParseResult;
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Wavefront `.mtl` material file parser. Companion to parseObj — reads the
|
|
775
|
+
* material library that ships next to a `.obj` and returns per-material
|
|
776
|
+
* diffuse color (`Kd`) and optional diffuse texture map path (`map_Kd`).
|
|
777
|
+
*
|
|
778
|
+
* Usage:
|
|
779
|
+
* const mtl = await fetch("/foo.mtl").then(r => r.text());
|
|
780
|
+
* const { colors, textures } = parseMtl(mtl);
|
|
781
|
+
* const obj = await fetch("/foo.obj").then(r => r.text());
|
|
782
|
+
* const { polygons } = parseObj(obj, { materialColors: colors, materialTextures: textures });
|
|
783
|
+
*
|
|
784
|
+
* Texture paths are returned exactly as written in the .mtl — relative paths,
|
|
785
|
+
* Windows backslashes etc. are not normalized. Callers are expected to
|
|
786
|
+
* resolve them against the .mtl's base URL.
|
|
787
|
+
*
|
|
788
|
+
* NOTE: parseMtl intentionally returns its own `MtlParseResult` shape
|
|
789
|
+
* (NOT the unified `ParseResult`). It's an asymmetric helper — it emits
|
|
790
|
+
* materials, not polygons — and forcing it into ParseResult would mean
|
|
791
|
+
* an empty `polygons[]` and a misleading `dispose()`.
|
|
792
|
+
*/
|
|
793
|
+
interface MtlParseResult {
|
|
794
|
+
/** Material name → CSS hex color (from `Kd r g b`). */
|
|
795
|
+
colors: Record<string, string>;
|
|
796
|
+
/** Material name → texture path (from `map_Kd <path>`). Path is unresolved. */
|
|
797
|
+
textures: Record<string, string>;
|
|
798
|
+
}
|
|
799
|
+
declare function parseMtl(text: string): MtlParseResult;
|
|
800
|
+
|
|
801
|
+
interface GltfParseOptions {
|
|
802
|
+
/** Largest mesh extent (units). Mesh is uniformly scaled to fit. Default 60. */
|
|
803
|
+
targetSize?: number;
|
|
804
|
+
/** Padding offset (avoids coordinate "0"). Default 1. */
|
|
805
|
+
gridShift?: number;
|
|
806
|
+
/** Color used when a primitive has no material or no baseColorFactor. */
|
|
807
|
+
defaultColor?: string;
|
|
808
|
+
/**
|
|
809
|
+
* Override map: glTF material name → CSS color string. Falls back to the
|
|
810
|
+
* material's `pbrMetallicRoughness.baseColorFactor` if not in this map.
|
|
811
|
+
*/
|
|
812
|
+
materialColors?: Record<string, string>;
|
|
813
|
+
/**
|
|
814
|
+
* Which axis is "up" in the source mesh.
|
|
815
|
+
* - "y" (default, glTF spec): cyclic permutation (x,y,z) → (z,x,y) so
|
|
816
|
+
* +Y ends up on polycss's +Z (elevation).
|
|
817
|
+
* - "z" (Blender-style, FBX2glTF often emits this): identity, no swap.
|
|
818
|
+
* Pick "z" if the model lands on its side / lies down instead of
|
|
819
|
+
* standing.
|
|
820
|
+
*/
|
|
821
|
+
upAxis?: "y" | "z";
|
|
822
|
+
/**
|
|
823
|
+
* For .gltf (non-binary) — resolve a glTF buffer URI to its bytes. The
|
|
824
|
+
* built-in parser handles GLB binary chunks natively; .gltf files with
|
|
825
|
+
* external .bin files need this.
|
|
826
|
+
*/
|
|
827
|
+
resolveBuffer?: (uri: string) => Promise<Uint8Array> | Uint8Array;
|
|
828
|
+
/**
|
|
829
|
+
* Base URL the source file lives at. Used to resolve external image URIs
|
|
830
|
+
* (`doc.images[i].uri = "Textures/foo.png"`) against the GLB/glTF's
|
|
831
|
+
* location. Without this, relative URIs would resolve against the page,
|
|
832
|
+
* which 404s. Pass the same URL you fetched the file from.
|
|
833
|
+
*/
|
|
834
|
+
baseUrl?: string;
|
|
835
|
+
}
|
|
836
|
+
declare function parseGltf(input: ArrayBuffer | Uint8Array, options?: GltfParseOptions): ParseResult;
|
|
837
|
+
|
|
838
|
+
interface SolidTextureSampleOptions {
|
|
839
|
+
/**
|
|
840
|
+
* Set false to keep every textured polygon texture-backed. Defaults to true
|
|
841
|
+
* when a browser-like Image + canvas environment is available.
|
|
842
|
+
*/
|
|
843
|
+
enabled?: boolean;
|
|
844
|
+
/** Per-channel tolerance for declaring sampled texels uniform. Default 2. */
|
|
845
|
+
colorTolerance?: number;
|
|
846
|
+
/** Skip decoding very large textures for this optimization. Default 16 MP. */
|
|
847
|
+
maxTexturePixels?: number;
|
|
848
|
+
}
|
|
849
|
+
declare function bakeSolidTextureSampledPolygons(polygons: Polygon[], options?: SolidTextureSampleOptions): Promise<Polygon[]>;
|
|
850
|
+
declare function bakeSolidTextureSamples(result: ParseResult, options?: SolidTextureSampleOptions): Promise<ParseResult>;
|
|
851
|
+
|
|
852
|
+
interface VoxParseOptions {
|
|
853
|
+
/**
|
|
854
|
+
* Largest mesh extent (in scene-space units). The mesh is uniformly
|
|
855
|
+
* scaled so its longest bbox dimension equals this. Default: 60.
|
|
856
|
+
*/
|
|
857
|
+
targetSize?: number;
|
|
858
|
+
/**
|
|
859
|
+
* Per-coordinate offset added after scaling. Keeps coordinates away from
|
|
860
|
+
* zero (matching OBJ/glTF parsers). Default: 0 — vox already starts at
|
|
861
|
+
* non-negative integers so zero makes sensible default.
|
|
862
|
+
*/
|
|
863
|
+
gridShift?: number;
|
|
864
|
+
}
|
|
865
|
+
declare function parseVox(buffer: ArrayBuffer, options?: VoxParseOptions): ParseResult;
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* loadMesh — high-level fetch+parse dispatcher. Picks the parser by file
|
|
869
|
+
* extension, fetches the URL, runs the parser, returns the unified
|
|
870
|
+
* `ParseResult`.
|
|
871
|
+
*
|
|
872
|
+
* Supported:
|
|
873
|
+
* - `.obj` → text fetch + `parseObj`
|
|
874
|
+
* - `.glb` → ArrayBuffer fetch + `parseGltf`
|
|
875
|
+
* - `.gltf` → ArrayBuffer fetch + `parseGltf` (caller may pass `baseUrl`)
|
|
876
|
+
* - `.vox` → ArrayBuffer fetch + `parseVox`
|
|
877
|
+
*
|
|
878
|
+
* `.mtl` is rejected — it's a material file, not a mesh. Use `parseMtl`
|
|
879
|
+
* directly if you want to read materials.
|
|
880
|
+
*
|
|
881
|
+
* Other extensions throw. Future formats (STL, PLY) plug in here.
|
|
882
|
+
*/
|
|
883
|
+
|
|
884
|
+
interface LoadMeshOptions {
|
|
885
|
+
/**
|
|
886
|
+
* Base URL for resolving relative texture/buffer URIs inside the mesh
|
|
887
|
+
* (passed through to `parseGltf` for embedded image extraction). When
|
|
888
|
+
* omitted, the URL passed to `loadMesh` is used as the base.
|
|
889
|
+
*/
|
|
890
|
+
baseUrl?: string;
|
|
891
|
+
/**
|
|
892
|
+
* Companion `.mtl` URL for OBJ files. When set, loadMesh fetches the
|
|
893
|
+
* mtl, runs `parseMtl`, and threads `materialColors` + `materialTextures`
|
|
894
|
+
* into `parseObj` — so the OBJ renders with its authored materials.
|
|
895
|
+
* Texture paths inside the mtl are resolved against the mtl URL.
|
|
896
|
+
* Ignored for `.glb` / `.gltf` (they carry materials inline).
|
|
897
|
+
*/
|
|
898
|
+
mtlUrl?: string;
|
|
899
|
+
/** Forwarded to `parseObj` (merged with materials derived from `mtlUrl`). */
|
|
900
|
+
objOptions?: ObjParseOptions;
|
|
901
|
+
/** Forwarded to `parseGltf`. */
|
|
902
|
+
gltfOptions?: GltfParseOptions;
|
|
903
|
+
/** Forwarded to `parseVox`. */
|
|
904
|
+
voxOptions?: VoxParseOptions;
|
|
905
|
+
/**
|
|
906
|
+
* Converts texture-backed faces whose UV samples are a uniform color into
|
|
907
|
+
* solid-color polygons before culling/merging. This avoids atlas sprites for
|
|
908
|
+
* low-poly models that use texture atlases as color swatches.
|
|
909
|
+
*/
|
|
910
|
+
solidTextureSamples?: boolean | SolidTextureSampleOptions;
|
|
911
|
+
}
|
|
912
|
+
declare function loadMesh(url: string, options?: LoadMeshOptions): Promise<ParseResult>;
|
|
913
|
+
|
|
914
|
+
export { type ArrowPolygonsOptions, type AutoRotateConfig, type AutoRotateOption, type AxesHelperOptions, BASE_TILE, type CameraHandle, type CameraState, type CameraStyleInput, type CoverPlanarPolygonsOptions, type CullInteriorOptions, DEFAULT_CAMERA_STATE, DEFAULT_PROJECTION, type GltfParseOptions, type LoadMeshOptions, type LoopMode, LoopOnce, LoopPingPong, LoopRepeat, type MtlParseResult, type NormalizeResult, type ObjParseOptions, type OctahedronPolygonsOptions, type ParseAnimationClip, type ParseAnimationController, type ParseResult, type ParsedColor, type PolyAmbientLight, type PolyAnimationAction, type ParseAnimationClip as PolyAnimationClip, type PolyAnimationMixer, type PolyAnimationTarget, type PolyDirectionalLight, type PolyMaterial, type PolyTextureLightingMode, type Polygon, type PolygonFace, type RingPolygonsOptions, type SceneBbox, type SceneContext, type SceneContextBuildArgs, type SceneContextBuildResult, type SolidTextureSampleOptions, type TexturePaintMetrics, type TexturePaintMetricsOptions, type TextureTriangle, type Vec2, type Vec3, type VoxParseOptions, arrowPolygons, axesHelperPolygons, bakeSolidTextureSampledPolygons, bakeSolidTextureSamples, buildSceneContext, clampChannel, computeSceneBbox, computeShapeLighting, computeTexturePaintMetrics, coverPlanarPolygons, createIsometricCamera, createPolyAnimationMixer, cullInteriorPolygons, formatColor, inverseRotateVec3, loadMesh, mergePolygons, normalizeInvertMultiplier, normalizePolygons, octahedronPolygons, parseColor, parseGltf, parseHexColor, parseMtl, parseObj, parsePureColor, parseRgbColor, parseVox, polygonFaces, ringPolygons, rotateVec3, shadeColor };
|