@omrips/viewstl 0.0.0-stage → 2.0.0-rc.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 +162 -2
- package/THIRD-PARTY-NOTICES.txt +1129 -0
- package/build/v2/README.md +11 -0
- package/build/v2/THIRD-PARTY-NOTICES.txt +1129 -0
- package/build/v2/cad/occt-import-js.js +8 -0
- package/build/v2/cad/occt-import-js.source.txt +57 -0
- package/build/v2/cad/occt-import-js.wasm +0 -0
- package/build/v2/cad/prepare-cad.source.txt +112 -0
- package/build/v2/chunks/archive-VGS4J4Z7.js +1 -0
- package/build/v2/chunks/cad-VY42CMP4.js +1 -0
- package/build/v2/chunks/chunk-JH3H3JWA.js +1 -0
- package/build/v2/chunks/chunk-JS56KC3I.js +1 -0
- package/build/v2/chunks/chunk-R3HNTB5A.js +38 -0
- package/build/v2/chunks/chunk-U33KANV7.js +1 -0
- package/build/v2/chunks/chunk-ZMK3UZZE.js +1 -0
- package/build/v2/chunks/chunk-ZSV4PTIA.js +1 -0
- package/build/v2/chunks/export-7OP4ZGGJ.js +29 -0
- package/build/v2/chunks/export-cad-QPBT756V.js +13 -0
- package/build/v2/chunks/export-zip-EDCWH5PX.js +1 -0
- package/build/v2/chunks/print-check-2PU7CSL3.js +1 -0
- package/build/v2/chunks/scene-export-KQBS7VRJ.js +1 -0
- package/build/v2/chunks/scene-reader-APUJOPUR.js +1 -0
- package/build/v2/stl_viewer.min.js +51 -0
- package/build/v2/viewstl.cjs +5445 -0
- package/build/v2/viewstl.d.cts +446 -0
- package/build/v2/viewstl.d.ts +446 -0
- package/build/v2/viewstl.js +5426 -0
- package/build/v2/viewstl.min.js +51 -0
- package/build/v2/viewstl.worker.js +1 -0
- package/docs/v2-compatibility.md +204 -0
- package/docs/v2-usage.md +723 -0
- package/docs/v2-verification.md +423 -0
- package/legacy/README.md +43 -0
- package/package.json +73 -4
package/docs/v2-usage.md
ADDED
|
@@ -0,0 +1,723 @@
|
|
|
1
|
+
# ViewSTL 2 — native WebGL2 plugin
|
|
2
|
+
|
|
3
|
+
Version: `2.0.0-rc.1` (ViewSTL v2.00 release candidate). The npm package is
|
|
4
|
+
`@omrips/viewstl`; install the candidate with `npm install @omrips/viewstl@2.0.0-rc.1`.
|
|
5
|
+
The legacy plugin remains at its original repository paths and on the production
|
|
6
|
+
website. The v2 website is available at https://preview.viewstl.com/.
|
|
7
|
+
|
|
8
|
+
## Browser script
|
|
9
|
+
|
|
10
|
+
Copy the complete `build/v2/` directory to your server, including the
|
|
11
|
+
worker, its `chunks/` and `cad/` directories and third-party notices. Then:
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<div id="viewer" style="width:100%;height:500px"></div>
|
|
15
|
+
<script src="/viewstl-v2/stl_viewer.min.js"></script>
|
|
16
|
+
<script>
|
|
17
|
+
const viewer = new StlViewer(document.getElementById('viewer'), {
|
|
18
|
+
models: [{ id: 0, filename: '/models/part.stl', color: '#568bdc' }],
|
|
19
|
+
load_error_callback: message => console.error(message)
|
|
20
|
+
});
|
|
21
|
+
</script>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`viewstl.min.js` is an identical classic-script alias. The canvas requires
|
|
25
|
+
a container with a nonzero height. Files must be served over HTTP(S),
|
|
26
|
+
including during local development; browsers restrict workers on `file:` URLs.
|
|
27
|
+
|
|
28
|
+
## ES modules and npm
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
import StlViewer from './viewstl-v2/viewstl.js';
|
|
32
|
+
|
|
33
|
+
const viewer = new StlViewer(container, {
|
|
34
|
+
models: [{ id: 0, local_file: fileInput.files[0] }]
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
await viewer.when_idle();
|
|
38
|
+
console.log(viewer.get_model_info(0));
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The package contains ESM, CommonJS and TypeScript entry points. Importing
|
|
42
|
+
the package is safe during server-side rendering; constructing a viewer
|
|
43
|
+
requires a browser DOM and WebGL2.
|
|
44
|
+
|
|
45
|
+
The package name is `@omrips/viewstl`, under the verified `omrips` npm account.
|
|
46
|
+
Release candidates use the `next` dist-tag. Pin the version above for a
|
|
47
|
+
repeatable installation; installing a local release tarball is also supported.
|
|
48
|
+
|
|
49
|
+
With a bundler, copy the complete `node_modules/@omrips/viewstl/build/v2/`
|
|
50
|
+
directory to your app's public assets (for example `public/viewstl-v2/`), keeping
|
|
51
|
+
the worker, `chunks/`, `cad/` and notices together. Set `worker_url` to its served
|
|
52
|
+
URL, or provide your bundler's worker factory.
|
|
53
|
+
Do not assume a bundler copies a module worker's dynamic chunks merely
|
|
54
|
+
because it sees a URL string.
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
import StlViewer from '@omrips/viewstl';
|
|
58
|
+
|
|
59
|
+
const viewer = new StlViewer(container, {
|
|
60
|
+
worker_url: '/viewstl-v2/viewstl.worker.js'
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
For Vite, the optional factory form is:
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
import ViewerWorker from '@omrips/viewstl/worker?worker';
|
|
68
|
+
const viewer = new StlViewer(container, {
|
|
69
|
+
worker_factory: () => new ViewerWorker()
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The static-assets/`worker_url` integration above was verified in production
|
|
74
|
+
builds using Vite 8.3.4 and Webpack 5.112.0, including STEP/IGES and lazy archive
|
|
75
|
+
assets. The optional Vite worker-factory example is separate integration guidance
|
|
76
|
+
and was not part of those checks. A factory must return a new worker for each
|
|
77
|
+
scheduled job and arrange for all dynamic chunks and CAD assets to be served.
|
|
78
|
+
The CommonJS entry point also requires
|
|
79
|
+
`worker_url` or `worker_factory` because it cannot infer a browser asset URL.
|
|
80
|
+
|
|
81
|
+
## Full app controls
|
|
82
|
+
|
|
83
|
+
`mountViewstlApp` is the optional app controller, exported from the same
|
|
84
|
+
`viewstl.js` bundle as `StlViewer` (and as a global in the classic script).
|
|
85
|
+
It owns the file queue, memory admission, cancellation, selection, scene
|
|
86
|
+
placement, translation/rotation/depth gestures, viewing modes, sectioning,
|
|
87
|
+
colors, grid, PNG downloads, keyboard handling, and control state.
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
import { mountViewstlApp } from './viewer/viewstl.js';
|
|
91
|
+
const app = mountViewstlApp(document, {
|
|
92
|
+
sample_url: new URL('./sample-vase.stl', import.meta.url).href,
|
|
93
|
+
sample_name: 'Twist vase.stl'
|
|
94
|
+
});
|
|
95
|
+
await app.openFiles(fileInput.files);
|
|
96
|
+
console.log(app.getState()); // detached metadata snapshot, no geometry copies
|
|
97
|
+
app.dispose(); // cancels work and releases listeners, workers and WebGL
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
This controller binds the preview's HTML control layout; the host supplies
|
|
101
|
+
markup and CSS. The reference layout is `Viewstl/site/index.html` in the sibling
|
|
102
|
+
website workspace. `requiredControls` in `src/v2/app.js` validates the control
|
|
103
|
+
IDs before registering handlers. Missing controls and duplicate mounts produce
|
|
104
|
+
a descriptive error. Custom integrations without that layout use `StlViewer`.
|
|
105
|
+
Branding, page metadata, advertisements and static help/privacy text belong
|
|
106
|
+
to the host page. The preview's JavaScript is only the initialization call.
|
|
107
|
+
|
|
108
|
+
For an embedded app, pass an `HTMLElement` containing the layout. Queries,
|
|
109
|
+
keyboard events and drops are scoped to that root. For multiple roots, prefix
|
|
110
|
+
each layout's IDs and label/ARIA references and pass the matching `id_prefix`;
|
|
111
|
+
the controller separates radio groups as well. `dispose()` permits remounting
|
|
112
|
+
and prevents late reads from updating the new app.
|
|
113
|
+
|
|
114
|
+
`openFiles()` accepts Files or configured `{name, url, size?}` sources and
|
|
115
|
+
resolves when the queue settles. File errors appear in the notice; success is
|
|
116
|
+
reflected by `getState().models`. Other methods are `select(id)`, `remove(id)`,
|
|
117
|
+
`cancelLoading()` and `clear()`. An omitted `sample_url` hides the sample action.
|
|
118
|
+
`worker_url`, `worker_factory` and `worker_timeout` support alternate hosting,
|
|
119
|
+
bundlers and CommonJS use.
|
|
120
|
+
|
|
121
|
+
Loading the bundle does not create a canvas or worker. The first file creates
|
|
122
|
+
the WebGL2 viewer. App source modules are bundled into `viewstl.js`; the host
|
|
123
|
+
ships no separate memory/layout/transform helpers. Worker JS, archive chunks
|
|
124
|
+
and CAD WASM remain separate plugin-owned assets to keep parsing off the main
|
|
125
|
+
thread and avoid downloading CAD code for STL/OBJ users.
|
|
126
|
+
|
|
127
|
+
`get_model_info()` also exposes copied source `bounds`, `has_colors`, and
|
|
128
|
+
`source_units` (`null` for unitless sources), so consumers need not inspect
|
|
129
|
+
internal geometry or retain its buffers.
|
|
130
|
+
|
|
131
|
+
## Rendering and file processing
|
|
132
|
+
|
|
133
|
+
- WebGL2 only; no CanvasRenderer, WebGL1 or IE fallback.
|
|
134
|
+
- No Three.js or other third-party library in the STL/OBJ rendering core.
|
|
135
|
+
- ASCII/binary STL, VisCAM/MeshLab and Materialise colors, plus the legacy
|
|
136
|
+
ViewSTL colored-STL convention.
|
|
137
|
+
- OBJ polygon fan triangulation and negative indices. OBJ materials,
|
|
138
|
+
textures and robust triangulation of concave polygons are not included.
|
|
139
|
+
- Core 3MF meshes, nested components, build transforms, units, base
|
|
140
|
+
materials and vertex colors. Root model relationships are followed.
|
|
141
|
+
Texture/composite materials, external component parts and unsupported
|
|
142
|
+
required extensions produce explicit errors rather than silent loss.
|
|
143
|
+
- STEP/STP and IGES/IGS solid/surface import via the optional pinned
|
|
144
|
+
Open CASCADE WASM reader. Units normalize to millimetres; assembly placements
|
|
145
|
+
and mesh/face colors are retained. All surfaces in a file form one model.
|
|
146
|
+
The display mesh is an approximation (relative deflection 0.001, angular
|
|
147
|
+
deflection 0.5 radians), not an exact CAD editing or measurement kernel.
|
|
148
|
+
Use self-contained exports: external part files are not fetched, and native
|
|
149
|
+
SolidWorks/Solid Edge formats, feature history, PMI and curve-only files are
|
|
150
|
+
unsupported. Incomplete external-reference assemblies may lack parts.
|
|
151
|
+
- Deploy the entire `build/v2/cad/` directory alongside `chunks/` and the worker.
|
|
152
|
+
CAD code/WASM is loaded only for CAD files; local input bytes are never uploaded.
|
|
153
|
+
Each job's worker is terminated on completion, cancellation, error or timeout.
|
|
154
|
+
CAD admission estimates 128 MiB plus 40 times the input size. The WASM heap
|
|
155
|
+
is separately capped to at most 512 MiB and to part of the remaining scene
|
|
156
|
+
budget. Output arrays and triangle counts are also checked; these checks
|
|
157
|
+
cannot predict exact peak browser/GPU memory for every CAD file.
|
|
158
|
+
- A strict CSP must allow `script-src 'self' 'wasm-unsafe-eval'` for the worker;
|
|
159
|
+
JavaScript `unsafe-eval` is not needed. Serve `.wasm` as `application/wasm`.
|
|
160
|
+
`scripts/prepare-cad.mjs` replaces the pinned glue's dynamic bindings with
|
|
161
|
+
static closures and adds its heap ceiling. The WASM is unmodified. Adapted
|
|
162
|
+
glue, the recipe, license texts and source references ship with the assets.
|
|
163
|
+
- VSJ JSON and VSB archives containing `json_data.vsj` and STL files.
|
|
164
|
+
- ZIP/3MF uses separately loaded worker chunks containing pinned fflate,
|
|
165
|
+
saxes and xmlchars. Those chunks are not fetched for ordinary STL/OBJ.
|
|
166
|
+
- ZIP accepts stored and deflated entries, validates CRC/length and bounds
|
|
167
|
+
expanded data. ZIP64, encryption and multi-disk archives are unsupported.
|
|
168
|
+
- Local files never leave the browser. Remote URLs obey normal CORS and
|
|
169
|
+
same-origin credential rules; there is no upload service or CORS proxy.
|
|
170
|
+
|
|
171
|
+
Parsing, bounds, flat normals and initial requested smooth/edge geometry
|
|
172
|
+
are calculated in workers. Results use transferable buffers. Workers are
|
|
173
|
+
bounded and terminated after jobs, on cancellation, and on disposal.
|
|
174
|
+
|
|
175
|
+
Changing an already-loaded model to smooth/edges/wireframe derives its
|
|
176
|
+
additional data in a worker. That operation intentionally copies positions
|
|
177
|
+
once, since the main thread retains them for synchronous export and picking.
|
|
178
|
+
Nonuniform-scale area queries also require a cached synchronous scan. These
|
|
179
|
+
are distinct from the initial file handoff, which does not clone geometry.
|
|
180
|
+
|
|
181
|
+
Rendering runs only when needed, including during interaction and animation.
|
|
182
|
+
Transparency uses model-level back-to-front sorting; intersecting transparent
|
|
183
|
+
surfaces can still have ordering artifacts. STL export stores face color,
|
|
184
|
+
so a 3MF triangle's per-vertex gradient cannot survive STL/VSB export exactly.
|
|
185
|
+
|
|
186
|
+
## Existing API and intentional differences
|
|
187
|
+
|
|
188
|
+
The existing constructor, model options and documented method names are
|
|
189
|
+
implemented. See [the full inventory](v2-compatibility.md). Existing getters
|
|
190
|
+
remain synchronous. `get_vsb_blob()` continues to return a Promise.
|
|
191
|
+
|
|
192
|
+
- `width` / `height` override their `canvas_width` / `canvas_height` aliases.
|
|
193
|
+
- `bg_color` overrides `bgcolor`.
|
|
194
|
+
- `on_model_mousedown` overrides `on_model_mouseclick`; both setter names work.
|
|
195
|
+
- `set_model_units(model_id, units, scale)` keeps the executable three-argument
|
|
196
|
+
signature. The old documentation omitted `model_id` incorrectly.
|
|
197
|
+
- `load_three_files: 'directory/'` remains a legacy alias for the worker
|
|
198
|
+
directory, resolved against the page. It never loads Three.js. An explicit
|
|
199
|
+
`worker_url` takes precedence; false/omitted uses the entry point's directory.
|
|
200
|
+
- `jszip_path` and `jszip_utils_path` are accepted deprecated options, with
|
|
201
|
+
no effect: archive support is shipped in the package's lazy worker chunks.
|
|
202
|
+
No scripts are fetched from those legacy paths.
|
|
203
|
+
- `get_model_info().dims` now updates after scaling. The old implementation
|
|
204
|
+
returned stale dimensions even when area and volume had changed.
|
|
205
|
+
- Zero IDs, zero coordinates, zero rotations and zero opacity are valid.
|
|
206
|
+
Invalid positive-only scales, colors, transforms and IDs report errors.
|
|
207
|
+
- Model-loading batches preserve the legacy final callback order:
|
|
208
|
+
`all_loaded_callback` precedes the final `model_loaded_callback`.
|
|
209
|
+
Failed/cancelled jobs settle the batch instead of leaving it hanging.
|
|
210
|
+
An empty initial viewer does not emit `all_loaded_callback`.
|
|
211
|
+
- `set_center_models` controls centering of subsequently loaded models.
|
|
212
|
+
- Model data remains CPU-resident for synchronous export/picking and context
|
|
213
|
+
restoration. `clean()` and `dispose()` release GPU buffers and worker jobs.
|
|
214
|
+
- `dispose()` removes only the viewer's owned DOM/listeners, not its siblings.
|
|
215
|
+
- The renderer, camera and models are native objects. Direct Three.js calls
|
|
216
|
+
into `.camera`, `.scene`, `.renderer`, or `.models` are not compatible.
|
|
217
|
+
|
|
218
|
+
STL export retains the legacy convention: geometry scale and centering are
|
|
219
|
+
baked into vertices; scene position and rotation are not baked. VSB saves
|
|
220
|
+
position/rotation in its manifest and avoids applying scale twice.
|
|
221
|
+
|
|
222
|
+
Volume is a signed-tetrahedron mesh calculation reported as an absolute
|
|
223
|
+
value, not a watertightness or printability certification. For inch models,
|
|
224
|
+
area/volume follow the legacy conversion convention.
|
|
225
|
+
|
|
226
|
+
## Optional Three.js mesh bridge
|
|
227
|
+
|
|
228
|
+
The ordinary viewer never imports Three.js. To request a real Three.js
|
|
229
|
+
Mesh from `get_model_mesh`, pass your own instance:
|
|
230
|
+
|
|
231
|
+
```js
|
|
232
|
+
const viewer = new StlViewer(container, { three: THREE });
|
|
233
|
+
// after loading:
|
|
234
|
+
const mesh = viewer.get_model_mesh(0);
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
The bridge uses `options.three` or `globalThis.THREE`. With neither present,
|
|
238
|
+
`get_model_mesh` reports a load error and returns null. It does not return
|
|
239
|
+
a misleading imitation Mesh.
|
|
240
|
+
|
|
241
|
+
Import supports static BufferGeometry meshes and legacy Geometry vertices/
|
|
242
|
+
faces. It copies geometry and basic material color/opacity. Placement is
|
|
243
|
+
controlled by the supplied model options, as in the old plugin. Skinning,
|
|
244
|
+
instances, morph targets, child objects, multiple/textured/shader materials
|
|
245
|
+
are rejected. Export returns an independent BufferGeometry Mesh. Dispose
|
|
246
|
+
the returned mesh's geometry and material when finished with it.
|
|
247
|
+
|
|
248
|
+
Use `get_model_data(id)` for a native copy of raw geometry, and
|
|
249
|
+
`add_model({ data, ...options })` to add it without Three.js. Data does not
|
|
250
|
+
include scene transforms; copy those options explicitly when duplicating.
|
|
251
|
+
|
|
252
|
+
Use `get_image_blob()` for screenshots; direct `renderer.domElement.toDataURL`
|
|
253
|
+
outside a draw is not guaranteed because continuous drawing-buffer
|
|
254
|
+
preservation is disabled.
|
|
255
|
+
|
|
256
|
+
## Additional options and helpers
|
|
257
|
+
|
|
258
|
+
| Option | Default |
|
|
259
|
+
| --- | --- |
|
|
260
|
+
| `worker_url` | Beside the ESM/classic script |
|
|
261
|
+
| `worker_factory` | None |
|
|
262
|
+
| `worker_count` | 2, allowed range 1–4 |
|
|
263
|
+
| `worker_timeout` | 120,000 ms per job |
|
|
264
|
+
| `pixel_ratio` | Device pixel ratio capped at 2 |
|
|
265
|
+
| `max_file_bytes` | 256 MiB |
|
|
266
|
+
| `max_triangles` | 5,000,000 |
|
|
267
|
+
| `max_uncompressed_bytes` | 256 MiB per archive |
|
|
268
|
+
| `max_archive_entries` | 1,024 |
|
|
269
|
+
| `max_memory_bytes` | `Number.MAX_SAFE_INTEGER` (optional estimated working-set budget) |
|
|
270
|
+
|
|
271
|
+
Limits are configurable positive integers. These are ceilings, not guarantees
|
|
272
|
+
that every mobile device has enough memory for the maximum. Derived smooth
|
|
273
|
+
normals/edge maps can use substantially more memory than flat rendering.
|
|
274
|
+
|
|
275
|
+
`max_memory_bytes` adds conservative checks for parsed geometry, text parsing,
|
|
276
|
+
archive expansion, expanded 3MF instances, and derived smooth/wire/edge maps.
|
|
277
|
+
It estimates working memory, including GPU buffers; it does not measure free
|
|
278
|
+
memory. Existing default byte/triangle limits remain unchanged for embedders.
|
|
279
|
+
The ViewSTL preview site configures its own device-dependent limits: half the
|
|
280
|
+
approximate `navigator.deviceMemory` report, or half a 2 GiB fallback if absent.
|
|
281
|
+
This leaves a 50% margin against that estimate, not a guaranteed allocation or
|
|
282
|
+
protection against an OS/browser killing an exhausted tab.
|
|
283
|
+
|
|
284
|
+
Local binary STL files are parsed in chunks of at most 65,536 triangles
|
|
285
|
+
(3.125 MiB input data) plus their 84-byte header. This avoids holding a complete
|
|
286
|
+
input file and a second assembled copy alongside geometry. ASCII/OBJ/archive
|
|
287
|
+
input is still read as a complete buffer; OBJ no longer creates a full array
|
|
288
|
+
of every input line. Native GPU allocation errors clean up partial resources
|
|
289
|
+
and report through `load_error_callback`.
|
|
290
|
+
|
|
291
|
+
`when_ready` resolves after renderer initialization, before initial models
|
|
292
|
+
finish. `when_idle()` waits for pending model, scene and derived-geometry
|
|
293
|
+
work; inspect `load_error_callback` for individual failures. `get_image_blob`
|
|
294
|
+
waits for that work, draws and returns a PNG Blob by default.
|
|
295
|
+
|
|
296
|
+
Keyboard: arrows orbit; + / - zoom; F fits the scene. Mouse: drag orbits,
|
|
297
|
+
shift/right/middle drag pans, wheel zooms. Touch: one finger rotates and
|
|
298
|
+
two fingers pan/pinch. Real mobile-device validation remains necessary.
|
|
299
|
+
|
|
300
|
+
For a same-origin standalone deployment, allow your script and worker assets
|
|
301
|
+
in the site's Content Security Policy (`script-src 'self'; worker-src 'self'`),
|
|
302
|
+
and permit intended remote model hosts in `connect-src`. SharedArrayBuffer,
|
|
303
|
+
cross-origin isolation, eval and worker blob bootstrapping are not required.
|
|
304
|
+
|
|
305
|
+
## Additional views and section cuts
|
|
306
|
+
|
|
307
|
+
The existing `flat`, `smooth` and `wireframe` display values remain supported.
|
|
308
|
+
New display values are `edges` (solid with 30-degree feature edges), `mesh`
|
|
309
|
+
(triangle overlay), `xray`, `studio` and `orientation` (blue front faces, red
|
|
310
|
+
back faces). None requires Three.js. `view_edges` / `set_edges` retain the
|
|
311
|
+
legacy one-degree edge threshold.
|
|
312
|
+
|
|
313
|
+
```js
|
|
314
|
+
viewer.set_view(0, {display: 'studio', smooth_shading: true});
|
|
315
|
+
await viewer.when_idle();
|
|
316
|
+
viewer.set_smooth(0, false); // Independent of the selected modern view
|
|
317
|
+
viewer.set_section(0, {axis: 'z', position: 0.5, flip: false});
|
|
318
|
+
viewer.set_section(0, null); // Restore the complete model
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
These fields are also accepted in model options, returned by `get_model_info`,
|
|
322
|
+
and preserved by VSJ/VSB scene export. `set_display('flat')` and
|
|
323
|
+
`set_display('smooth')` keep their legacy shading behavior. Smooth shading is
|
|
324
|
+
ignored visually in wireframe and retained for the next surface view. Derived
|
|
325
|
+
view changes commit after preparation succeeds; a rejected memory estimate or
|
|
326
|
+
failed worker preserves the previous appearance. Wait for `when_idle()` and
|
|
327
|
+
inspect `load_error_callback` as with model loading.
|
|
328
|
+
|
|
329
|
+
Mesh overlay uses shader barycentric coordinates without an extra geometry
|
|
330
|
+
buffer. Studio, orientation, X-ray and clipping also reuse existing geometry.
|
|
331
|
+
Smooth normals, wireframe and feature edges are computed on demand in a worker
|
|
332
|
+
and checked against the memory budget, including cached derived arrays.
|
|
333
|
+
|
|
334
|
+
Section position is a fraction from 0 to 1 of the source model's bounding box
|
|
335
|
+
along its chosen axis. The plane follows model transforms, clips picking and
|
|
336
|
+
PNG rendering, and does not modify exported STL geometry or model statistics.
|
|
337
|
+
The cut remains open, with an amber boundary highlight; no cap is generated.
|
|
338
|
+
X-ray uses lightweight back-face/front-face alpha passes; it is an illustrative
|
|
339
|
+
view, not exact order-independent transparency for intersecting surfaces.
|
|
340
|
+
Face orientation describes winding relative to the camera, not an automatic
|
|
341
|
+
watertightness or printability diagnosis.
|
|
342
|
+
|
|
343
|
+
## Optional streaming URL imports
|
|
344
|
+
|
|
345
|
+
The plugin does not silently route existing `filename` requests through a server.
|
|
346
|
+
To retrieve a public URL without depending on the source server's CORS policy,
|
|
347
|
+
configure a same-origin relay and explicitly use `remote_url`:
|
|
348
|
+
|
|
349
|
+
```js
|
|
350
|
+
const viewer = new StlViewer(container, {url_import_endpoint: '/api/import-url'});
|
|
351
|
+
viewer.add_model({id: 0, remote_url: 'https://example.com/model.stl'});
|
|
352
|
+
// Optional remote_format: 'stl', 'obj', '3mf', 'step', 'stp', 'iges', 'igs'.
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
`mountViewstlApp` accepts the same endpoint and exposes `app.openURL(url, format)`.
|
|
356
|
+
Its optional `url-dialog`/`url-form` controls are shown in the preview site's HTML.
|
|
357
|
+
The site supplies markup, styles and configuration; URL interaction, loading,
|
|
358
|
+
progress, cancellation and parsing live in the plugin. App jobs allow ten minutes
|
|
359
|
+
by default; low-level viewer worker_timeout remains configurable as before.
|
|
360
|
+
|
|
361
|
+
The relay receives the URL in a JSON POST body and streams the response without
|
|
362
|
+
file storage. A signed URL's query string is not displayed as a model name or
|
|
363
|
+
included in scene exports. Local files still never leave the browser. URL imports
|
|
364
|
+
are a separate privacy path: the relay sees the remote bytes in transit.
|
|
365
|
+
|
|
366
|
+
Binary STL is decoded incrementally in the worker. Other formats use bounded
|
|
367
|
+
browser buffers, including archives and CAD. A complete model appears after
|
|
368
|
+
download and validation; progressive partial rendering is not implemented.
|
|
369
|
+
`get_model_info().file_bytes` reports the imported byte count when available.
|
|
370
|
+
Downloaded names are metadata, not reloadable URLs; use VSB to package a scene
|
|
371
|
+
containing these models. Embedders must provide their own compatible relay; no
|
|
372
|
+
ViewSTL server is implicitly used by the library.
|
|
373
|
+
|
|
374
|
+
When `url_import_endpoint` is configured, `mountViewstlApp` also accepts dropped
|
|
375
|
+
links (`text/uri-list`), Firefox URL/title data, and plain HTTP/HTTPS URL text.
|
|
376
|
+
URL drops use `openURL` and its existing queue, relay, progress, cancellation and
|
|
377
|
+
error handling. Multiple URI-list links are deduplicated per drop. Local files
|
|
378
|
+
take priority over accompanying URL metadata. Plain text is not searched for
|
|
379
|
+
embedded links, HTML drag contents are not parsed, and drops into text inputs or
|
|
380
|
+
editable content retain their normal behavior. This belongs to the optional app
|
|
381
|
+
controller; the low-level viewer's existing file-drop contract is unchanged.
|
|
382
|
+
|
|
383
|
+
The reference relay lives in the website repository's `relay/` directory. Its
|
|
384
|
+
request is `{url, format, max_bytes}` and its response supplies X-ViewSTL-Format,
|
|
385
|
+
percent-encoded X-ViewSTL-Filename, and optional Content-Length. All relay and
|
|
386
|
+
parser failures use the existing error callback. Cancellation terminates the
|
|
387
|
+
worker/fetch; the server then closes the upstream connection.
|
|
388
|
+
|
|
389
|
+
## Local mesh export
|
|
390
|
+
|
|
391
|
+
The optional `mountViewstlApp` controller can bind a Save dialog using the
|
|
392
|
+
`save-*` control group in the preview site's `site/index.html`. Include the entire
|
|
393
|
+
group or omit it; incomplete groups fail before mounting. All event handling,
|
|
394
|
+
selection, progress, cancellation and download dispatch compile into `viewstl.js`.
|
|
395
|
+
The host supplies markup, styles and explanatory copy (format option `data-note`
|
|
396
|
+
attributes and the CAD limitation paragraph). No Save UI is injected by the
|
|
397
|
+
low-level viewer.
|
|
398
|
+
|
|
399
|
+
The reference dialog exports only the current app selection for mesh formats,
|
|
400
|
+
with positions/rotations applied and millimetre output. Unitless STL/OBJ inputs
|
|
401
|
+
are assumed to be millimetres. Its optional color setting applies to OBJ/3MF;
|
|
402
|
+
colored OBJ uses ZIP. It calls `download_models` with explicit model IDs, so
|
|
403
|
+
closing an editing panel does not clear the export selection. VSB/VSJ always
|
|
404
|
+
export the whole scene. `save-scope` is a text status element displaying the
|
|
405
|
+
selected filename or whole-scene model count, not a scope dropdown. Cancel, Escape,
|
|
406
|
+
the close button, backdrop dismissal, changing selection, starting an import,
|
|
407
|
+
removing/clearing models and app disposal cancel an active export. Errors stay
|
|
408
|
+
in the dialog and permit another format. Existing PNG controls remain separate.
|
|
409
|
+
|
|
410
|
+
All exporters live in the plugin and run in disposable workers. They generate
|
|
411
|
+
local Blobs; no relay, upload, server conversion or third-party network endpoint
|
|
412
|
+
is used. Export modules and ZIP compression load only on demand. STEP/IGES writing
|
|
413
|
+
uses JavaScript and does **not** download the CAD importer or WASM engine.
|
|
414
|
+
|
|
415
|
+
```js
|
|
416
|
+
await viewer.when_idle();
|
|
417
|
+
const controller = new AbortController();
|
|
418
|
+
const result = await viewer.export_models({
|
|
419
|
+
format: '3mf', // stl, obj, 3mf, step/stp, iges/igs
|
|
420
|
+
model_ids: [0, 2], // omitted = all; 'selected' = selected model
|
|
421
|
+
filename: 'assembly', // correct extension added/replaced automatically
|
|
422
|
+
units: 'mm', // mm (default), inch
|
|
423
|
+
apply_transforms: true, // default: bake position, rotation, scale and centering
|
|
424
|
+
colors: true, // default for OBJ/3MF; ignored for STL/STEP/IGES
|
|
425
|
+
signal: controller.signal,
|
|
426
|
+
on_progress({ loaded, total, phase }) {
|
|
427
|
+
// Triangle counts. phase is 'exporting' or 'complete'.
|
|
428
|
+
// Encoding can reach total before ZIP packaging completes.
|
|
429
|
+
},
|
|
430
|
+
});
|
|
431
|
+
// {blob, filename, format, units, model_ids, triangles, representation: 'mesh'}
|
|
432
|
+
// Keep result.blob, or use the convenience method to initiate a browser download:
|
|
433
|
+
await viewer.download_models({format: 'step', model_ids: 'selected'});
|
|
434
|
+
// controller.abort() rejects an active/queued operation with AbortError.
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Exports capture the model state at dispatch; subsequent edits/removal do not
|
|
438
|
+
change an in-flight export. Buffers used for rendering are never transferred or
|
|
439
|
+
detached. No selection, an unknown ID, duplicate IDs or an unfinished model
|
|
440
|
+
rejects the promise. Call `when_idle()` first to include pending imports. Errors
|
|
441
|
+
reject the promise and progress goes only to the supplied callback; exporters do
|
|
442
|
+
not show dialogs or invoke the viewer's import-error callback. A throwing progress
|
|
443
|
+
callback rejects its export and terminates the worker. `clean()`/`dispose()` cancel
|
|
444
|
+
active and queued jobs. The caller owns the returned Blob and its lifetime.
|
|
445
|
+
|
|
446
|
+
`apply_transforms: false` exports source coordinates and their accumulated unit
|
|
447
|
+
conversion, without centering, presentation movement/rotation or user scaling.
|
|
448
|
+
Scene coordinates are treated as millimeters; `units: 'inch'` divides output
|
|
449
|
+
coordinates by 25.4 and writes inch metadata where the format supports it.
|
|
450
|
+
Unitless inputs must be interpreted/scaled appropriately by the embedding app.
|
|
451
|
+
STL and OBJ have no standardized units; OBJ includes an informational comment.
|
|
452
|
+
|
|
453
|
+
| Format | Output and scope |
|
|
454
|
+
| --- | --- |
|
|
455
|
+
| STL | Standard binary STL; selected meshes combined into one triangle stream. Attributes are zero, so no ambiguous vendor color encoding. |
|
|
456
|
+
| OBJ | With `colors: true`, a ZIP containing `model.obj` and `materials.mtl`, including object groups, face normals, per-face colors and opacity. Vertex colors are averaged per face and colors/opacity quantized to 8-bit channels. With `colors: false`, a plain `.obj` file. |
|
|
457
|
+
| 3MF | ZIP/XML package with separate mesh objects, indexed vertices, units and per-vertex color/opacity using the Materials extension. Requires non-degenerate triangles, paired consistently oriented edges, and positive volume. Open/inconsistently wound meshes reject; there is no automatic repair or full self-intersection validation. |
|
|
458
|
+
| STEP | AP214 `AUTOMOTIVE_DESIGN`: separate named products made of planar triangle faces in open shells. Exact displayed mesh coordinates are written; this is a surface model, not a reconstructed CAD solid. |
|
|
459
|
+
| IGES | IGES 5.3 bounded planes (108/form 1) with closed 3D polylines (106/form 12). Models use separate levels. Triangle surfaces, not stitched CAD solids. |
|
|
460
|
+
|
|
461
|
+
STEP/IGES preserve mesh geometry and placement, but omit colors, textures,
|
|
462
|
+
analytic curves, original CAD topology/assemblies and feature history. They work
|
|
463
|
+
with open triangle meshes, but reject zero-area triangles. No F3D export is
|
|
464
|
+
provided. A consuming site can describe these limitations in its own interface;
|
|
465
|
+
the low-level export API is UI-free. CAD interoperability has been verified
|
|
466
|
+
against Open CASCADE, not every commercial CAD application.
|
|
467
|
+
|
|
468
|
+
Section cuts, camera orientation, grid, selection frames and viewing/shading modes
|
|
469
|
+
are presentation settings and do not modify exported geometry. Use VSJ/VSB for
|
|
470
|
+
ViewSTL scene settings. Texture/UV data discarded at import cannot be recreated.
|
|
471
|
+
|
|
472
|
+
The scene memory budget includes pending exports. Output is encoded in chunks
|
|
473
|
+
instead of building one large text string; Blobs still require browser storage
|
|
474
|
+
and this API does not stream directly to a filesystem handle. Output obeys
|
|
475
|
+
`max_file_bytes`, archives also obey `max_uncompressed_bytes` and
|
|
476
|
+
`max_archive_entries`, and the complete selection obeys `max_triangles`.
|
|
477
|
+
Conservative format-specific memory estimates can reject an export before copying
|
|
478
|
+
geometry. Cancellation terminates its worker, including compression.
|
|
479
|
+
|
|
480
|
+
The existing synchronous `get_stl_bin`/`download_model` and VSJ/VSB methods retain
|
|
481
|
+
their legacy behavior. Use the new API for scene transforms, correct filename
|
|
482
|
+
extensions, asynchronous execution and cancellation.
|
|
483
|
+
|
|
484
|
+
## Development and packaging
|
|
485
|
+
|
|
486
|
+
```sh
|
|
487
|
+
pnpm install --frozen-lockfile
|
|
488
|
+
pnpm build
|
|
489
|
+
pnpm test
|
|
490
|
+
pnpm check:types
|
|
491
|
+
pnpm check:legacy
|
|
492
|
+
pnpm start
|
|
493
|
+
pnpm pack
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
Open `/examples/v2/` for the demo and `/tests/v2/browser.html` for real worker/
|
|
497
|
+
WebGL checks. `pnpm pack` builds a local tarball; it does not publish anything.
|
|
498
|
+
The package allowlist includes v2 artifacts, types, documentation and license
|
|
499
|
+
notices. It excludes legacy snapshots, old dependencies, tests and server data.
|
|
500
|
+
|
|
501
|
+
Before a stable release, validate real mobile hardware, Safari and Firefox,
|
|
502
|
+
larger user fixtures, npm/bundler integrations and the integrations used by
|
|
503
|
+
the production site. Automated and desktop browser results are recorded in
|
|
504
|
+
[verification](v2-verification.md).
|
|
505
|
+
|
|
506
|
+
## Multiple models, colors and an infinite grid
|
|
507
|
+
|
|
508
|
+
Use `center_models: false` to preserve the coordinates in assembly files, then call
|
|
509
|
+
`add_model` / `add_models` to append files. `set_position` changes presentation
|
|
510
|
+
coordinates without rewriting source geometry. The preview site's Models panel
|
|
511
|
+
adds selection, individual removal and reversible side-by-side placement.
|
|
512
|
+
|
|
513
|
+
```js
|
|
514
|
+
const viewer = new StlViewer(element, { center_models: false });
|
|
515
|
+
viewer.add_models([{id: 0, local_file: partA}, {id: 1, local_file: partB}]);
|
|
516
|
+
await viewer.when_idle();
|
|
517
|
+
viewer.set_color(0, '#dd766b');
|
|
518
|
+
viewer.set_color(0, null); // Restore embedded file colors (or neutral gray if absent).
|
|
519
|
+
viewer.set_bg_color('#202d35');
|
|
520
|
+
viewer.set_infinite_grid(true, 1, 0); // enabled, base spacing, Z height
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
The infinite XY grid is a procedural shader. Its spacing adapts as the camera
|
|
524
|
+
zooms and it fades near the horizon. Panning does not allocate a larger grid;
|
|
525
|
+
opaque models occlude it. `set_grid` retains its existing finite-grid behavior.
|
|
526
|
+
Infinite settings round trip through VSJ/VSB as `infinite_grid: {spacing,height}`.
|
|
527
|
+
Colors change shader uniforms without rebuilding the mesh buffers.
|
|
528
|
+
|
|
529
|
+
An explicit `max_memory_bytes` budget now covers the whole scene, including
|
|
530
|
+
resident geometry, cached view arrays and pending derived geometry. Parsing is
|
|
531
|
+
serialized under that budget so each new model receives the remaining allowance.
|
|
532
|
+
Removing a model frees its allowance and cancels its pending derived work.
|
|
533
|
+
These remain conservative estimates, not measurements of free RAM or GPU memory.
|
|
534
|
+
|
|
535
|
+
### Selecting a model for editing
|
|
536
|
+
|
|
537
|
+
`set_selection(id)` draws a light 3D bounding frame using that model's transform.
|
|
538
|
+
`set_selection(null)` clears it. The frame uses one 288-byte vertex buffer, follows
|
|
539
|
+
rotation/translation/scale without rebuilding mesh buffers, and is excluded from
|
|
540
|
+
PNG and scene exports. Removing or clearing its model releases the frame.
|
|
541
|
+
|
|
542
|
+
`pick_model(clientX, clientY)` returns `{id, distance}` for the nearest visible
|
|
543
|
+
surface, or `null` for empty space. Coordinates use the same viewport coordinate
|
|
544
|
+
system as mouse events. It respects transforms, hidden models and section cuts.
|
|
545
|
+
The preview calls it on double-click only; ordinary dragging does not run a mesh
|
|
546
|
+
intersection scan. The existing legacy click callbacks retain their behavior.
|
|
547
|
+
|
|
548
|
+
The preview provides Move, Rotate and Depth controls per model. Rotation uses
|
|
549
|
+
degrees in the UI and compensates for the original mesh center; the plugin's
|
|
550
|
+
`set_rotation` API continues to accept radians with its existing origin behavior.
|
|
551
|
+
Depth translates along the eye-to-model ray while holding the camera fixed.
|
|
552
|
+
|
|
553
|
+
## Saving ViewSTL scenes
|
|
554
|
+
|
|
555
|
+
Use `export_scene` for a Blob or `download_scene` for a browser download:
|
|
556
|
+
|
|
557
|
+
```js
|
|
558
|
+
const result = await viewer.export_scene({
|
|
559
|
+
format: 'vsb', // or 'vsj'
|
|
560
|
+
filename: 'my-scene',
|
|
561
|
+
signal: abortController.signal,
|
|
562
|
+
on_progress({ loaded, total, phase }) {
|
|
563
|
+
// Model counts; exporting, packaging (VSB only), complete.
|
|
564
|
+
},
|
|
565
|
+
});
|
|
566
|
+
await viewer.download_scene({ format: 'vsj', filename: 'scene', force_basename: true });
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
Both methods always capture the entire loaded scene. They return `{blob,
|
|
570
|
+
filename, format, model_ids, triangles, representation: 'scene'}`. Pending loads,
|
|
571
|
+
empty scenes, excess model/triangle counts, memory and output limits reject.
|
|
572
|
+
Errors reject the Promise instead of using the import-error callback. Cancellation
|
|
573
|
+
and throwing progress callbacks release the worker and memory reservation.
|
|
574
|
+
|
|
575
|
+
VSB uses the existing ZIP layout: `json_data.vsj` plus one colored binary STL per
|
|
576
|
+
model. Mesh encoding and compression run in a disposable worker using copied
|
|
577
|
+
snapshot buffers; renderer buffers remain intact. Camera, background, grid,
|
|
578
|
+
transforms, model colors/opacity, viewing modes and sections stay in the manifest.
|
|
579
|
+
Original model names are kept as `orig_filename`. As with the legacy VSB format,
|
|
580
|
+
STL geometry uses float32 positions and 5-bit per-face colors, taking the first
|
|
581
|
+
vertex color of each triangle. Texture/UV data and original CAD topology/history
|
|
582
|
+
are not reconstructed or included.
|
|
583
|
+
|
|
584
|
+
VSJ is JSON settings and model references, without embedded geometry. The
|
|
585
|
+
`force_basename` option defaults to false for API callers; the preview uses true
|
|
586
|
+
to write only filenames. Referenced files must be supplied separately. A local-file
|
|
587
|
+
reference alone does not grant browser access to a file on disk. VSB is the
|
|
588
|
+
self-contained choice. The preview opens both formats through the file picker,
|
|
589
|
+
drag and drop, and URL opening. Existing `get_vsj`, `get_vsb`, `get_vsb_blob` and their legacy
|
|
590
|
+
download methods retain their signatures and behavior.
|
|
591
|
+
|
|
592
|
+
In the app Save dialog, VSB/VSJ save the entire scene. STL/OBJ/3MF/STEP/IGES save
|
|
593
|
+
only the selected model. There is no user-selectable scope dropdown. The low-level
|
|
594
|
+
`export_models` API still permits explicit multiple-model selections for embedders.
|
|
595
|
+
|
|
596
|
+
## Opening ViewSTL scenes
|
|
597
|
+
|
|
598
|
+
Use the Promise-based `import_scene` API for local files or public URLs:
|
|
599
|
+
|
|
600
|
+
```js
|
|
601
|
+
const result = await viewer.import_scene(sceneFile, {
|
|
602
|
+
files: companionFiles, // File[]: model files referenced by a local VSJ.
|
|
603
|
+
signal: abortController.signal,
|
|
604
|
+
on_progress({ loaded, total, phase }) {
|
|
605
|
+
// reading-scene: reader progress; opening-model/complete: model counts.
|
|
606
|
+
},
|
|
607
|
+
});
|
|
608
|
+
console.log(result.model_ids, result.scene, result.used_files);
|
|
609
|
+
|
|
610
|
+
// Requires the viewer's same-origin url_import_endpoint configuration.
|
|
611
|
+
await viewer.import_scene('https://example.com/scene.vsb');
|
|
612
|
+
await viewer.import_scene('https://example.com/download?id=123', { format: 'vsj' });
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
VSB archives contain `json_data.vsj` and their model files. VSJ manifests reference
|
|
616
|
+
separate files: supplied local files match by exact relative path or unambiguous
|
|
617
|
+
basename. Missing or ambiguous files reject with an actionable error. Absolute
|
|
618
|
+
HTTP/HTTPS references use the configured URL relay. For a remote VSJ, relative
|
|
619
|
+
references resolve against its final directory after redirects, also through the
|
|
620
|
+
relay. Local files and manifests are not uploaded. The relay streams remote files
|
|
621
|
+
without saving them. It still applies its request, size and network limits, so a
|
|
622
|
+
scene with many remote references can hit the relay's rate limit.
|
|
623
|
+
|
|
624
|
+
Imports append models with new IDs and restore camera, background/grid, transforms,
|
|
625
|
+
colors/opacity, view modes, smoothing and sections. Saved centering is converted
|
|
626
|
+
to equivalent model positions without changing existing models' centering. Embed
|
|
627
|
+
canvas size, resize/mouse controls and per-model animation are not imported.
|
|
628
|
+
Scene reading and mesh parsing use workers and the existing memory/triangle/archive
|
|
629
|
+
limits. Models become visible together after all have loaded. Errors, cancellation,
|
|
630
|
+
or a throwing progress callback remove the incoming models and retain the existing
|
|
631
|
+
scene. `clean()` and `dispose()` also cancel pending scene imports. Existing
|
|
632
|
+
`load_vsj` and `load_vsb` retain their previous signatures and behavior.
|
|
633
|
+
|
|
634
|
+
In the preview, choose or drop a local VSJ together with its referenced model files;
|
|
635
|
+
companions used by the scene are not added twice. A VSB needs no separate files.
|
|
636
|
+
Choose VSB/VSJ explicitly in Open URL for a URL without a scene extension. Scene
|
|
637
|
+
opening, progress, cancellation and restored editing controls all live in the
|
|
638
|
+
plugin's app controller; the website initializer remains minimal.
|
|
639
|
+
|
|
640
|
+
## Checking meshes for 3D printing
|
|
641
|
+
|
|
642
|
+
The optional checks run locally on demand. They analyze the loaded triangle mesh
|
|
643
|
+
from any supported format, including models restored from VSB/VSJ. CAD accuracy
|
|
644
|
+
is limited by the imported tessellation. Analysis does not repair or modify models.
|
|
645
|
+
|
|
646
|
+
```js
|
|
647
|
+
const controller = new AbortController();
|
|
648
|
+
const report = await viewer.check_printability({
|
|
649
|
+
model_ids: [selectedId], // Omit for all loaded models; 'selected' uses the editing selection.
|
|
650
|
+
level: 'detailed', // 'basic' is the default.
|
|
651
|
+
apply_transforms: true, // Default: current placement/rotation/scale, like mesh export.
|
|
652
|
+
units_confirmed: true, // Confirm the current mm scale for unitless input.
|
|
653
|
+
profile: { // Optional; omit for geometry checks only.
|
|
654
|
+
technology: 'fdm',
|
|
655
|
+
build_volume_mm: [220, 220, 250],
|
|
656
|
+
min_wall_mm: 0.8, // User-chosen thresholds, not universal printing rules.
|
|
657
|
+
overhang_degrees: 45 // Measured from vertical; +Z is print up.
|
|
658
|
+
},
|
|
659
|
+
max_time_ms: 30000, // Per model, maximum 120000.
|
|
660
|
+
signal: controller.signal,
|
|
661
|
+
on_progress: ({ phase, model_index, total_models }) => console.log(phase)
|
|
662
|
+
});
|
|
663
|
+
if (viewer.is_printability_current(report)) {
|
|
664
|
+
viewer.show_printability(report, { model_id: selectedId, issue: 'boundary_edges' });
|
|
665
|
+
}
|
|
666
|
+
viewer.clear_printability();
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
Basic checks cover degenerate and nearly degenerate triangles, duplicates, open
|
|
670
|
+
boundaries, non-manifold edges and vertices, inconsistent winding, connected
|
|
671
|
+
components and physical-unit provenance. Detailed checks add a native-JavaScript
|
|
672
|
+
BVH for self-intersections (including coplanar overlaps), shell containment,
|
|
673
|
+
orientation and enclosed volume. Separate components can be intentional. Hollow
|
|
674
|
+
models require opposite cavity-shell orientation. Vertex connectivity uses exact
|
|
675
|
+
source coordinates; small gaps are not silently welded closed. Intersection
|
|
676
|
+
checks use the reported scale-dependent numerical tolerance; near-contact cases
|
|
677
|
+
can be inconclusive. The existing 3MF export guards remain independent and unchanged.
|
|
678
|
+
|
|
679
|
+
Optional FDM checks compare dimensions with a build-volume box, identify potential
|
|
680
|
+
overhang regions, estimate bed contact and sample wall thickness. `line_width_mm`
|
|
681
|
+
can supply the wall threshold when `min_wall_mm` is omitted. No printer defaults
|
|
682
|
+
are assumed. Build fit tests current orientation dimensions, not actual placement,
|
|
683
|
+
exclusion zones or alternative rotations. Bed contact virtually lowers each model
|
|
684
|
+
to its minimum Z; the visible grid and camera do not define the print bed.
|
|
685
|
+
Thickness tests at most 2,048 face centres using inward normal rays and can miss
|
|
686
|
+
small features or oblique thin regions. No finding from those samples is explicitly
|
|
687
|
+
inconclusive, never proof of a minimum thickness. Overhangs do not simulate
|
|
688
|
+
bridging/supports; contact area does not predict adhesion/stability. Resin, toolpaths,
|
|
689
|
+
cross-model collisions and Boolean unions are outside these checks.
|
|
690
|
+
|
|
691
|
+
Reports include each check's `pass`, `issue`, `inconclusive` or `not_run` status,
|
|
692
|
+
severity, counts, explanations, bounded highlight samples, dimensions, tolerance,
|
|
693
|
+
timing and optional estimates. `volume_valid` means a geometrically validated
|
|
694
|
+
enclosed volume; its physical size still depends on the `units` check. Overall
|
|
695
|
+
status is `issues_found`, `incomplete` or `no_issues_found`. A basic report remains
|
|
696
|
+
incomplete because detailed checks were not run. Errors and time/memory limits
|
|
697
|
+
never imply a pass. This API does not certify a successful print.
|
|
698
|
+
|
|
699
|
+
Workers and analysis modules load only when requested. Models are checked in
|
|
700
|
+
sequence, with cooperative snapshot copying and aggregate memory admission.
|
|
701
|
+
The working estimate is 64 MiB plus 2,400 bytes per triangle, with bounded report
|
|
702
|
+
allowances; a model that can be viewed may be too large to analyze on the same
|
|
703
|
+
device. One bounded report cache is retained, not the topology/BVH. Geometry,
|
|
704
|
+
transforms, scale and unit changes invalidate reports; colors and camera changes
|
|
705
|
+
do not. Removing a checked model, clean/dispose, AbortSignal cancellation or a
|
|
706
|
+
throwing progress callback releases the active worker and reservations. Report
|
|
707
|
+
metadata uses weak references so retaining a report cannot retain removed meshes.
|
|
708
|
+
|
|
709
|
+
Highlights use temporary native WebGL line buffers and are excluded from PNG,
|
|
710
|
+
mesh and scene exports. They show up to 128 faces or 256 edges per check, through
|
|
711
|
+
occluding surfaces. Closing the site panel clears highlights. The preview exposes
|
|
712
|
+
the feature under **Info → Check for 3D printing**, with selected/all model scope,
|
|
713
|
+
basic/detailed depth and collapsed optional FDM settings. Unit confirmation resets
|
|
714
|
+
when the checked scope or an existing result's geometry/transform changes. A complete
|
|
715
|
+
optional `print-*` control group is bound by `mountViewstlApp`; hosts omitting the
|
|
716
|
+
entire group keep their previous behavior. The website only supplies markup/styles.
|
|
717
|
+
|
|
718
|
+
The check panel stays open while using the canvas, other controls or dialogs,
|
|
719
|
+
loading files, selecting models and clearing the scene. Only its close button or
|
|
720
|
+
Escape with focus inside the panel dismisses it. Reopening it from Info reveals
|
|
721
|
+
and focuses the existing panel. Loading or changing the checked selection cancels
|
|
722
|
+
an active check; stale results are cleared. Loading and empty scenes disable Run
|
|
723
|
+
and show the current availability without closing the panel.
|