@toolpath/viewer 2.2.1 → 2.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.
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { Group, Mesh, LineSegments, Box3, Plane, BufferGeometry, Vector3, Raycaster, Object3D, Intersection, Camera } from 'three';
3
+ import { Vector3, OrthographicCamera, PerspectiveCamera, Box3, Object3D, BufferGeometry, Group, Mesh, LineSegments, Plane, Raycaster, Intersection, Camera } from 'three';
4
4
 
5
5
  /**
6
6
  * The normalized part — the only thing the renderer consumes.
@@ -151,6 +151,207 @@ interface FocusOptions {
151
151
  readonly opacity?: number;
152
152
  }
153
153
 
154
+ type Projection = 'orthographic' | 'perspective';
155
+ type ViewerCamera = OrthographicCamera | PerspectiveCamera;
156
+ interface ViewportSize {
157
+ readonly width: number;
158
+ readonly height: number;
159
+ }
160
+ /** Vertical field of view, in degrees, for the perspective camera. */
161
+ declare const PERSPECTIVE_FOV = 30;
162
+ /** Padding around the framed bounds, as a multiple of its radius. */
163
+ declare const DEFAULT_FIT_MARGIN = 1.2;
164
+ /** Marks scene furniture — grid, axes — that the camera should not frame. */
165
+ declare const EXCLUDE_FROM_FRAME = "viewerExcludeFromFrame";
166
+ /**
167
+ * What the camera frames: a bounding *sphere*, not a box.
168
+ *
169
+ * A sphere makes framing rotation-invariant — the part stays fully visible from
170
+ * every angle, and a resize never needs to know the current pose. Framing
171
+ * per-axis box dimensions instead means recomputing the camera distance on
172
+ * every resize, and still clipping on some orientations.
173
+ */
174
+ interface SceneBounds {
175
+ readonly center: Vector3;
176
+ readonly radius: number;
177
+ }
178
+ /**
179
+ * Bounds for a scene with nothing in it. A viewer is mounted before it has a
180
+ * part, and a camera with a zero-size frustum renders nothing at all.
181
+ */
182
+ declare function defaultBounds(): SceneBounds;
183
+ /**
184
+ * A container can be laid out at zero size, and a degenerate aspect ratio
185
+ * produces a `NaN` projection matrix that never recovers. Fall back to square.
186
+ */
187
+ declare function aspectRatio(size: ViewportSize): number;
188
+ /**
189
+ * A world length that covers `pixels` on screen at `point`.
190
+ *
191
+ * Anything sized in world units is a thumbnail on a plate and a wall on an
192
+ * insert; the whole reason a control is measured this way is that it is a
193
+ * control rather than part of the model. The section handle and the orbit
194
+ * target marker both size themselves with it, which is why it lives here with
195
+ * the camera rather than beside either of them.
196
+ *
197
+ * The two projections answer differently on purpose. An orthographic frustum
198
+ * covers the same world height wherever the point is, so distance does not
199
+ * enter; a perspective one covers more the further away it looks, so it does.
200
+ */
201
+ declare function screenLength(camera: ViewerCamera, point: Vector3, viewport: ViewportSize, pixels: number): number;
202
+ declare function boundsFromBox(box: Box3): SceneBounds;
203
+ /**
204
+ * The bounds of everything worth framing under `root`.
205
+ *
206
+ * Skips objects flagged with {@link EXCLUDE_FROM_FRAME} and their descendants:
207
+ * a 100 mm grid around a 6 mm part would otherwise frame the grid, and the part
208
+ * would be a speck.
209
+ */
210
+ declare function contentBounds(root: Object3D, into: Box3): SceneBounds;
211
+ /**
212
+ * Whether `object`, or anything between it and `root`, carries
213
+ * {@link EXCLUDE_FROM_FRAME}. The flag is set on an overlay's outermost group
214
+ * and means the whole subtree, so the walk goes up rather than reading the
215
+ * object alone.
216
+ */
217
+ declare function excludedFromFrame(object: Object3D, root: Object3D): boolean;
218
+ /**
219
+ * The distance at which a sphere of `radius` fits inside a perspective frustum.
220
+ * Uses the narrower of the two field-of-view angles, so a portrait viewport
221
+ * frames on width and a landscape one on height.
222
+ */
223
+ declare function perspectiveFitDistance(fovDegrees: number, aspect: number, radius: number): number;
224
+ /**
225
+ * Half-height of an orthographic frustum that fits a sphere of `radius`. A
226
+ * portrait viewport grows the height so the width still clears the sphere.
227
+ */
228
+ declare function orthographicHalfHeight(aspect: number, radius: number): number;
229
+ declare function fitDistance(projection: Projection, size: ViewportSize, bounds: SceneBounds, margin?: number): number;
230
+ declare function startPosition(projection: Projection, size: ViewportSize, bounds: SceneBounds, margin?: number): Vector3;
231
+ /**
232
+ * How far out the wheel may pull, as a fraction of the fitted framing: the part
233
+ * may shrink to a quarter of the view and no further. Past that it is a speck
234
+ * with no cue that Fit is the way back.
235
+ */
236
+ declare const MIN_FRAME_RATIO = 0.25;
237
+ /**
238
+ * How far in the wheel may push, as a multiple of the fitted framing.
239
+ *
240
+ * Both ratios are the legacy viewer's `minZoom` 0.25 / `maxZoom` 10
241
+ * (`three-object.tsx:289-311`), which transfer almost exactly: legacy's
242
+ * orthographic frustum was `largestDimension * 2` tall and this one is the
243
+ * fitted bounding sphere, which for a cube agree within a few percent. So the
244
+ * numbers are the ones that shipped, and here they carry a meaning they did not
245
+ * have there — `zoom` 1 *is* the fitted framing, so 0.25 and 10 say exactly
246
+ * what a reader thinks they say.
247
+ */
248
+ declare const MAX_FRAME_RATIO = 10;
249
+ /** How far the camera may travel, in the two units the two cameras travel in. */
250
+ interface CameraLimits {
251
+ readonly minZoom: number;
252
+ readonly maxZoom: number;
253
+ readonly minDistance: number;
254
+ readonly maxDistance: number;
255
+ }
256
+ /**
257
+ * The clamps for a scene, so the wheel cannot leave the viewport empty.
258
+ *
259
+ * Without them it can, from either end, and both cameras can do it: an
260
+ * orthographic `camera.zoom` reaches 1e30 in sixty notches, and a perspective
261
+ * camera dives inside the part in eight, because `minDistance` defaults to
262
+ * `Number.EPSILON`. Fit recovers from both — but Fit is a double middle click
263
+ * and nothing on screen says so, which makes it a way out rather than an
264
+ * answer.
265
+ *
266
+ * One rule for both cameras: the wheel may take the part from a quarter of its
267
+ * fitted size to ten times it. Under an orthographic camera that scale *is* the
268
+ * frustum, so the ratios land on `zoom`; under a perspective camera apparent
269
+ * size is the inverse of distance, so they land on `distance` — which is why
270
+ * they swap sides between the two.
271
+ *
272
+ * Pure, and derived from `bounds`, so it re-derives wherever the scene is
273
+ * re-measured rather than being sampled once at mount.
274
+ *
275
+ * `framed` is what the view has been framed *on*, when that is not the whole
276
+ * scene — `frameBox` on a single feature. The band is then taken about that
277
+ * framing as well as about the scene's, because a band centred on the part is
278
+ * the wrong band for a view of a 3 mm hole in it: ten times the *part's* fitted
279
+ * size can be less than once the hole's, so the framing the caller asked for sat
280
+ * outside the clamps meant to keep it in view. Under an orthographic camera
281
+ * `zoom` is measured against a frustum still sized to the scene, so the framing
282
+ * enters as the zoom ratio it takes to reach; under a perspective one it enters
283
+ * as its own fitted distance.
284
+ *
285
+ * Widened to the union of the two rather than moved onto `framed`, and that is
286
+ * the whole of why this takes both. A band that simply followed the last framing
287
+ * would take the part away: framing a hole would put "far enough out to see what
288
+ * the hole is in" past `maxDistance`, so the wheel could no longer get back to
289
+ * the part it had just been looking at, and Fit — a gesture with nothing on
290
+ * screen to say so — would be the only way. Reaching further in must not cost
291
+ * the reach back out, so each end takes whichever bound is looser. With no
292
+ * `framed`, or one the size of the scene, both ends collapse to the scene's own
293
+ * and this is the function it was before.
294
+ */
295
+ declare function cameraLimits(projection: Projection, size: ViewportSize, bounds: SceneBounds, margin?: number, framed?: SceneBounds): CameraLimits;
296
+ /**
297
+ * The box the orbit target is confined to — the fitted framing, several frames
298
+ * over. Written into `into` so the per-frame path allocates nothing.
299
+ */
300
+ declare function targetBoundary(bounds: SceneBounds, into: Box3, margin?: number): Box3;
301
+ /**
302
+ * Points an existing camera's frustum at `bounds` for the current viewport.
303
+ * Pose is untouched — that belongs to the controls.
304
+ */
305
+ declare function applyProjection(camera: ViewerCamera, size: ViewportSize, bounds: SceneBounds, margin?: number): void;
306
+ /**
307
+ * The world-up convention. The part data is Z-up (millimetres, no conversion) —
308
+ * not the glTF-conventional Y-up — so the camera has to say so explicitly.
309
+ */
310
+ declare const CAD_CAMERA_UP: Vector3;
311
+ /**
312
+ * `up` re-squared against a view direction: the part of it perpendicular to
313
+ * `view`, written into `into`.
314
+ *
315
+ * This is what keeps the horizon level while a free orbit carries the camera
316
+ * over a pole — the up vector follows the view instead of flipping. The
317
+ * controls run it on every update, which is what makes the next sentence the
318
+ * important one.
319
+ *
320
+ * **It is path-dependent.** It is a projection, so it discards the component it
321
+ * removes and cannot put it back: running it at one view and then another does
322
+ * not give what running it once at the second view would. So a camera carries
323
+ * the roll of every pose it has passed through, and any pose that is meant to
324
+ * be canonical — the opening frame, a reset, a named view — has to say what
325
+ * `up` is rather than inherit it. `viewer.tsx` does, at `resetContent`. The
326
+ * test beside this pins both halves.
327
+ *
328
+ * `into` may be `view` or `up` — three.js `crossVectors` reads all six
329
+ * components before it writes any, and the intermediate is this module's own
330
+ * scratch, so writing the result over an input is safe. Said here because this
331
+ * is exported and an out-parameter invites the question; the test beside this
332
+ * pins it, so a three.js change cannot quietly turn the answer around.
333
+ *
334
+ * `view` and `up` being parallel is the one degenerate case: their cross is
335
+ * zero, `normalize` leaves it zero, and the result is a zero vector rather than
336
+ * an error. A caller with a free-orbiting camera reaches that at the pole,
337
+ * which is what `freeOrbit` and a squared `up` at every canonical pose exist to
338
+ * keep it away from.
339
+ */
340
+ declare function adaptedUp(view: Vector3, up: Vector3, into: Vector3): Vector3;
341
+ /** Named viewing directions, as unit vectors from the part toward the camera. */
342
+ declare const cadViewDirections: {
343
+ readonly front: Vector3;
344
+ readonly back: Vector3;
345
+ readonly left: Vector3;
346
+ readonly right: Vector3;
347
+ readonly top: Vector3;
348
+ readonly bottom: Vector3;
349
+ readonly isometric: Vector3;
350
+ };
351
+ type ViewerView = keyof typeof cadViewDirections;
352
+ /** The current orbit direction, so Fit can retain the direction being looked from. */
353
+ declare function currentViewDirection(camera: ViewerCamera, target: Vector3, into: Vector3): Vector3;
354
+
154
355
  /**
155
356
  * Viewer colors.
156
357
  *
@@ -182,6 +383,8 @@ interface ViewerTheme {
182
383
  /** `EdgesGeometry` line color and opacity. */
