@toolpath/viewer 1.3.0 → 1.5.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/README.md +290 -55
- package/dist/assets/banana.glb +0 -0
- package/dist/{chunk-HWAEUJ4H.js → chunk-4TBLMR4Z.js} +744 -175
- package/dist/engine/index.d.ts +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/index.d.ts +225 -22
- package/dist/index.js +755 -405
- package/dist/{normalize-DHOSNiuO.d.ts → normalize-CvnV9Ggh.d.ts} +55 -18
- package/dist/toolbar.css +108 -0
- package/package.json +5 -4
|
@@ -144,6 +144,12 @@ interface PartModel {
|
|
|
144
144
|
readonly warnings: readonly string[];
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
/** Enables selection-driven X-ray rendering on a part. */
|
|
148
|
+
interface FocusOptions {
|
|
149
|
+
/** Opacity for regions outside the current selection, from 0 through 1. */
|
|
150
|
+
readonly opacity?: number;
|
|
151
|
+
}
|
|
152
|
+
|
|
147
153
|
/**
|
|
148
154
|
* Viewer colors.
|
|
149
155
|
*
|
|
@@ -184,7 +190,8 @@ interface ViewerTheme {
|
|
|
184
190
|
/** The cutting plane itself — the translucent sheet `<SectionTool>` draws, its outline, and the surface preview. */
|
|
185
191
|
readonly sectionOutline: number;
|
|
186
192
|
/**
|
|
187
|
-
* The arrow that drags the cut
|
|
193
|
+
* The arrow that drags the cut when overridden. When omitted from a theme
|
|
194
|
+
* override, the handle uses the cutting plane's direction colour. Hovered it
|
|
188
195
|
* takes {@link ViewerTheme.hover}, like every other control here.
|
|
189
196
|
*/
|
|
190
197
|
readonly sectionHandle: number;
|
|
@@ -243,6 +250,7 @@ declare function directionColor(index: number): number;
|
|
|
243
250
|
|
|
244
251
|
/** The vertex attribute carrying each vertex's column in the state texture. */
|
|
245
252
|
declare const REGION_ATTRIBUTE = "aRegion";
|
|
253
|
+
type PartDisplay = 'solid' | 'wireframe';
|
|
246
254
|
/**
|
|
247
255
|
* A part on screen: one mesh, one draw call, one material.
|
|
248
256
|
*
|
|
@@ -271,6 +279,10 @@ interface PartObject {
|
|
|
271
279
|
/** Paints every region the feature explicitly owns. */
|
|
272
280
|
paintFeature(tag: FeatureTag, color: number, weight: number): void;
|
|
273
281
|
clearPaint(): void;
|
|
282
|
+
/** Makes selected features solid and the rest of the part translucent. */
|
|
283
|
+
setFocus(selection: readonly FeatureTag[], focus?: FocusOptions): void;
|
|
284
|
+
/** The current opacity of one region, or `null` if it does not exist. */
|
|
285
|
+
regionOpacity(region: number): number | null;
|
|
274
286
|
/** A feature's bounds in part space, for framing. `null` if it has none. */
|
|
275
287
|
boxForFeature(tag: FeatureTag): Box3 | null;
|
|
276
288
|
/**
|
|
@@ -280,6 +292,8 @@ interface PartObject {
|
|
|
280
292
|
*/
|
|
281
293
|
setClippingPlanes(planes: readonly Plane[] | null): void;
|
|
282
294
|
setTheme(theme: ViewerTheme): void;
|
|
295
|
+
/** Semantic edges only in wireframe; painted faces remain visible for interaction. */
|
|
296
|
+
setDisplay(display: PartDisplay, showEdges?: boolean): void;
|
|
283
297
|
dispose(): void;
|
|
284
298
|
}
|
|
285
299
|
interface RegionPaint {
|
|
@@ -422,6 +436,8 @@ declare const SECTION_RENDER_ORDER: {
|
|
|
422
436
|
};
|
|
423
437
|
/** The handle's length on screen, in CSS pixels, whatever the zoom. */
|
|
424
438
|
declare const HANDLE_PIXELS = 78;
|
|
439
|
+
/** The viewer-space span of the visible section-plane frame, relative to the part diagonal. */
|
|
440
|
+
declare const SECTION_GIZMO_FRAME_SCALE = 1.1;
|
|
425
441
|
/**
|
|
426
442
|
* The hatch on the cap: stripe pitch and line thickness in CSS pixels, and the
|
|
427
443
|
* outline's width. Screen-space, so the cut reads the same at any zoom.
|
|
@@ -463,6 +479,12 @@ interface SectionState {
|
|
|
463
479
|
readonly constant: number;
|
|
464
480
|
readonly plane: SectionPlacement | null;
|
|
465
481
|
readonly depth: number | null;
|
|
482
|
+
/**
|
|
483
|
+
* Distance swept from the edge of the part into its projected bounds, in
|
|
484
|
+
* model units. A surface-anchored cut also reports `depth`, which is its
|
|
485
|
+
* more useful physical datum.
|
|
486
|
+
*/
|
|
487
|
+
readonly cutDistance?: number;
|
|
466
488
|
/**
|
|
467
489
|
* How far the cut can travel from its anchor, in model units, or `null` for a
|
|
468
490
|
* sweep — which is measured as a fraction of the part rather than a distance.
|
|
@@ -484,6 +506,13 @@ declare const DEFAULT_SECTION_NORMAL: Vec3;
|
|
|
484
506
|
* own state never has to special-case the absence: `enabled` says it.
|
|
485
507
|
*/
|
|
486
508
|
declare const DISABLED_SECTION: SectionState;
|
|
509
|
+
/**
|
|
510
|
+
* A concise physical measurement for a host application's section control.
|
|
511
|
+
*
|
|
512
|
+
* A cut placed from a surface is measured from that surface. A free sweep is
|
|
513
|
+
* measured from the edge of the part along the cut normal.
|
|
514
|
+
*/
|
|
515
|
+
declare function sectionMeasurement(state: SectionState): string;
|
|
487
516
|
/**
|
|
488
517
|
* The options that would resolve to `state` again.
|
|
489
518
|
*
|
|
@@ -526,9 +555,9 @@ interface SurfaceHit {
|
|
|
526
555
|
*
|
|
527
556
|
* "The part" is whatever in the scene is a visible mesh outside an overlay —
|
|
528
557
|
* every overlay here marks its outermost group with `EXCLUDE_FROM_FRAME`, the
|
|
529
|
-
* same flag that keeps it out of the camera's framing
|
|
530
|
-
*
|
|
531
|
-
*
|
|
558
|
+
* same flag that keeps it out of the camera's framing. Stock has its own flag:
|
|
559
|
+
* it belongs in Fit, but not in section or measurement picks. Non-clickable
|
|
560
|
+
* overlays also turn their own raycast off.
|
|
532
561
|
*
|
|
533
562
|
* A surface a section cut has clipped away is skipped too. three's raycaster
|
|
534
563
|
* knows nothing about clipping planes, so without this a ray through the open
|
|
@@ -572,18 +601,6 @@ interface SectionPlacement {
|
|
|
572
601
|
readonly label?: string;
|
|
573
602
|
}
|
|
574
603
|
declare const PICKED_SURFACE_LABEL = "Part surface";
|
|
575
|
-
/**
|
|
576
|
-
* The range of plane constants that sweeps a box along `normal`.
|
|
577
|
-
*
|
|
578
|
-
* Derived from the eight corners rather than from a single axis extent, which is
|
|
579
|
-
* what makes an arbitrary normal work: a tilted plane leaves the box through a
|
|
580
|
-
* corner, and an axis-aligned approximation either stops short of cutting the
|
|
581
|
-
* part or sweeps a long way through empty space before reaching it.
|
|
582
|
-
*
|
|
583
|
-
* `Plane` keeps the half-space where `normal · p + constant > 0`, so a *larger*
|
|
584
|
-
* constant clips less. `min` and `max` are named for the constant, not for how
|
|
585
|
-
* much they remove.
|
|
586
|
-
*/
|
|
587
604
|
declare function sectionBounds(box: Box3, normal: Vec3): SectionBounds;
|
|
588
605
|
/** The plane constant at `t`, from 0 (uncut) to 1 (fully cut away). */
|
|
589
606
|
declare function sectionConstant(bounds: SectionBounds, t: number): number;
|
|
@@ -657,6 +674,11 @@ interface PickModifiers {
|
|
|
657
674
|
readonly secondary: boolean;
|
|
658
675
|
}
|
|
659
676
|
declare const NO_MODIFIERS: PickModifiers;
|
|
677
|
+
/** A browser-viewport point, for placing an application-owned hover card. */
|
|
678
|
+
interface PointerLocation {
|
|
679
|
+
readonly clientX: number;
|
|
680
|
+
readonly clientY: number;
|
|
681
|
+
}
|
|
660
682
|
/**
|
|
661
683
|
* A pointer event on the part, resolved to the face it landed on and the
|
|
662
684
|
* features that own it.
|
|
@@ -678,6 +700,8 @@ interface PartPick {
|
|
|
678
700
|
readonly point: readonly [number, number, number];
|
|
679
701
|
/** The surface's outward normal in world space — the plane under the cursor. */
|
|
680
702
|
readonly normal: readonly [number, number, number];
|
|
703
|
+
/** Browser coordinates when the pick came from `<PartMesh>`. */
|
|
704
|
+
readonly pointer?: PointerLocation;
|
|
681
705
|
readonly modifiers: PickModifiers;
|
|
682
706
|
/**
|
|
683
707
|
* Whether this click completed a double click on the part.
|
|
@@ -703,6 +727,7 @@ interface BuildPickInput {
|
|
|
703
727
|
readonly triangleIndex: number;
|
|
704
728
|
readonly point: readonly [number, number, number];
|
|
705
729
|
readonly normal: readonly [number, number, number];
|
|
730
|
+
readonly pointer?: PointerLocation;
|
|
706
731
|
readonly modifiers?: PickModifiers;
|
|
707
732
|
/**
|
|
708
733
|
* The machining direction the pick is scoped to, as an index into
|
|
@@ -740,6 +765,11 @@ interface PartMeshProps {
|
|
|
740
765
|
* one-to-many and no scoping rule fixes that.
|
|
741
766
|
*/
|
|
742
767
|
selection?: readonly FeatureTag[];
|
|
768
|
+
/**
|
|
769
|
+
* Makes selected feature regions solid and the rest of the part translucent.
|
|
770
|
+
* Omit it for the normal solid view. The application still owns selection.
|
|
771
|
+
*/
|
|
772
|
+
focus?: FocusOptions;
|
|
743
773
|
/**
|
|
744
774
|
* Every feature a click could have meant, painted faintly in each one's own
|
|
745
775
|
* direction colour, under the selection.
|
|
@@ -761,6 +791,11 @@ interface PartMeshProps {
|
|
|
761
791
|
* and needs no prop.
|
|
762
792
|
*/
|
|
763
793
|
hoveredFeatureIds?: readonly FeatureTag[];
|
|
794
|
+
/**
|
|
795
|
+
* Whether moving across the part paints and reports a hovered face. Turn it
|
|
796
|
+
* off for an application-level "feature hover" control; picks still work.
|
|
797
|
+
*/
|
|
798
|
+
hover?: boolean;
|
|
764
799
|
/**
|
|
765
800
|
* Scopes a pick to one machining direction, as an index into the model's
|
|
766
801
|
* `candidateDirections`. A face that direction cannot reach then picks to
|
|
@@ -814,6 +849,8 @@ interface PartMeshProps {
|
|
|
814
849
|
onPick?: (pick: PartPick) => void;
|
|
815
850
|
theme?: Partial<ViewerTheme>;
|
|
816
851
|
showEdges?: boolean;
|
|
852
|
+
/** Wireframe shows region boundaries and any hovered/painted faces, with no triangle diagonals. */
|
|
853
|
+
display?: PartDisplay;
|
|
817
854
|
}
|
|
818
855
|
/**
|
|
819
856
|
* The part, as one mesh with one material.
|
|
@@ -825,7 +862,7 @@ interface PartMeshProps {
|
|
|
825
862
|
* React render at all: the hovered face lives in a ref, and routing it through
|
|
826
863
|
* state is what this rewrite exists to stop doing.
|
|
827
864
|
*/
|
|
828
|
-
declare const PartMesh: ({ model, geometry, selection, candidates, highlights, regionHighlights, pickedRegions, hoveredFeatureIds, activeDirection, section, onSectionChange, onAdjacency, focusFeature, onHover, onPick, theme, showEdges, }: PartMeshProps) => react.JSX.Element;
|
|
865
|
+
declare const PartMesh: ({ model, geometry, selection, focus, candidates, highlights, regionHighlights, pickedRegions, hoveredFeatureIds, hover, activeDirection, section, onSectionChange, onAdjacency, focusFeature, onHover, onPick, theme, showEdges, display, }: PartMeshProps) => react.JSX.Element;
|
|
829
866
|
|
|
830
867
|
interface EnginePartProps extends Omit<PartMeshProps, 'model' | 'geometry'> {
|
|
831
868
|
/**
|
|
@@ -900,4 +937,4 @@ declare function normalizePartReport(report: unknown): PartModel;
|
|
|
900
937
|
*/
|
|
901
938
|
declare function assertSupportedKernelVersion(kernelVersion: string): void;
|
|
902
939
|
|
|
903
|
-
export { type
|
|
940
|
+
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 };
|
package/dist/toolbar.css
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
.viewer-toolbar-stack {
|
|
2
|
+
position: absolute;
|
|
3
|
+
bottom: 1.25rem;
|
|
4
|
+
left: 0;
|
|
5
|
+
width: 100%;
|
|
6
|
+
padding: 0 0.75rem;
|
|
7
|
+
z-index: 2;
|
|
8
|
+
pointer-events: none;
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
align-items: center;
|
|
12
|
+
gap: 0.6rem;
|
|
13
|
+
}
|
|
14
|
+
.viewer-toolbar,
|
|
15
|
+
.viewer-tool-options {
|
|
16
|
+
pointer-events: auto;
|
|
17
|
+
display: flex;
|
|
18
|
+
align-items: center;
|
|
19
|
+
justify-content: center;
|
|
20
|
+
flex-wrap: wrap;
|
|
21
|
+
gap: 0.25rem;
|
|
22
|
+
max-width: 100%;
|
|
23
|
+
padding: 0.4rem;
|
|
24
|
+
border: 1px solid #52607880;
|
|
25
|
+
border-radius: 0.6rem;
|
|
26
|
+
background: #202737df;
|
|
27
|
+
backdrop-filter: blur(12px);
|
|
28
|
+
box-shadow: 0 3px 14px #0003;
|
|
29
|
+
}
|
|
30
|
+
.viewer-toolbar-stack button,
|
|
31
|
+
.viewer-toolbar-button {
|
|
32
|
+
border: 1px solid #526078;
|
|
33
|
+
border-radius: 0.4rem;
|
|
34
|
+
background: #202737;
|
|
35
|
+
color: #eef0f6;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
padding: 0.45rem 0.65rem;
|
|
38
|
+
}
|
|
39
|
+
.viewer-toolbar button,
|
|
40
|
+
.viewer-toolbar-button {
|
|
41
|
+
position: relative;
|
|
42
|
+
display: grid;
|
|
43
|
+
place-items: center;
|
|
44
|
+
width: 2.2rem;
|
|
45
|
+
height: 2.2rem;
|
|
46
|
+
padding: 0.4rem;
|
|
47
|
+
border-color: transparent;
|
|
48
|
+
background: transparent;
|
|
49
|
+
}
|
|
50
|
+
.viewer-toolbar-icon {
|
|
51
|
+
width: 1.3rem;
|
|
52
|
+
height: 1.3rem;
|
|
53
|
+
}
|
|
54
|
+
.viewer-toolbar-divider {
|
|
55
|
+
width: 1px;
|
|
56
|
+
height: 1.4rem;
|
|
57
|
+
margin: 0 0.2rem;
|
|
58
|
+
background: #526078;
|
|
59
|
+
}
|
|
60
|
+
.viewer-toolbar-tooltip {
|
|
61
|
+
display: none;
|
|
62
|
+
position: absolute;
|
|
63
|
+
bottom: calc(100% + 0.75rem);
|
|
64
|
+
left: 50%;
|
|
65
|
+
transform: translateX(-50%);
|
|
66
|
+
white-space: nowrap;
|
|
67
|
+
background: #101522;
|
|
68
|
+
padding: 0.4rem 0.6rem;
|
|
69
|
+
border-radius: 0.3rem;
|
|
70
|
+
pointer-events: none;
|
|
71
|
+
font-size: 0.75rem;
|
|
72
|
+
z-index: 3;
|
|
73
|
+
}
|
|
74
|
+
.viewer-toolbar-button:hover .viewer-toolbar-tooltip,
|
|
75
|
+
.viewer-toolbar-button:focus-visible .viewer-toolbar-tooltip {
|
|
76
|
+
display: block;
|
|
77
|
+
}
|
|
78
|
+
.viewer-toolbar-button:focus {
|
|
79
|
+
outline: none;
|
|
80
|
+
}
|
|
81
|
+
.viewer-toolbar-button:focus-visible {
|
|
82
|
+
outline: 2px solid #83a9ff;
|
|
83
|
+
outline-offset: 2px;
|
|
84
|
+
}
|
|
85
|
+
.viewer-toolbar-button:hover {
|
|
86
|
+
background: #303b51;
|
|
87
|
+
}
|
|
88
|
+
.viewer-toolbar-button[aria-pressed='true'] {
|
|
89
|
+
border-color: #83a9ff;
|
|
90
|
+
background: #2b3f66;
|
|
91
|
+
}
|
|
92
|
+
.viewer-toolbar label {
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
gap: 0.4rem;
|
|
96
|
+
color: #b9c0d1;
|
|
97
|
+
font-size: 0.85rem;
|
|
98
|
+
}
|
|
99
|
+
.viewer-tool-options label {
|
|
100
|
+
display: flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
gap: 0.4rem;
|
|
103
|
+
}
|
|
104
|
+
.viewer-hint {
|
|
105
|
+
align-self: center;
|
|
106
|
+
color: #b9c0d1;
|
|
107
|
+
font-size: 0.85rem;
|
|
108
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toolpath/viewer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "React Three Fiber viewer for Toolpath Engine part reports",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"engines": {
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"./engine": {
|
|
31
31
|
"types": "./dist/engine/index.d.ts",
|
|
32
32
|
"import": "./dist/engine/index.js"
|
|
33
|
-
}
|
|
33
|
+
},
|
|
34
|
+
"./toolbar.css": "./dist/toolbar.css"
|
|
34
35
|
},
|
|
35
36
|
"files": [
|
|
36
37
|
"dist",
|
|
@@ -63,8 +64,8 @@
|
|
|
63
64
|
"camera-controls": "3.1.0"
|
|
64
65
|
},
|
|
65
66
|
"scripts": {
|
|
66
|
-
"build": "tsup src/index.ts src/engine/index.ts --format esm --dts --clean --external react --external react-dom --external three --external @react-three/fiber --external @react-three/drei",
|
|
67
|
-
"build:watch": "tsup src/index.ts src/engine/index.ts --format esm --dts --watch --external react --external react-dom --external three --external @react-three/fiber --external @react-three/drei",
|
|
67
|
+
"build": "tsup src/index.ts src/engine/index.ts --format esm --dts --clean --external react --external react-dom --external three --external @react-three/fiber --external @react-three/drei && node scripts/copy-assets.mjs",
|
|
68
|
+
"build:watch": "node scripts/copy-assets.mjs && tsup src/index.ts src/engine/index.ts --format esm --dts --watch --external react --external react-dom --external three --external @react-three/fiber --external @react-three/drei",
|
|
68
69
|
"check-types": "tsc --noEmit",
|
|
69
70
|
"test": "vitest run"
|
|
70
71
|
}
|