three-cad-viewer 3.6.3 → 4.1.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.
Files changed (111) hide show
  1. package/Readme.md +266 -42
  2. package/dist/_version.d.ts +1 -0
  3. package/dist/camera/camera.d.ts +150 -0
  4. package/dist/camera/controls/CADOrbitControls.d.ts +91 -0
  5. package/dist/camera/controls/CADTrackballControls.d.ts +164 -0
  6. package/dist/camera/controls.d.ts +186 -0
  7. package/dist/core/patches.d.ts +10 -0
  8. package/dist/core/types.d.ts +488 -0
  9. package/dist/core/viewer-state.d.ts +239 -0
  10. package/dist/core/viewer.d.ts +1313 -0
  11. package/dist/index.d.ts +33 -0
  12. package/dist/rendering/material-factory.d.ts +131 -0
  13. package/dist/rendering/raycast.d.ts +111 -0
  14. package/dist/rendering/tree-model.d.ts +172 -0
  15. package/dist/scene/animation.d.ts +124 -0
  16. package/dist/scene/axes.d.ts +41 -0
  17. package/dist/scene/bbox.d.ts +57 -0
  18. package/dist/scene/clipping.d.ts +158 -0
  19. package/dist/scene/grid.d.ts +144 -0
  20. package/dist/scene/nestedgroup.d.ts +282 -0
  21. package/dist/scene/objectgroup.d.ts +262 -0
  22. package/dist/scene/orientation.d.ts +61 -0
  23. package/dist/scene/render-shape.d.ts +85 -0
  24. package/dist/three-cad-viewer.css +46 -2
  25. package/dist/three-cad-viewer.esm.js +16970 -11714
  26. package/dist/three-cad-viewer.esm.js.map +1 -1
  27. package/dist/three-cad-viewer.esm.min.js +3 -2
  28. package/dist/three-cad-viewer.js +16980 -11716
  29. package/dist/three-cad-viewer.min.js +3 -2
  30. package/dist/tools/cad_tools/measure.d.ts +99 -0
  31. package/dist/tools/cad_tools/select.d.ts +21 -0
  32. package/dist/tools/cad_tools/tools.d.ts +105 -0
  33. package/dist/tools/cad_tools/ui.d.ts +85 -0
  34. package/dist/tools/cad_tools/zebra.d.ts +70 -0
  35. package/dist/ui/display.d.ts +540 -0
  36. package/dist/ui/info.d.ts +64 -0
  37. package/dist/ui/slider.d.ts +93 -0
  38. package/dist/ui/toolbar.d.ts +87 -0
  39. package/dist/ui/treeview.d.ts +267 -0
  40. package/dist/utils/font.d.ts +31 -0
  41. package/dist/utils/gpu-tracker.d.ts +124 -0
  42. package/dist/utils/logger.d.ts +55 -0
  43. package/dist/utils/sizeof.d.ts +1 -0
  44. package/dist/utils/timer.d.ts +38 -0
  45. package/dist/utils/utils.d.ts +136 -0
  46. package/package.json +74 -9
  47. package/src/_version.ts +1 -0
  48. package/src/camera/camera.ts +428 -0
  49. package/src/camera/controls/CADOrbitControls.ts +241 -0
  50. package/src/camera/controls/CADTrackballControls.ts +598 -0
  51. package/src/camera/controls.ts +380 -0
  52. package/src/core/patches.ts +16 -0
  53. package/src/core/types.ts +597 -0
  54. package/src/core/viewer-state.ts +704 -0
  55. package/src/core/viewer.ts +4390 -0
  56. package/src/index.ts +128 -0
  57. package/src/rendering/material-factory.ts +282 -0
  58. package/src/rendering/raycast.ts +291 -0
  59. package/src/rendering/tree-model.ts +542 -0
  60. package/src/scene/animation.ts +342 -0
  61. package/src/scene/axes.ts +108 -0
  62. package/src/{bbox.js → scene/bbox.ts} +83 -24
  63. package/src/scene/clipping.ts +581 -0
  64. package/src/{grid.js → scene/grid.ts} +317 -117
  65. package/src/scene/nestedgroup.ts +1040 -0
  66. package/src/scene/objectgroup.ts +691 -0
  67. package/src/{orientation.js → scene/orientation.ts} +101 -42
  68. package/src/scene/render-shape.ts +600 -0
  69. package/src/tools/cad_tools/measure.ts +811 -0
  70. package/src/{cad_tools/select.js → tools/cad_tools/select.ts} +32 -21
  71. package/src/{cad_tools/tools.js → tools/cad_tools/tools.ts} +90 -29
  72. package/src/tools/cad_tools/ui.ts +454 -0
  73. package/src/tools/cad_tools/zebra.ts +359 -0
  74. package/src/types/html.d.ts +5 -0
  75. package/src/types/three-augmentation.d.ts +60 -0
  76. package/src/ui/display.ts +2290 -0
  77. package/src/{index.html → ui/index.html} +60 -7
  78. package/src/{info.js → ui/info.ts} +75 -19
  79. package/src/ui/slider.ts +206 -0
  80. package/src/ui/toolbar.ts +347 -0
  81. package/src/ui/treeview.ts +945 -0
  82. package/src/utils/font.ts +60 -0
  83. package/src/utils/gpu-tracker.ts +265 -0
  84. package/src/utils/logger.ts +92 -0
  85. package/src/{sizeof.js → utils/sizeof.ts} +21 -14
  86. package/src/utils/timer.ts +69 -0
  87. package/src/utils/utils.ts +433 -0
  88. package/src/_version.js +0 -1
  89. package/src/animation.js +0 -192
  90. package/src/axes.js +0 -67
  91. package/src/cad_tools/measure.js +0 -619
  92. package/src/cad_tools/ui.js +0 -406
  93. package/src/camera.js +0 -347
  94. package/src/clipping.js +0 -315
  95. package/src/controls/CameraControls.js +0 -1421
  96. package/src/controls.js +0 -266
  97. package/src/display.js +0 -1479
  98. package/src/font.js +0 -118
  99. package/src/fontloader/FontLoader.js +0 -150
  100. package/src/index.js +0 -10
  101. package/src/nestedgroup.js +0 -752
  102. package/src/objectgroup.js +0 -331
  103. package/src/patches.js +0 -33
  104. package/src/raycast.js +0 -237
  105. package/src/slider.js +0 -101
  106. package/src/timer.js +0 -36
  107. package/src/toolbar.js +0 -254
  108. package/src/treeview.js +0 -972
  109. package/src/types.js +0 -336
  110. package/src/utils.js +0 -191
  111. package/src/viewer.js +0 -3035