183
384
  readonly edge: number;
184
385
  readonly edgeOpacity: number;
386
+ /** The sharp corners `<PartMesh sharpCorners>` draws. */
387
+ readonly sharpCorner: number;
185
388
  /**
186
389
  * The capped face of a section cut: its fill, and the hatch lines drawn over
187
390
  * it. The cap's edge takes {@link ViewerTheme.sectionHandleOutline}.
@@ -249,6 +452,100 @@ declare function themesEqual(a: ViewerTheme, b: ViewerTheme): boolean;
249
452
  /** The color for a candidate direction, wrapping at {@link DIRECTION_COLORS}. */
250
453
  declare function directionColor(index: number): number;
251
454
 
455
+ /**
456
+ * Every place two surfaces of the part meet, with how sharply and which way
457
+ * they fold there, and the two regions either side.
458
+ *
459
+ * This finds edges; it does not judge them. Which corners are a problem is the
460
+ * DFM rules' call, from the Engine's measurements (see
461
+ * {@link SharpCornerOptions.features}) — geometry alone calls every hole's rim
462
+ * and every stud's base sharp, and neither is anything an end mill minds. What
463
+ * the mesh contributes is *where*: the exact edges to draw for a feature the
464
+ * rules have already flagged.
465
+ *
466
+ * The walk is the one `regionEdgesGeometry` makes — an edge between two visual
467
+ * surfaces is a real edge of the part, an edge inside one is tessellation — and
468
+ * then each such edge is measured from the two triangles either side of it:
469
+ *
470
+ * - **The angle** between their normals. A fillet or a blend meets its
471
+ * neighbours tangentially, so it reads near 0°; a square shoulder reads 90°.
472
+ * On real Engine parts the two populations do not overlap — creases sit at
473
+ * 60–100°, tangent seams under 10°.
474
+ * - **Which way it folds.** Concave where each triangle's far corner stands in
475
+ * front of the other's plane: an inside corner.
476
+ *
477
+ * Endpoints are matched by **quantised position** — `keyFor`, the key
478
+ * `regionAdjacency` uses, so the two agree on a shared vertex — not by exact
479
+ * float: the two triangles either side of an edge belong to two
480
+ * surfaces tessellated separately, and the pairing is the whole measurement.
481
+ * The Engine's meshes are watertight — every edge on the parts measured is met
482
+ * by exactly two triangles — so an edge met once is a hole in a mesh from
483
+ * somewhere else and is skipped, and one met a third time keeps the first pair.
484
+ *
485
+ * The mesh must be non-indexed, which `parsePartGeometry` guarantees.
486
+ */
487
+ interface SurfaceCreases {
488
+ /** How many segments. */
489
+ readonly count: number;
490
+ /** Each segment's two endpoints, `x y z x y z`, in the geometry's own space. */
491
+ readonly positions: Float32Array;
492
+ /** Degrees between the two faces' normals: 0 is smooth, 90 is square. */
493
+ readonly angles: Float32Array;
494
+ /** 1 where the surfaces fold inward — an inside corner — and 0 where they fold outward. */
495
+ readonly concave: Uint8Array;
496
+ /** The region `idx` either side of each segment, two to a segment; `-1` for a triangle in none. */
497
+ readonly regions: Int32Array;
498
+ /**
499
+ * The far corner of the triangle either side of each segment, `x y z x y z`:
500
+ * which way each face runs on from the corner, and how far.
501
+ */
502
+ readonly fars: Float32Array;
503
+ }
504
+ interface SharpCornerOptions {
505
+ /**
506
+ * The features the DFM rules flag with a sharp corner — those whose
507
+ * `featureSheet(datasheet).sharpCorners` is set, from `@toolpath/dfm/model`.
508
+ * Each one's inside corners that run along its machining direction are
509
+ * drawn: the vertical corners between its walls that no end mill makes.
510
+ * Nothing else is. Tags are matched without regard to case.
511
+ */
512
+ readonly features: readonly FeatureTag[];
513
+ }
514
+ /** Finds and measures every crease between two visual surfaces. See {@link SurfaceCreases}. */
515
+ declare function surfaceCreases(geometry: BufferGeometry, model: Pick<PartModel, 'regions'>): SurfaceCreases;
516
+ /**
517
+ * One sharp corner the DFM rules flag, as drawn: a run of crease segments end
518
+ * to end along its feature's machining direction — usually one, more where the
519
+ * mesh splits the corner.
520
+ */
521
+ interface SharpCorner {
522
+ /** Its place among the part's corners, stable while the flagged features are. */
523
+ readonly index: number;
524
+ /** The flagged feature it belongs to, as the part model spells the tag. */
525
+ readonly feature: FeatureTag;
526
+ /** Its two ends, in the part's own space. */
527
+ readonly start: Vec3;
528
+ readonly end: Vec3;
529
+ /** How far it runs, mm: as deep as a tool would have to reach to make it. */
530
+ readonly length: number;
531
+ /** The angle between the two faces that meet in it, degrees: 90 for a square corner. */
532
+ readonly angle: number;
533
+ /** The regions either side of it. */
534
+ readonly regions: readonly number[];
535
+ /** Its segments, as indices into the {@link SurfaceCreases} it was found in. */
536
+ readonly segments: readonly number[];
537
+ }
538
+ /**
539
+ * The flagged features' corners: each inside crease with a flagged feature's
540
+ * face on either side of it, running along that feature's machining direction,
541
+ * joined end to end into whole corners. A floor meeting a wall square is a
542
+ * flat end mill's ordinary work, and runs across the direction rather than
543
+ * along it.
544
+ */
545
+ declare function findSharpCorners(creases: SurfaceCreases, model: Pick<PartModel, 'features' | 'regionIndex'>, options: SharpCornerOptions): SharpCorner[];
546
+ /** The flagged features' corners, as `x y z x y z` endpoint pairs. See {@link findSharpCorners}. */
547
+ declare function sharpCornerPositions(creases: SurfaceCreases, model: Pick<PartModel, 'features' | 'regionIndex'>, options: SharpCornerOptions): Float32Array;
548
+
252
549
  /** The vertex attribute carrying each vertex's column in the state texture. */
253
550
  declare const REGION_ATTRIBUTE = "aRegion";
254
551
  type PartDisplay = 'solid' | 'wireframe';
@@ -295,6 +592,24 @@ interface PartObject {
295
592
  setTheme(theme: ViewerTheme): void;
296
593
  /** Semantic edges only in wireframe; painted faces remain visible for interaction. */
297
594
  setDisplay(display: PartDisplay, showEdges?: boolean): void;
595
+ /**
596
+ * Draws the sharp corners of the features the DFM rules flag, bold and
597
+ * through the part — see `render/sharp-corners.ts`. `null` hides them. Setting what is already drawn
598
+ * costs a string comparison, so a caller may pass a fresh object each render.
599
+ */
600
+ setSharpCorners(options: SharpCornerOptions | null): void;
601
+ /** The corners drawn now, in the order their `index` counts; none while they are off. */
602
+ sharpCorners(): readonly SharpCorner[];
603
+ /**
604
+ * The drawn corner under a pointer on the part — `point` in world space,
605
+ * `region` the face it hit — or `null`. See `sharpCornerAt`.
606
+ */
607
+ sharpCornerAt(hit: {
608
+ readonly point: Vector3;
609
+ readonly region: number;
610
+ }, camera: ViewerCamera, viewport: ViewportSize): SharpCorner | null;
611
+ /** Draws one corner up as the one under the pointer; `null` for none. */
612
+ setHoveredSharpCorner(index: number | null): void;
298
613
  dispose(): void;
299
614
  }