package/Readme.md CHANGED
@@ -1,10 +1,20 @@
1
1
  # A threejs based CAD viewer
2
2
 
3
- ## Overview
3
+ A CAD viewer component based on three.js. The CAD viewer can visualize low level `threejs` objects (tessellated objects)
4
+
5
+ ![three-js-cad-viewer](overview.png)
4
6
 
5
- The CAD viewer can visualize low level `threejs` objects (tessellated objects)
7
+ [Live Examples](https://bernhard-42.github.io/three-cad-viewer/example.html)
6
8
 
7
- [Live Examples](https://bernhard-42.github.io/three-cad-viewer/example.html)
9
+ ## Getting started
10
+
11
+ 1. [Install yarn](https://classic.yarnpkg.com/en/docs/install) on your system (ie. `npm i -g yarn`) if not already done;
12
+ 2. Clone the repository: `git clone https://github.com/bernhard-42/three-cad-viewer.git && cd three-cad-viewer`;
13
+ 3. Run `yarn install` to install dependencies
14
+ 4. Start web server: `yarn run start` and go to the page displayed in the logs (ie. `127.0.0.1:8080`)
15
+ 5. Build project: `yarn run clean; yarn run build; yarn run docs`;
16
+
17
+ ## Overview
8
18
 
9
19
  ### Shape and Shapes
10
20
 
@@ -40,14 +50,6 @@ The value 2 is reserved for nodes and shows a mixed state, i.d. some of the chil
40
50
 
41
51
  For the `States` object, see [Class States](https://bernhard-42.github.io/three-cad-viewer/global.html#States)
42
52
 
43
- ### Getting started
44
-
45
- 1. [Install yarn](https://classic.yarnpkg.com/en/docs/install) on your system (ie. `npm i -g yarn`) if not already done;
46
- 2. Clone the repository: `git clone https://github.com/bernhard-42/three-cad-viewer.git && cd three-cad-viewer`;
47
- 3. Run `yarn install` to install dependencies
48
- 4. Start web server: `yarn run start` and go to the page displayed in the logs (ie. `127.0.0.1:8080`)
49
- 5. Build project: `yarn run clean; yarn run build; yarn run docs`;
50
-
51
53
  ## Skeleton:
52
54
 
53
55
  ```html
@@ -68,24 +70,24 @@ For the `States` object, see [Class States](https://bernhard-42.github.io/three-
68
70
  theme: "browser",
69
71
  pinning: true,
70
72
  keymap: {
71
- "shift": "shiftKey",
72
- "ctrl": "ctrlKey",
73
- "meta": "metaKey"
74
- }
73
+ shift: "shiftKey",
74
+ ctrl: "ctrlKey",
75
+ meta: "metaKey",
76
+ },
75
77
  };
76
78
 
77
79
  const renderOptions = {
78
80
  ambientIntensity: 1.0,
79
81
  directIntensity: 1.1,
80
- metalness: 0.30,
82
+ metalness: 0.3,
81
83
  roughness: 0.65,
82
84
  edgeColor: 0x707070,
83
85
  defaultOpacity: 0.5,
84
86
  normalLen: 0,
85
87
  };
86
88
  const viewerOptions = {
87
- "target":[0,0,0],
88
- "up": "Z"
89
+ target: [0, 0, 0],
90
+ up: "Z",
89
91
  };
90
92
 
91
93
  const shapes = {
@@ -98,36 +100,40 @@ For the `States` object, see [Class States](https://bernhard-42.github.io/three-
98
100
  name: "Workplane(Solid)",
99
101
  shape: {
100
102
  vertices: [
101
- -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5,
102
- 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5,
103
- -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5,
104
- 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5,
105
- -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5,
106
- 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5,
103
+ -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5,
104
+ 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5,
105
+ 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5,
106
+ -0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5,
107
+ 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5,
108
+ 0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5,
109
+ 0.5, 0.5, 0.5,
107
110
  ],
108
111
  triangles: [
109
- 1, 2, 0, 1, 3, 2, 5, 4, 6, 5, 6, 7, 11, 8, 9, 11, 10, 8, 15, 13, 12,
110
- 15, 12, 14, 19, 16, 17, 19, 18, 16, 23, 21, 20, 23, 20, 22,
112
+ 1, 2, 0, 1, 3, 2, 5, 4, 6, 5, 6, 7, 11, 8, 9, 11, 10, 8, 15, 13,
113
+ 12, 15, 12, 14, 19, 16, 17, 19, 18, 16, 23, 21, 20, 23, 20, 22,
111
114
  ],
112
115
  normals: [
113
- -1.0, -0.0, 0.0, -1.0, -0.0, 0.0, -1.0, -0.0, 0.0, -1.0, -0.0, 0.0,
114
- 1.0, 0.0, -0.0, 1.0, 0.0, -0.0, 1.0, 0.0, -0.0, 1.0, 0.0, -0.0, 0.0,
115
- -1.0, -0.0, 0.0, -1.0, -0.0, 0.0, -1.0, -0.0, 0.0, -1.0, -0.0, -0.0,
116
- 1.0, 0.0, -0.0, 1.0, 0.0, -0.0, 1.0, 0.0, -0.0, 1.0, 0.0, -0.0, -0.0,
117
- -1.0, -0.0, -0.0, -1.0, -0.0, -0.0, -1.0, -0.0, -0.0, -1.0, 0.0, 0.0,
118
- 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,
116
+ -1.0, -0.0, 0.0, -1.0, -0.0, 0.0, -1.0, -0.0, 0.0, -1.0, -0.0,
117
+ 0.0, 1.0, 0.0, -0.0, 1.0, 0.0, -0.0, 1.0, 0.0, -0.0, 1.0, 0.0,
118
+ -0.0, 0.0, -1.0, -0.0, 0.0, -1.0, -0.0, 0.0, -1.0, -0.0, 0.0,
119
+ -1.0, -0.0, -0.0, 1.0, 0.0, -0.0, 1.0, 0.0, -0.0, 1.0, 0.0,
120
+ -0.0, 1.0, 0.0, -0.0, -0.0, -1.0, -0.0, -0.0, -1.0, -0.0, -0.0,
121
+ -1.0, -0.0, -0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,
122
+ 1.0, 0.0, 0.0, 1.0,
119
123
  ],
120
124
  edges: [
121
- -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5,
122
- -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5,
123
- 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
124
- 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5,
125
- -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5,
126
- -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
125
+ -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5,
126
+ 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5,
127
+ 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5,
128
+ 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5,
129
+ 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5,
130
+ 0.5, -0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5,
131
+ 0.5, 0.5, 0.5,
127
132
  ],
128
133
  obj_vertices: [
129
- -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5,
130
- 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5,
134
+ -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5,
135
+ -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
136
+ -0.5,
131
137
  ],
132
138
  face_types: [0, 0, 0, 0, 0, 0],
133
139
  edge_types: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
@@ -154,7 +160,14 @@ For the `States` object, see [Class States](https://bernhard-42.github.io/three-
154
160
  name: "Group",
155
161
  id: "/Group",
156
162
  normal_len: 0,
157
- bb: { xmin: -0.5, xmax: 0.5, ymin: -0.5, ymax: 0.5, zmin: -0.5, zmax: 0.5 },
163
+ bb: {
164
+ xmin: -0.5,
165
+ xmax: 0.5,
166
+ ymin: -0.5,
167
+ ymax: 0.5,
168
+ zmin: -0.5,
169
+ zmax: 0.5,
170
+ },
158
171
  };
159
172
 
160
173
  // 1) get the container
@@ -166,9 +179,66 @@ For the `States` object, see [Class States](https://bernhard-42.github.io/three-
166
179
  // 3) Create the CAD viewer
167
180
  const viewer = new Viewer(display, viewerOptions, nc);
168
181
  // or viewer.clear() if the viewer exists
169
-
182
+
170
183
  // 4) Render the shapes and provide states for the navigation tree in this viewer
171
184
  viewer.render(shapes, renderOptions, viewerOptions);
185
+
186
+ // 5) Dynamically add a second box offset by 2 units along X.
187
+ // addPart(parentPath, partData) builds the absolute path from the
188
+ // parent and the part's name: "/Group" + "/" + "Box2" = "/Group/Box2"
189
+ const newPart = {
190
+ version: 3,
191
+ name: "Box2",
192
+ type: "shapes",
193
+ subtype: "solid",
194
+ shape: {
195
+ vertices: [
196
+ 1.5, -0.5, -0.5, 1.5, -0.5, 0.5, 1.5, 0.5, -0.5, 1.5, 0.5, 0.5, 2.5,
197
+ -0.5, -0.5, 2.5, -0.5, 0.5, 2.5, 0.5, -0.5, 2.5, 0.5, 0.5, 1.5,
198
+ -0.5, -0.5, 2.5, -0.5, -0.5, 1.5, -0.5, 0.5, 2.5, -0.5, 0.5, 1.5,
199
+ 0.5, -0.5, 2.5, 0.5, -0.5, 1.5, 0.5, 0.5, 2.5, 0.5, 0.5, 1.5, -0.5,
200
+ -0.5, 2.5, -0.5, -0.5, 1.5, 0.5, -0.5, 2.5, 0.5, -0.5, 1.5, -0.5,
201
+ 0.5, 2.5, -0.5, 0.5, 1.5, 0.5, 0.5, 2.5, 0.5, 0.5,
202
+ ],
203
+ triangles: [
204
+ 1, 2, 0, 1, 3, 2, 5, 4, 6, 5, 6, 7, 11, 8, 9, 11, 10, 8, 15, 13, 12,
205
+ 15, 12, 14, 19, 16, 17, 19, 18, 16, 23, 21, 20, 23, 20, 22,
206
+ ],
207
+ normals: [
208
+ -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
209
+ 1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0,
210
+ 0, 1, 0, 0, 1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1,
211
+ 0, 0, 1, 0, 0, 1, 0, 0, 1,
212
+ ],
213
+ edges: [
214
+ 1.5, -0.5, -0.5, 1.5, -0.5, 0.5, 1.5, -0.5, 0.5, 1.5, 0.5, 0.5, 1.5,
215
+ 0.5, -0.5, 1.5, 0.5, 0.5, 1.5, -0.5, -0.5, 1.5, 0.5, -0.5, 2.5,
216
+ -0.5, -0.5, 2.5, -0.5, 0.5, 2.5, -0.5, 0.5, 2.5, 0.5, 0.5, 2.5, 0.5,
217
+ -0.5, 2.5, 0.5, 0.5, 2.5, -0.5, -0.5, 2.5, 0.5, -0.5, 1.5, -0.5,
218
+ -0.5, 2.5, -0.5, -0.5, 1.5, 0.5, -0.5, 2.5, 0.5, -0.5, 1.5, -0.5,
219
+ 0.5, 2.5, -0.5, 0.5, 1.5, 0.5, 0.5, 2.5, 0.5, 0.5,
220
+ ],
221
+ obj_vertices: [
222
+ 1.5, -0.5, 0.5, 1.5, -0.5, -0.5, 1.5, 0.5, 0.5, 1.5, 0.5, -0.5, 2.5,
223
+ -0.5, 0.5, 2.5, -0.5, -0.5, 2.5, 0.5, 0.5, 2.5, 0.5, -0.5,
224
+ ],
225
+ face_types: [0, 0, 0, 0, 0, 0],
226
+ edge_types: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
227
+ triangles_per_face: [2, 2, 2, 2, 2, 2],
228
+ segments_per_edge: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
229
+ },
230
+ state: [1, 1],
231
+ color: "#5b9bd5",
232
+ alpha: 1.0,
233
+ renderback: false,
234
+ };
235
+ viewer.addPart("/Group", newPart); // creates "/Group/Box2"
236
+
237
+ // 6) Remove the part again by absolute path
238
+ viewer.removePart("/Group/Box2");
239
+
240
+ // 7) Update an existing part's geometry (see "Dynamic Scene Updates" below)
241
+ viewer.updatePart("/Group/Box2", updatedPartData);
172
242
  </script>
173
243
  </head>
174
244
 
@@ -178,11 +248,108 @@ For the `States` object, see [Class States](https://bernhard-42.github.io/three-
178
248
  </html>
179
249
  ```
180
250
 
251
+ ## Dynamic Scene Updates
252
+
253
+ After the initial `viewer.render()`, parts can be added, removed, or updated without re-rendering the entire scene.
254
+
255
+ ### addPart / removePart
256
+
257
+ `addPart(parentPath, partData)` creates new Three.js objects (meshes, edges, clipping stencils) from the part data and inserts them into the scene graph and navigation tree. `removePart(path)` disposes the Three.js objects and removes the part from the scene.
258
+
259
+ ```js
260
+ viewer.addPart("/Group", partData); // creates "/Group/PartName"
261
+ viewer.removePart("/Group/PartName");
262
+ ```
263
+
264
+ ### updatePart
265
+
266
+ `updatePart(path, partData)` updates an existing part's geometry without tearing down and recreating the Three.js objects. When the mesh topology is unchanged (same number of vertices, triangles, and edge segments), vertex positions, normals, and edge coordinates are written directly into the existing GPU buffers — this is significantly faster than a remove/add cycle. When the topology differs (e.g. a re-tessellation changed the face or edge count), `updatePart` automatically falls back to a batched `removePart` + `addPart` so the caller does not need to handle this case.
267
+
268
+ ```js
269
+ viewer.updatePart("/Group/PartName", updatedPartData);
270
+ ```
271
+
272
+ ### Batching
273
+
274
+ Each of the three methods individually recomputes the bounding box, rebuilds clipping stencils, and (for add/remove) rebuilds the navigation tree. In a loop over N parts this becomes the dominant cost. All three methods accept an optional `{ skipBounds: true }` parameter that defers this work. Call `updateBounds()` once after the loop to perform a single recomputation for the entire batch:
275
+
276
+ ```js
277
+ for (const part of partsToUpdate) {
278
+ viewer.updatePart(`/Group/${part.name}`, part, { skipBounds: true });
279
+ }
280
+ for (const part of partsToAdd) {
281
+ viewer.addPart("/Group", part, { skipBounds: true });
282
+ }
283
+ for (const path of pathsToRemove) {
284
+ viewer.removePart(path, { skipBounds: true });
285
+ }
286
+ viewer.updateBounds();
287
+ ```
288
+
289
+ Add, remove, and update calls can be freely mixed within a single batch.
290
+
291
+ ### ensureStencilSize
292
+
293
+ `updateBounds()` rebuilds clipping stencils whenever the scene's bounding box grows beyond the region that stencils were previously built for. This rebuild is the most expensive part of the bounds update. When the maximum extent of the geometry is known upfront (e.g. the full parameter range of a slider), call `ensureStencilSize()` once after the initial render to pre-size the stencil region. All subsequent `updateBounds()` calls whose geometry stays within this region will skip the stencil rebuild entirely:
294
+
295
+ ```js
296
+ viewer.render(shapes, renderOptions, viewerOptions);
297
+
298
+ viewer.ensureStencilSize({
299
+ xmin: -200, xmax: 200,
300
+ ymin: -200, ymax: 200,
301
+ zmin: 0, zmax: 300,
302
+ });
303
+
304
+ // All updates within these bounds are now stencil-rebuild-free
305
+ ```
306
+
307
+ ## Keyboard Shortcuts
308
+
309
+ The keymap serves two purposes:
310
+
311
+ - **Modifier keys** (`shift`, `ctrl`, `meta`, `alt`) remap which physical modifier key is used for mouse interactions (e.g. shift-click to isolate, ctrl-rotate). Values are DOM event properties like `"shiftKey"`, `"ctrlKey"`, `"metaKey"`, `"altKey"`.
312
+ - **Action shortcuts** map single keys (with or without Shift) to toolbar buttons, camera presets, tab switches, and animation control. Only plain keys are supported — Ctrl/Alt/Meta combinations are reserved for modifier-based mouse interactions.
313
+
314
+ Click on the viewer to give it focus, then press shortcut keys to trigger actions. Button tooltips show `[key]` suffixes when shortcuts are configured.
315
+
316
+ The default keymap:
317
+
318
+ ```javascript
319
+ keymap: {
320
+ // Modifier keys (remap physical keys for mouse interactions)
321
+ shift: "shiftKey", ctrl: "ctrlKey", meta: "metaKey", alt: "altKey",
322
+ // Toggle buttons
323
+ axes: "a", axes0: "A", grid: "g", gridxy: "G",
324
+ perspective: "p", transparent: "t", blackedges: "b",
325
+ explode: "x", zscale: "L",
326
+ distance: "D", properties: "P", select: "S",
327
+ // Execute buttons
328
+ reset: "R", resize: "r",
329
+ iso: "0", front: "1", rear: "2", top: "3", bottom: "4", left: "5", right: "6",
330
+ // Help
331
+ help: "h",
332
+ // Animation
333
+ play: " ", stop: "Escape",
334
+ // Tab selection
335
+ tree: "T", clip: "C", material: "M", zebra: "Z",
336
+ }
337
+ ```
338
+
339
+ Pass a partial keymap to override individual bindings — unspecified keys keep their defaults:
340
+
341
+ ```javascript
342
+ const displayOptions = {
343
+ keymap: { axes: "q", reset: "!" }, // only these two change
344
+ };
345
+ ```
346
+
181
347
  ## Examples
182
348
 
183
349
  To understand the data format, a look at the simple 1 unit sized box might be helpful:
184
350
 
185
351
  - [1 unit sized box source code](https://github.com/bernhard-42/three-cad-viewer/blob/master/examples/box1.js)
352
+ - [addPart / removePart demo](https://github.com/bernhard-42/three-cad-viewer/blob/master/example-add-remove-part.html) — dynamically adding and removing shapes and subtrees after render
186
353
 
187
354
  ## APIs of Viewer, Display, Camera and Controls
188
355
 
@@ -190,6 +357,63 @@ To understand the data format, a look at the simple 1 unit sized box might be he
190
357
 
191
358
  Back to [Github repo](https://github.com/bernhard-42/three-cad-viewer)
192
359
 
360
+ ## Utilities
361
+
362
+ ### Logger
363
+
364
+ Control log verbosity with the built-in logger:
365
+
366
+ ```javascript
367
+ import { logger } from "three-cad-viewer";
368
+
369
+ // Default level is "warn" (only warnings and errors shown)
370
+ logger.setLevel("debug"); // Enable all logging
371
+ logger.setLevel("info"); // Info, warnings, and errors
372
+ logger.setLevel("warn"); // Warnings and errors (default)
373
+ logger.setLevel("error"); // Only errors
374
+ logger.setLevel("silent"); // Disable all logging
375
+ ```
376
+
377
+ ### GPU Resource Tracker
378
+
379
+ Track GPU resource allocation to inspect current state or detect memory leaks:
380
+
381
+ ```javascript
382
+ import { gpuTracker } from "three-cad-viewer";
383
+
384
+ // Check resource counts at any time
385
+ console.log(gpuTracker.summary);
386
+ // { geometry: 5, material: 10, texture: 1, total: 16 }
387
+
388
+ // Log details of allocated resources
389
+ gpuTracker.details();
390
+ ```
391
+
392
+ For detailed allocation info with stack traces:
393
+
394
+ ```javascript
395
+ // Enable debug mode BEFORE creating the viewer
396
+ gpuTracker.enableDebug();
397
+
398
+ const display = new Display(container, displayOptions);
399
+ const viewer = new Viewer(display, viewerOptions, nc);
400
+ viewer.render(shapes, renderOptions, viewerOptions);
401
+
402
+ // Inspect current allocations
403
+ gpuTracker.details();
404
+ // [1] geometry: BufferGeometry (shape) for /Assembly/Part1
405
+ // Created at: 1234.56ms
406
+ // Stack:
407
+ // at NestedGroup.renderShape (nestedgroup.ts:425)
408
+ // ...
409
+
410
+ // After disposal, any remaining resources are potential leaks
411
+ viewer.dispose();
412
+ gpuTracker.details();
413
+ ```
414
+
415
+ The tracker is also available globally in the browser console as `window.tcv_gpu`.
416
+
193
417
  ## Development
194
418
 
195
419
  Run a web server in watch and debug mode
@@ -0,0 +1 @@
1
+ export declare const version: string;
@@ -0,0 +1,150 @@
1
+ import * as THREE from "three";
2
+ import type { Vector3Tuple, QuaternionTuple } from "three";
3
+ import type { UpDirection } from "../core/types";
4
+ type CameraDirection = "iso" | "front" | "rear" | "left" | "right" | "top" | "bottom";
5
+ type UpMode = "y_up" | "z_up" | "legacy";
6
+ /**
7
+ * Manages orthographic and perspective cameras for the viewer.
8
+ *
9
+ * Camera wraps both camera types and provides:
10
+ * - Seamless switching between orthographic and perspective
11
+ * - Preset positions (iso, front, top, etc.)
12
+ * - Support for Y-up and Z-up coordinate systems
13
+ * - Synchronized position/zoom across camera types
14
+ *
15
+ * ## Coordinate Systems
16
+ * Supports three modes via `up` parameter:
17
+ * - `"Y"`: Y-up (Fusion 360 compatible)
18
+ * - `"Z"`: Z-up (FreeCAD, OnShape compatible)
19
+ * - Legacy Z-up mode
20
+ *
21
+ * @internal - This is an internal class used by Viewer
22
+ */
23
+ declare class Camera {
24
+ private static readonly DISTANCE_FACTOR;
25
+ target: THREE.Vector3;
26
+ ortho: boolean;
27
+ up: UpMode;
28
+ yaxis: THREE.Vector3;
29
+ zaxis: THREE.Vector3;
30
+ camera_distance: number;
31
+ pCamera: THREE.PerspectiveCamera;
32
+ oCamera: THREE.OrthographicCamera;
33
+ camera: THREE.PerspectiveCamera | THREE.OrthographicCamera;
34
+ /**
35
+ * Create a combined camera (orthographic and perspective).
36
+ * @param width - canvas width.
37
+ * @param height - canvas height.
38
+ * @param distance - distance from the lookAt point.
39
+ * @param target - target (Vector3) to look at.
40
+ * @param ortho - flag whether the initial camera should be orthographic.
41
+ * @param up - Z or Y to define whether Z or Y direction is camera up.
42
+ */
43
+ constructor(width: number, height: number, distance: number, target: Vector3Tuple, ortho: boolean, up: UpDirection);
44
+ /**
45
+ * Update the far clipping plane for both cameras.
46
+ * @param distance - The new bounding radius to base the far plane on.
47
+ */
48
+ updateFarPlane(distance: number): void;
49
+ /**
50
+ * Recalculate camera_distance from a new bounding radius.
51
+ * Uses the same factor as the constructor so that zoom 1.0 frames the scene.
52
+ * @param distance - The new bounding radius (bb_radius).
53
+ */
54
+ updateCameraDistance(distance: number): void;
55
+ /**
56
+ * Remove assets.
57
+ */
58
+ dispose(): void;
59
+ /**
60
+ * Get the current camera.
61
+ * @returns Camera object.
62
+ */
63
+ getCamera(): THREE.PerspectiveCamera | THREE.OrthographicCamera;
64
+ /**
65
+ * Set the lookAt point for the camera to the provided target.
66
+ */
67
+ lookAtTarget(): void;
68
+ /**
69
+ * Update current camera's projection matrix.
70
+ */
71
+ updateProjectionMatrix(): void;
72
+ /**
73
+ * Switch between orthographic and perspective camera.
74
+ * @param ortho_flag - true for orthographic camera, else perspective camera.
75
+ */
76
+ switchCamera(ortho_flag: boolean): void;
77
+ /**
78
+ * Calculate projected size for orthographic camera.
79
+ * @param frustum - View frustum size.
80
+ * @param aspect - Viewer aspect ratio (width / height).
81
+ * @returns Width and height [w, h] for the orthographic camera.
82
+ */
83
+ projectSize(frustum: number, aspect: number): [number, number];
84
+ /**
85
+ * Setup the current camera.
86
+ * @param relative - flag whether the position is a relative (e.g. [1,1,1] for iso) or absolute point.
87
+ * @param position - the camera position (relative or absolute).
88
+ * @param quaternion - the camera rotation expressed by a quaternion.
89
+ * @param zoom - zoom value.
90
+ */
91
+ setupCamera(relative: boolean, position?: THREE.Vector3 | null, quaternion?: THREE.Quaternion | null, zoom?: number | null): void;
92
+ /**
93
+ * Move the camera to a given preset.
94
+ * @param dir - can be "iso", "top", "bottom", "front", "rear", "left", "right"
95
+ */
96
+ presetCamera(dir: CameraDirection, zoom?: number | null): void;
97
+ /**
98
+ * Return current zoom value.
99
+ * @returns zoom value.
100
+ */
101
+ getZoom(): number;
102
+ /**
103
+ * Set zoom value.
104
+ * @param val - float zoom value.
105
+ */
106
+ setZoom(val: number): void;
107
+ /**
108
+ * Get the current camera position.
109
+ * @returns camera position.
110
+ */
111
+ getPosition(): THREE.Vector3;
112
+ /**
113
+ * Set camera position.
114
+ * @param position - position as 3 dim Array [x,y,z] or as Vector3.
115
+ * @param relative - flag whether the position is a relative (e.g. [1,1,1] for iso) or absolute point.
116
+ */
117
+ setPosition(position: Vector3Tuple | THREE.Vector3, relative: boolean): void;
118
+ /**
119
+ * Get the current camera quaternion.
120
+ * @returns camera quaternion.
121
+ */
122
+ getQuaternion(): THREE.Quaternion;
123
+ /**
124
+ * Set camera quaternion.
125
+ * @param quaternion - quaternion as 4 dim Array or as Quaternion.
126
+ */
127
+ setQuaternion(quaternion: QuaternionTuple | THREE.Quaternion): void;
128
+ /**
129
+ * Get the current camera rotation.
130
+ * @returns camera rotation.
131
+ */
132
+ getRotation(): THREE.Euler;
133
+ /**
134
+ * Get the visible area dimensions at the target plane.
135
+ * @returns The visible width and height.
136
+ */
137
+ getVisibleArea(): {
138
+ width: number;
139
+ height: number;
140
+ };
141
+ /**
142
+ * Update camera dimensions when viewport size changes.
143
+ * @param distance - Distance used for orthographic frustum calculation.
144
+ * @param width - New viewport width in pixels.
145
+ * @param height - New viewport height in pixels.
146
+ */
147
+ changeDimensions(distance: number, width: number, height: number): void;
148
+ }
149
+ export { Camera };
150
+ export type { CameraDirection, UpMode };
@@ -0,0 +1,91 @@
1
+ /**
2
+ * CADOrbitControls - Extended OrbitControls for CAD applications
3
+ *
4
+ * Adds:
5
+ * - Public rotateLeft/rotateUp methods for programmatic rotation
6
+ * - Quaternion-based saveState/reset
7
+ * - Modifier key rotation restrictions (ctrl: vertical only, meta: horizontal only)
8
+ *
9
+ * Internal OrbitControls methods/properties used (see three-augmentation.d.ts):
10
+ * - _onMouseDown: Replaced to customize modifier key behavior (shift=pan, ctrl/meta=rotate with axis lock)
11
+ * - _handleMouseDownRotate: Called to initialize rotation state
12
+ * - _handleMouseDownDolly: Called to initialize dolly/zoom state
13
+ * - _handleMouseDownPan: Called to initialize pan state
14
+ * - _sphericalDelta: Modified in _rotateLeft/_rotateUp overrides to implement axis locking
15
+ * - state: Set to track current interaction mode (ROTATE/DOLLY/PAN/NONE)
16
+ */
17
+ import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
18
+ import { Quaternion, Vector3, Camera } from "three";
19
+ declare class CADOrbitControls extends OrbitControls {
20
+ quaternion0: Quaternion;
21
+ private _horizontalRotate;
22
+ private _verticalRotate;
23
+ private _onCADPointerDown?;
24
+ private _onCADPointerUp?;
25
+ state: number;
26
+ _sphericalDelta: {
27
+ theta: number;
28
+ phi: number;
29
+ };
30
+ zoom0: number;
31
+ target0: Vector3;
32
+ position0: Vector3;
33
+ _onMouseDown: (event: MouseEvent) => void;
34
+ _handleMouseDownRotate: (event: MouseEvent) => void;
35
+ _handleMouseDownDolly: (event: MouseEvent) => void;
36
+ _handleMouseDownPan: (event: MouseEvent) => void;
37
+ /**
38
+ * Constructs CAD-enhanced orbit controls.
39
+ *
40
+ * @param object - The camera to control.
41
+ * @param domElement - The HTML element for event listeners.
42
+ */
43
+ constructor(object: Camera, domElement?: HTMLElement | null);
44
+ /**
45
+ * Handle pointer down to check modifier keys for rotation restriction.
46
+ */
47
+ private _handleCADPointerDown;
48
+ /**
49
+ * Handle pointer up to reset rotation restrictions.
50
+ */
51
+ private _handleCADPointerUp;
52
+ /**
53
+ * Override dispose to clean up our event listeners.
54
+ */
55
+ dispose(): void;
56
+ /**
57
+ * Custom mouse down handler for rotation restriction via modifier keys.
58
+ *
59
+ * Original OrbitControls: ctrl/meta/shift + left mouse = pan
60
+ * CADOrbitControls: ctrl = vertical rotate only, meta = horizontal rotate only,
61
+ * shift = pan (via KeyMapper)
62
+ */
63
+ private _handleMouseDown;
64
+ /**
65
+ * Override _rotateLeft to respect horizontal rotation restriction.
66
+ */
67
+ _rotateLeft(angle: number): void;
68
+ /**
69
+ * Override _rotateUp to respect vertical rotation restriction.
70
+ */
71
+ _rotateUp(angle: number): void;
72
+ /**
73
+ * Save the current state including quaternion.
74
+ */
75
+ saveState(): void;
76
+ /**
77
+ * Reset to saved state including quaternion.
78
+ */
79
+ reset(): void;
80
+ /**
81
+ * Rotate camera left (around the up axis).
82
+ * Programmatic rotation bypasses modifier key restrictions.
83
+ */
84
+ rotateLeft(angle: number): void;
85
+ /**
86
+ * Rotate camera up (around the right axis).
87
+ * Programmatic rotation bypasses modifier key restrictions.
88
+ */
89
+ rotateUp(angle: number): void;
90
+ }
91
+ export { CADOrbitControls };