300
615
  interface RegionPaint {
@@ -719,6 +1034,13 @@ interface PartPick {
719
1034
  * part, and is nobody else's to answer.
720
1035
  */
721
1036
  readonly doubled: boolean;
1037
+ /**
1038
+ * The sharp corner under the pointer, when `<PartMesh sharpCorners>` is
1039
+ * drawing them and the pointer is on one: within a few pixels of it, on one
1040
+ * of the two faces that meet there. The face is still `region`; this says the
1041
+ * pointer is on the corner drawn over it.
1042
+ */
1043
+ readonly sharpCorner?: SharpCorner;
722
1044
  }
723
1045
  /** A unit vector from the part toward the camera, for the owner ranking. */
724
1046
  declare function viewDirection(camera: Camera, target: Vector3): Vec3;
@@ -850,6 +1172,14 @@ interface PartMeshProps {
850
1172
  onPick?: (pick: PartPick) => void;
851
1173
  theme?: Partial<ViewerTheme>;
852
1174
  showEdges?: boolean;
1175
+ /**
1176
+ * Draws the sharp corners of the features the DFM rules flag — `features`,
1177
+ * those whose `featureSheet(datasheet).sharpCorners` is set — bold, and
1178
+ * faintly through the part where it hides them. The rules decide which
1179
+ * corners; the mesh only says where they are. Off when omitted or `null`.
1180
+ * Coloured by the theme's `sharpCorner`.
1181
+ */
1182
+ sharpCorners?: SharpCornerOptions | null;
853
1183
  /** Wireframe shows region boundaries and any hovered/painted faces, with no triangle diagonals. */
854
1184
  display?: PartDisplay;
855
1185
  /**
@@ -868,7 +1198,7 @@ interface PartMeshProps {
868
1198
  * React render at all: the hovered face lives in a ref, and routing it through
869
1199
  * state is what this rewrite exists to stop doing.
870
1200
  */
871
- declare const PartMesh: ({ model, geometry, selection, focus, candidates, highlights, regionHighlights, pickedRegions, hoveredFeatureIds, hover, activeDirection, section, onSectionChange, onAdjacency, focusFeature, onHover, onPick, theme, showEdges, display, children, }: PartMeshProps) => react.JSX.Element;
1201
+ declare const PartMesh: ({ model, geometry, selection, focus, candidates, highlights, regionHighlights, pickedRegions, hoveredFeatureIds, hover, activeDirection, section, onSectionChange, onAdjacency, focusFeature, onHover, onPick, theme, showEdges, sharpCorners, display, children, }: PartMeshProps) => react.JSX.Element;
872
1202
 
873
1203
  interface EnginePartProps extends Omit<PartMeshProps, 'model' | 'geometry'> {
874
1204
  /**
@@ -943,4 +1273,4 @@ declare function normalizePartReport(report: unknown): PartModel;
943
1273
  */
944
1274
  declare function assertSupportedKernelVersion(kernelVersion: string): void;
945
1275
 
946
- export { type SectionAnchor as $, AXES_PLANE_OFFSET as A, type BuildPickInput as B, CANDIDATE_WEIGHT as C, DEFAULT_SECTION_NORMAL as D, EnginePart as E, type FeatureTag as F, PREVIEW_SCALE as G, HANDLE_PIXELS as H, type PartDisplay as I, PartMesh as J, type KnownFeatureType as K, type PartMeshProps as L, MIN_KERNEL_VERSION as M, NO_MODIFIERS as N, OUTLINE_SCALE as O, type PartModel as P, type PartObject as Q, type RegionHighlight as R, type SectionOptions as S, type TriangleRange as T, type PickModifiers as U, type Vec3 as V, type PointerLocation as W, REGION_ATTRIBUTE as X, type RegionPaint as Y, SECTION_GIZMO_FRAME_SCALE as Z, SECTION_RENDER_ORDER as _, type PartMeshRefs as a, type SectionBounds as a0, type SectionPlacement as a1, type ShapeKind as a2, type SurfaceHit as a3, applyHighlightLayers as a4, axesPlanes as a5, buildPick as a6, buildRegionAttribute as a7, buildRegionTexels as a8, createPart as a9, directionColor as aa, dragPlane as ab, focusForPick as ac, hitUnderRay as ad, pickedStartDepth as ae, resolveTheme as af, sectionAnchor as ag, sectionBounds as ah, sectionConstant as ai, sectionDepth as aj, sectionDepthConstant as ak, sectionDepthRange as al, sectionFromPick as am, sectionMeasurement as an, sectionOffset as ao, sectionOptionsFromState as ap, sectionPlane as aq, surfaceUnderRay as ar, themesEqual as as, viewDirection as at, type EnginePartProps as b, assertSupportedKernelVersion as c, type PartPick as d, type ViewerTheme as e, type SectionState as f, type PartModelRegion as g, type RegionIndex as h, type PartModelFeature as i, type FeatureType as j, AXES_PLANE_SCALE as k, type AxesPlane as l, CAP_HATCH as m, normalizePartReport as n, DEFAULT_THEME as o, DIRECTION_COLORS as p, DISABLED_SECTION as q, type FeatureHighlight as r, smoothRegionNormals as s, type FocusOptions as t, HIGHLIGHT_COLORS as u, HIGHLIGHT_WEIGHT as v, HOVER_WEIGHT as w, type HighlightLayers as x, type KnownShapeKind as y, PICKED_SURFACE_LABEL as z };
1276
+ export { PREVIEW_SCALE as $, AXES_PLANE_OFFSET as A, type BuildPickInput as B, type CameraLimits as C, DEFAULT_FIT_MARGIN as D, EnginePart as E, type FeatureTag as F, type FeatureHighlight as G, type FocusOptions as H, HANDLE_PIXELS as I, HIGHLIGHT_COLORS as J, HIGHLIGHT_WEIGHT as K, HOVER_WEIGHT as L, MIN_KERNEL_VERSION as M, type HighlightLayers as N, type KnownFeatureType as O, type PartModel as P, type KnownShapeKind as Q, type RegionHighlight as R, type SectionOptions as S, type TriangleRange as T, MAX_FRAME_RATIO as U, type Vec3 as V, MIN_FRAME_RATIO as W, NO_MODIFIERS as X, OUTLINE_SCALE as Y, PERSPECTIVE_FOV as Z, PICKED_SURFACE_LABEL as _, type PartMeshRefs as a, viewDirection as a$, type PartDisplay as a0, PartMesh as a1, type PartMeshProps as a2, type PartObject as a3, type PickModifiers as a4, type PointerLocation as a5, REGION_ATTRIBUTE as a6, type RegionPaint as a7, SECTION_GIZMO_FRAME_SCALE as a8, SECTION_RENDER_ORDER as a9, excludedFromFrame as aA, findSharpCorners as aB, fitDistance as aC, focusForPick as aD, hitUnderRay as aE, orthographicHalfHeight as aF, perspectiveFitDistance as aG, pickedStartDepth as aH, resolveTheme as aI, screenLength as aJ, sectionAnchor as aK, sectionBounds as aL, sectionConstant as aM, sectionDepth as aN, sectionDepthConstant as aO, sectionDepthRange as aP, sectionFromPick as aQ, sectionMeasurement as aR, sectionOffset as aS, sectionOptionsFromState as aT, sectionPlane as aU, sharpCornerPositions as aV, startPosition as aW, surfaceCreases as aX, surfaceUnderRay as aY, targetBoundary as aZ, themesEqual as a_, type SceneBounds as aa, type SectionAnchor as ab, type SectionBounds as ac, type SectionPlacement as ad, type ShapeKind as ae, type SharpCorner as af, type SharpCornerOptions as ag, type SurfaceCreases as ah, type SurfaceHit as ai, adaptedUp as aj, applyHighlightLayers as ak, applyProjection as al, aspectRatio as am, axesPlanes as an, boundsFromBox as ao, buildPick as ap, buildRegionAttribute as aq, buildRegionTexels as ar, cadViewDirections as as, cameraLimits as at, contentBounds as au, createPart as av, currentViewDirection as aw, defaultBounds as ax, directionColor as ay, dragPlane as az, type EnginePartProps as b, assertSupportedKernelVersion as c, type PartPick as d, type ViewerTheme as e, type SectionState as f, type ViewerCamera as g, type ViewportSize as h, type PartModelRegion as i, type ViewerView as j, type Projection as k, type RegionIndex as l, type PartModelFeature as m, normalizePartReport as n, type FeatureType as o, AXES_PLANE_SCALE as p, type AxesPlane as q, CAD_CAMERA_UP as r, smoothRegionNormals as s, CANDIDATE_WEIGHT as t, CAP_HATCH as u, DEFAULT_SECTION_NORMAL as v, DEFAULT_THEME as w, DIRECTION_COLORS as x, DISABLED_SECTION as y, EXCLUDE_FROM_FRAME as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolpath/viewer",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
4
4
  "description": "React Three Fiber viewer for Toolpath Engine part reports",
5
5
  "license": "MIT",
6
6
  "engines": {