@omrips/viewstl 2.0.0-rc.4 → 2.0.0-rc.6
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 +19 -173
- package/build/chunks/archive-QK7XZSVT.js +1 -0
- package/build/{v2/chunks/cad-VY42CMP4.js → chunks/cad-QGVO6UGR.js} +1 -1
- package/build/chunks/chunk-6AW5U52H.js +1 -0
- package/build/{v2/chunks/chunk-R3HNTB5A.js → chunks/chunk-CVGQTUJ5.js} +2 -2
- package/build/chunks/chunk-FUXP2W57.js +1 -0
- package/build/chunks/chunk-LFTKNL2V.js +1 -0
- package/build/{v2/chunks/chunk-ZMK3UZZE.js → chunks/chunk-T6PPRDOE.js} +1 -1
- package/build/chunks/chunk-V6KYGP62.js +1 -0
- package/build/{v2/chunks/export-7OP4ZGGJ.js → chunks/export-2CFMTPJ3.js} +3 -3
- package/build/{v2/chunks/export-cad-QPBT756V.js → chunks/export-cad-XOXIE726.js} +1 -1
- package/build/{v2/chunks/export-zip-EDCWH5PX.js → chunks/export-zip-I2ADLFJI.js} +1 -1
- package/build/chunks/measure-3LDALPCN.js +1 -0
- package/build/chunks/print-check-WWHTT5PW.js +1 -0
- package/build/{v2/chunks/scene-export-KQBS7VRJ.js → chunks/scene-export-FPPL466I.js} +1 -1
- package/build/chunks/scene-reader-WXTRELY3.js +1 -0
- package/build/{v2/node → node}/analysis-worker.js +13 -12
- package/build/{v2/node → node}/index.cjs +7 -7
- package/build/{v2/node → node}/index.js +6 -6
- package/build/stl_viewer.min.js +51 -0
- package/build/{v2/viewstl.cjs → viewstl.cjs} +1641 -272
- package/build/{v2/viewstl.d.cts → viewstl.d.cts} +98 -0
- package/build/{v2/viewstl.d.ts → viewstl.d.ts} +98 -0
- package/build/{v2/viewstl.js → viewstl.js} +1641 -272
- package/build/viewstl.min.js +51 -0
- package/build/viewstl.worker.js +1 -0
- package/docs/releases/2.0.0-rc.6.md +7 -0
- package/docs/v2-compatibility.md +5 -5
- package/docs/v2-usage.md +152 -21
- package/docs/v2-verification.md +169 -0
- package/legacy/README.md +14 -8
- package/package.json +18 -35
- package/build/v2/README.md +0 -15
- package/build/v2/chunks/archive-VGS4J4Z7.js +0 -1
- package/build/v2/chunks/chunk-JH3H3JWA.js +0 -1
- package/build/v2/chunks/chunk-U33KANV7.js +0 -1
- package/build/v2/chunks/print-check-2PU7CSL3.js +0 -1
- package/build/v2/chunks/scene-reader-APUJOPUR.js +0 -1
- package/build/v2/stl_viewer.min.js +0 -51
- package/build/v2/viewstl.min.js +0 -51
- package/build/v2/viewstl.worker.js +0 -1
- /package/build/{v2/THIRD-PARTY-NOTICES.txt → THIRD-PARTY-NOTICES.txt} +0 -0
- /package/build/{v2/cad → cad}/occt-import-js.js +0 -0
- /package/build/{v2/cad → cad}/occt-import-js.source.txt +0 -0
- /package/build/{v2/cad → cad}/occt-import-js.wasm +0 -0
- /package/build/{v2/cad → cad}/prepare-cad.source.txt +0 -0
- /package/build/{v2/chunks/chunk-JS56KC3I.js → chunks/chunk-W5KVLGVR.js} +0 -0
- /package/build/{v2/chunks → chunks}/chunk-ZSV4PTIA.js +0 -0
- /package/build/{v2/node → node}/index.d.cts +0 -0
- /package/build/{v2/node → node}/index.d.ts +0 -0
package/docs/v2-usage.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# ViewSTL 2 — native WebGL2 plugin
|
|
2
2
|
|
|
3
|
-
Version: `2.0.0-rc.
|
|
4
|
-
|
|
5
|
-
The
|
|
6
|
-
|
|
3
|
+
Version: `2.0.0-rc.5` (ViewSTL v2.00 release candidate, GitHub and npm).
|
|
4
|
+
On `main`, the new plugin is in `src/` and `build/`; the legacy tree is in
|
|
5
|
+
`legacy/v1/`. The unchanged `master` branch retains original legacy paths.
|
|
6
|
+
The v2 website is available at https://preview.viewstl.com/.
|
|
7
7
|
|
|
8
8
|
## Quick start
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
`
|
|
10
|
+
Download the plugin ZIP from the [GitHub release](https://github.com/omrips/viewstl/releases/tag/v2.0.0-rc.5),
|
|
11
|
+
then copy its complete `build/` folder to `/viewstl-v2/` on your website.
|
|
12
12
|
Paste these three lines into your page's `<body>`:
|
|
13
13
|
|
|
14
14
|
```html
|
|
@@ -23,7 +23,7 @@ required so the viewer can find its worker and optional format assets.
|
|
|
23
23
|
|
|
24
24
|
## Browser script
|
|
25
25
|
|
|
26
|
-
Copy the complete `build
|
|
26
|
+
Copy the complete `build/` directory to your server, including the
|
|
27
27
|
worker, its `chunks/` and `cad/` directories and third-party notices. Then:
|
|
28
28
|
|
|
29
29
|
```html
|
|
@@ -58,11 +58,13 @@ The package contains ESM, CommonJS and TypeScript entry points. Importing
|
|
|
58
58
|
the package is safe during server-side rendering; constructing a viewer
|
|
59
59
|
requires a browser DOM and WebGL2.
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
Install with `npm install viewstl`. No version suffix is required: the `latest`
|
|
62
|
+
tag selects the current release candidate. The established `@omrips/viewstl`
|
|
63
|
+
package is also updated with the same plugin; `npm install @omrips/viewstl`
|
|
64
|
+
works without a version suffix. Use either package name consistently in imports
|
|
65
|
+
and asset-copy paths; there is no need to install both.
|
|
64
66
|
|
|
65
|
-
With a bundler, copy the complete `node_modules
|
|
67
|
+
With a bundler, copy the complete `node_modules/viewstl/build/`
|
|
66
68
|
directory to your app's public assets (for example `public/viewstl-v2/`), keeping
|
|
67
69
|
the worker, `chunks/`, `cad/` and notices together. Set `worker_url` to its served
|
|
68
70
|
URL, or provide your bundler's worker factory.
|
|
@@ -70,7 +72,7 @@ Do not assume a bundler copies a module worker's dynamic chunks merely
|
|
|
70
72
|
because it sees a URL string.
|
|
71
73
|
|
|
72
74
|
```js
|
|
73
|
-
import StlViewer from '
|
|
75
|
+
import StlViewer from 'viewstl';
|
|
74
76
|
|
|
75
77
|
const viewer = new StlViewer(container, {
|
|
76
78
|
worker_url: '/viewstl-v2/viewstl.worker.js'
|
|
@@ -80,7 +82,7 @@ const viewer = new StlViewer(container, {
|
|
|
80
82
|
For Vite, the optional factory form is:
|
|
81
83
|
|
|
82
84
|
```js
|
|
83
|
-
import ViewerWorker from '
|
|
85
|
+
import ViewerWorker from 'viewstl/worker?worker';
|
|
84
86
|
const viewer = new StlViewer(container, {
|
|
85
87
|
worker_factory: () => new ViewerWorker()
|
|
86
88
|
});
|
|
@@ -96,17 +98,17 @@ The CommonJS entry point also requires
|
|
|
96
98
|
|
|
97
99
|
## Node.js model analysis
|
|
98
100
|
|
|
99
|
-
|
|
101
|
+
Run `npm install viewstl`. Node.js 20+ resolves the analysis
|
|
100
102
|
worker and optional CAD WASM directly inside the package; there is no asset-copy
|
|
101
103
|
step for server use.
|
|
102
104
|
|
|
103
105
|
```js
|
|
104
|
-
import { analyzeFile } from '
|
|
106
|
+
import { analyzeFile } from 'viewstl/node';
|
|
105
107
|
const report = await analyzeFile('part.stl', { units: 'mm' });
|
|
106
108
|
console.log(report.dimensions_mm, report.surface_area_mm2, report.volume_mm3);
|
|
107
109
|
```
|
|
108
110
|
|
|
109
|
-
CommonJS is supported with `const { analyzeFile } = require('
|
|
111
|
+
CommonJS is supported with `const { analyzeFile } = require('viewstl/node')`.
|
|
110
112
|
The `/node` entry point is separate from the browser viewer and has no DOM,
|
|
111
113
|
WebGL or Three.js dependency. It supports STL, OBJ, 3MF, STEP/STP and IGES/IGS.
|
|
112
114
|
STEP/IGES measurements describe the tessellated mesh, not exact CAD surfaces.
|
|
@@ -119,7 +121,7 @@ object. `analyzeBuffer(data, options)` accepts a Node Buffer, Uint8Array or
|
|
|
119
121
|
ArrayBuffer, and requires `filename` or `format` to identify the format:
|
|
120
122
|
|
|
121
123
|
```js
|
|
122
|
-
import { analyzeBuffer } from '
|
|
124
|
+
import { analyzeBuffer } from 'viewstl/node';
|
|
123
125
|
const report = await analyzeBuffer(uploadBuffer, { filename: 'part.stl', units: 'mm' });
|
|
124
126
|
```
|
|
125
127
|
|
|
@@ -151,7 +153,7 @@ The convenience functions share an analyzer with two active workers, up to
|
|
|
151
153
|
Create an independent analyzer when the host needs different concurrency:
|
|
152
154
|
|
|
153
155
|
```js
|
|
154
|
-
import { createAnalyzer } from '
|
|
156
|
+
import { createAnalyzer } from 'viewstl/node';
|
|
155
157
|
const analyzer = createAnalyzer({ concurrency: 1, max_queue: 4 });
|
|
156
158
|
try {
|
|
157
159
|
const reports = await Promise.all(paths.map(path => analyzer.analyzeFile(path, {
|
|
@@ -220,7 +222,7 @@ app.dispose(); // cancels work and releases listeners, workers and WebGL
|
|
|
220
222
|
|
|
221
223
|
This controller binds the preview's HTML control layout; the host supplies
|
|
222
224
|
markup and CSS. The reference layout is `Viewstl/site/index.html` in the sibling
|
|
223
|
-
website workspace. `requiredControls` in `src/
|
|
225
|
+
website workspace. `requiredControls` in `src/app.js` validates the control
|
|
224
226
|
IDs before registering handlers. Missing controls and duplicate mounts produce
|
|
225
227
|
a descriptive error. Custom integrations without that layout use `StlViewer`.
|
|
226
228
|
Branding, page metadata, advertisements and static help/privacy text belong
|
|
@@ -269,7 +271,7 @@ internal geometry or retain its buffers.
|
|
|
269
271
|
Use self-contained exports: external part files are not fetched, and native
|
|
270
272
|
SolidWorks/Solid Edge formats, feature history, PMI and curve-only files are
|
|
271
273
|
unsupported. Incomplete external-reference assemblies may lack parts.
|
|
272
|
-
- Deploy the entire `build/
|
|
274
|
+
- Deploy the entire `build/cad/` directory alongside `chunks/` and the worker.
|
|
273
275
|
CAD code/WASM is loaded only for CAD files; local input bytes are never uploaded.
|
|
274
276
|
Each job's worker is terminated on completion, cancellation, error or timeout.
|
|
275
277
|
CAD admission estimates 128 MiB plus 40 times the input size. The WASM heap
|
|
@@ -304,6 +306,109 @@ Transparency uses model-level back-to-front sorting; intersecting transparent
|
|
|
304
306
|
surfaces can still have ordering artifacts. STL export stores face color,
|
|
305
307
|
so a 3MF triangle's per-vertex gradient cannot survive STL/VSB export exactly.
|
|
306
308
|
|
|
309
|
+
## Model animation
|
|
310
|
+
|
|
311
|
+
Animation is included in `2.0.0-rc.5` on GitHub and in both npm packages.
|
|
312
|
+
Playback remains inside the native WebGL2 plugin.
|
|
313
|
+
|
|
314
|
+
After a model has loaded, one call starts continuous rotation:
|
|
315
|
+
|
|
316
|
+
```js
|
|
317
|
+
await viewer.when_idle();
|
|
318
|
+
viewer.animate_model(0, {
|
|
319
|
+
delta: { rotationz: 2 * Math.PI, msec: 5000, loop: true },
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
The legacy `animation` model option also works. `delta` adds a change to the
|
|
324
|
+
starting pose; `exact` interpolates toward an absolute target. They can operate
|
|
325
|
+
together on different properties and finish independently:
|
|
326
|
+
|
|
327
|
+
```js
|
|
328
|
+
viewer.animate_model(0, {
|
|
329
|
+
delta: { rotationx: 1, rotationy: 1.1, rotationz: 1.2, msec: 1000, loop: true },
|
|
330
|
+
exact: { x: 1000, y: 150, z: 200, scale: 5, msec: 3000 },
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
viewer.pause_model_animation(0); // Keep the pose and elapsed time.
|
|
334
|
+
viewer.resume_model_animation(0);
|
|
335
|
+
console.log(viewer.get_model_animation_state(0));
|
|
336
|
+
viewer.animate_model(0, null); // Stop at the current pose; discard playback.
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Supported properties are `x/y/z`, `rotationx/y/z` in radians and
|
|
340
|
+
`scale` or `scalex/scaley/scalez`. Durations are positive milliseconds, defaulting
|
|
341
|
+
to 300. Scale deltas are additive, as in the legacy API; all resulting scales
|
|
342
|
+
must stay positive. Only delta tracks repeat, accumulating their change each
|
|
343
|
+
cycle. A negative looping scale delta is rejected. Delta and exact may not claim
|
|
344
|
+
the same property. Inputs must be finite and within JavaScript's safe numeric
|
|
345
|
+
range. Invalid replacements leave the current animation intact.
|
|
346
|
+
|
|
347
|
+
Starting a new animation replaces the old one from the current pose. Manual
|
|
348
|
+
position, rotation, scale and unit setters stop that model's playback first.
|
|
349
|
+
Camera interaction, color and viewing-mode changes remain usable. Completed
|
|
350
|
+
tracks no longer write their properties. Removal, `clean()` and `dispose()`
|
|
351
|
+
release playback; paused/completed models do not keep the render loop running.
|
|
352
|
+
|
|
353
|
+
Timing follows elapsed frame timestamps, not frame count. Hidden documents and
|
|
354
|
+
lost WebGL contexts suspend playback without including that gap on resumption.
|
|
355
|
+
User pause is independent of this automatic suspension. State queries return
|
|
356
|
+
`status`, `elapsed_ms`, `suspended` and active `tracks`; unknown IDs return null.
|
|
357
|
+
|
|
358
|
+
Set callbacks in the viewer options:
|
|
359
|
+
|
|
360
|
+
```js
|
|
361
|
+
const viewer = new StlViewer(container, {
|
|
362
|
+
animation_state_callback(id, state, reason) {
|
|
363
|
+
console.log(id, state.status, reason);
|
|
364
|
+
},
|
|
365
|
+
animation_complete_callback(id, state) {
|
|
366
|
+
console.log('Finished', id, state.elapsed_ms);
|
|
367
|
+
},
|
|
368
|
+
});
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Callbacks describe transitions, not every frame, and are deferred until the
|
|
372
|
+
current operation finishes. Completion fires once when every track finishes;
|
|
373
|
+
an animation with a looping track does not complete. Call playback controls on
|
|
374
|
+
loaded models, for example after `when_idle()`.
|
|
375
|
+
|
|
376
|
+
VSB/VSJ preserve the animation definition, original pose, elapsed phase, rotation
|
|
377
|
+
pivot and pause flag. Both scene-loading APIs start incoming animations together
|
|
378
|
+
after all incoming models load. VSJ still needs its referenced model files.
|
|
379
|
+
Animated VSB entries retain unscaled mesh data and explicit scale metadata;
|
|
380
|
+
static entries retain the previous scale-baked convention. This prevents scale
|
|
381
|
+
being applied twice. Older viewers may read the pose but cannot restore the new
|
|
382
|
+
playback-state extension exactly.
|
|
383
|
+
|
|
384
|
+
PNG and modern `export_models()` capture the current pose without stopping
|
|
385
|
+
playback. Legacy `get_stl_bin()` keeps its documented scale/centering-only export
|
|
386
|
+
convention. Regular model files do not store animation. Print checks should run
|
|
387
|
+
while the affected models are paused; subsequent motion makes the report stale.
|
|
388
|
+
|
|
389
|
+
A self-contained example is in `examples/v2/animation.html` in the source
|
|
390
|
+
checkout (serve with `pnpm start`). It includes Play, Pause, Resume, Stop and Reset.
|
|
391
|
+
|
|
392
|
+
The app controller also supports an optional `animation-*` group (see the new
|
|
393
|
+
site's HTML template): `animation-details`, `animation-fields`, `animation-axis`,
|
|
394
|
+
`animation-seconds`, `animation-direction`, `animation-play`, `animation-pause`,
|
|
395
|
+
`animation-stop`, `animation-status` and `animation-error`. Supply the whole group
|
|
396
|
+
or omit it. It exposes selected-model spin around the mesh center, duration
|
|
397
|
+
(0.1–3,600 seconds per turn), direction and playback buttons. Other models keep
|
|
398
|
+
playing when selection changes. Manual tools capture the current animated pose.
|
|
399
|
+
Readouts update at most four times per second; geometry and GPU buffers are reused.
|
|
400
|
+
|
|
401
|
+
`mountViewstlApp` composes `animation_state_callback` and
|
|
402
|
+
`animation_complete_callback` options with its own UI behavior. `app.getState()`
|
|
403
|
+
includes each model's current transform and `animation` state. Ordinary files
|
|
404
|
+
never auto-spin. Imported running animations are paused when the browser reports
|
|
405
|
+
`prefers-reduced-motion: reduce`; explicit user playback remains available.
|
|
406
|
+
|
|
407
|
+
App print checks pause running target models. Optional `print-resume` and
|
|
408
|
+
`print-animation-note` elements expose resumption; closing the panel does not
|
|
409
|
+
silently restart motion. Resuming clears stale results and keeps the panel open.
|
|
410
|
+
Scene saving includes playback; PNG and regular model saving capture a pose.
|
|
411
|
+
|
|
307
412
|
## Existing API and intentional differences
|
|
308
413
|
|
|
309
414
|
The existing constructor, model options and documented method names are
|
|
@@ -609,6 +714,7 @@ pnpm install --frozen-lockfile
|
|
|
609
714
|
pnpm build
|
|
610
715
|
pnpm test
|
|
611
716
|
pnpm check:types
|
|
717
|
+
pnpm check:node-types
|
|
612
718
|
pnpm check:legacy
|
|
613
719
|
pnpm start
|
|
614
720
|
pnpm pack
|
|
@@ -745,7 +851,8 @@ scene with many remote references can hit the relay's rate limit.
|
|
|
745
851
|
Imports append models with new IDs and restore camera, background/grid, transforms,
|
|
746
852
|
colors/opacity, view modes, smoothing and sections. Saved centering is converted
|
|
747
853
|
to equivalent model positions without changing existing models' centering. Embed
|
|
748
|
-
canvas size
|
|
854
|
+
canvas size and resize/mouse controls are not imported. The development animation
|
|
855
|
+
update also restores per-model animation and preserves its original pivot.
|
|
749
856
|
Scene reading and mesh parsing use workers and the existing memory/triangle/archive
|
|
750
857
|
limits. Models become visible together after all have loaded. Errors, cancellation,
|
|
751
858
|
or a throwing progress callback remove the incoming models and retain the existing
|
|
@@ -842,3 +949,27 @@ Escape with focus inside the panel dismisses it. Reopening it from Info reveals
|
|
|
842
949
|
and focuses the existing panel. Loading or changing the checked selection cancels
|
|
843
950
|
an active check; stale results are cleared. Loading and empty scenes disable Run
|
|
844
951
|
and show the current availability without closing the panel.
|
|
952
|
+
|
|
953
|
+
## Model size, units, duplicates, cameras and measurements (rc.6)
|
|
954
|
+
|
|
955
|
+
All operations below are implemented inside the plugin. The optional site controls remain a thin HTML/CSS host.
|
|
956
|
+
|
|
957
|
+
`viewer.resize_model(id, [2, 2, 2])` doubles the model about its world-space bounds center, preserving rotation and placement. Positive finite XYZ factors are required; independent factors allow nonuniform scaling. It stops only that model's animation. `get_model_size(id)` returns dimensions and the reset baseline in millimetres. `reset_model_size(id)` restores that baseline while retaining file-unit corrections.
|
|
958
|
+
|
|
959
|
+
`viewer.set_file_units(id, 'inch')` reinterprets a unitless STL/OBJ mesh (default mm) without moving its center. Switching back reverses the conversion. Explicit 3MF/STEP/IGES units are normalized to mm during parsing and cannot be reinterpreted. `set_display_units('inch')` changes the optional app's size/Info readouts only; scene coordinates, position controls and the grid remain in mm. Existing `set_model_units` and `set_scale` retain their legacy semantics.
|
|
960
|
+
|
|
961
|
+
`const copy = viewer.duplicate_model(id)` returns a new ID at the same pose, with independent appearance, transforms and metadata. Immutable geometry and matching GPU buffers are shared; memory admission remains conservative. The source reference remains unchanged for VSJ, while `display_name` identifies the copy. Copied animation definitions and phase are retained but paused; the original keeps playing.
|
|
962
|
+
|
|
963
|
+
`viewer.set_camera_view('top')` fits the scene from front/back/left/right/top/bottom/isometric using Z up and the existing perspective projection. It never rotates the models. Camera bookmarks are explicit data:
|
|
964
|
+
|
|
965
|
+
`viewer.set_camera_bookmarks([{name: 'Detail', camera: viewer.get_camera_state()}])`
|
|
966
|
+
|
|
967
|
+
Use `get_camera_bookmarks()` to obtain a defensive copy and `set_camera_state(bookmark.camera)` to restore one. Up to 32 uniquely named views (80 characters per name) are supported. They are kept in memory and in scene exports, not localStorage.
|
|
968
|
+
|
|
969
|
+
`const {area_mm2, volume_mm3, volume_valid, volume_reason} = await viewer.measure_model(id)`
|
|
970
|
+
|
|
971
|
+
Measurements use workers and support `signal`, `max_time_ms` (default 30 seconds) and `on_progress`. Area includes all triangles at current scale. Volume is nullable: detailed topology, intersections and shell-orientation checks must establish a closed volume. An open/invalid mesh or an inconclusive/time-limited check never becomes a plausible-looking volume. Results are cached by mesh and scale; position/rotation do not invalidate them and uniform resizing updates cached measurements algebraically. Nonuniform area is recalculated in the worker. Memory limits can reject the calculation before buffers are copied. This is a bounded mesh analysis, not a guarantee of printability.
|
|
972
|
+
|
|
973
|
+
VSB/VSJ retain size baselines, file-unit interpretation, display units, duplicate labels and bookmarks. VSB still embeds geometry; VSJ still needs the referenced source files. No second unit conversion occurs during import. Appending scenes merges bookmark names with numbered suffixes; a combined total above 32 rejects the incoming scene. Old files without the new optional fields continue to load. The `size_state.unit_factor` serialization field preserves source-unit correction separately from resize factors for exports with `apply_transforms:false`.
|
|
974
|
+
|
|
975
|
+
The optional app control group is listed in `src/app-tools.js` (`toolsControls`). Provide the whole group or omit it when embedding older markup. The preview's `site/index.html` is a complete example. Models contains collapsed Size & units and Duplicate; View contains collapsed Camera & saved views; Info contains area and the volume calculation. No server is involved for local files or measurements.
|
package/docs/v2-verification.md
CHANGED
|
@@ -3,6 +3,167 @@
|
|
|
3
3
|
This file records dated checks. Older sections describe the alpha at the time
|
|
4
4
|
of each check; release-candidate results are recorded separately below.
|
|
5
5
|
|
|
6
|
+
## npm names and installation — 2026-11-07
|
|
7
|
+
|
|
8
|
+
Published `viewstl@2.0.0-rc.5` and `@omrips/viewstl@2.0.0-rc.5` with `latest`
|
|
9
|
+
pointing to rc.5. The existing scoped `next` tag was also advanced to rc.5.
|
|
10
|
+
Both READMEs document `npm install viewstl` and retain the scoped alternative.
|
|
11
|
+
All existing scoped versions remain available.
|
|
12
|
+
|
|
13
|
+
All 136 unit tests, strict browser/Node type checks and 37 legacy integrity
|
|
14
|
+
checks pass again. Both packed distributions pass Node ESM/CommonJS type checks
|
|
15
|
+
and runtime checks for browser exports, worker/CAD assets and STL/OBJ/3MF/STEP/IGES
|
|
16
|
+
analysis. Fresh public-registry installs without a version suffix pass those
|
|
17
|
+
runtime checks for both package names. Public tarball bytes and SHA-512 integrity
|
|
18
|
+
match the tested local archives; each package contains 40 files.
|
|
19
|
+
|
|
20
|
+
All 31 files under `build/` match the previously tested GitHub rc.5 distribution
|
|
21
|
+
byte for byte. No renderer changes were made and browser/device tests were not
|
|
22
|
+
rerun for this packaging update. The GitHub browser evidence below still applies
|
|
23
|
+
to those exact runtime bytes. Evidence: local `test-results/npm-stage.json` and
|
|
24
|
+
its referenced staging directory. See [maintainer workflow](npm-releases.md).
|
|
25
|
+
|
|
26
|
+
## GitHub root-layout release 2.0.0-rc.5 — 2026-11-07
|
|
27
|
+
|
|
28
|
+
The release worktree places the v2 sources/distribution in `src/` and `build/`.
|
|
29
|
+
The complete pre-v2 GitHub tree is archived under `legacy/v1/`; its 23 original
|
|
30
|
+
Git blobs and the 14-file local v1.14 snapshot pass SHA-256/size verification.
|
|
31
|
+
Historical sections below retain the paths and versions used at the time.
|
|
32
|
+
|
|
33
|
+
All **136 unit tests** pass, along with strict browser and Node TypeScript
|
|
34
|
+
consumers. Actual desktop Chrome 156, without device emulation, passes **46
|
|
35
|
+
browser checks**: 15 compatibility, 11 animation, 11 scene and 9 export checks.
|
|
36
|
+
These exercise the relocated classic/ESM entries, module workers, legacy mesh
|
|
37
|
+
bridge, STL/OBJ/3MF/STEP/IGES export/reimport, scene playback, cancellation,
|
|
38
|
+
context restoration and a responsive million-triangle STL export.
|
|
39
|
+
|
|
40
|
+
The packed `@omrips/viewstl@2.0.0-rc.5` tarball installs into a clean consumer
|
|
41
|
+
project. Browser ESM/CommonJS exports, version reporting, worker/CAD asset paths,
|
|
42
|
+
and server analysis of STL, OBJ, 3MF, STEP and IGES pass. Node analysis also
|
|
43
|
+
passes through the CommonJS entry. Archive contents exclude development fixtures,
|
|
44
|
+
legacy runtime copies and site/server files; license notices and lazy assets are included.
|
|
45
|
+
|
|
46
|
+
The layout update also corrects old harness references to the legacy parser and
|
|
47
|
+
worker directory. The compatibility animation assertion now waits for the public
|
|
48
|
+
completion callback and checks the public completed state, rather than assuming
|
|
49
|
+
the old private animation representation or a fixed wall-clock delay.
|
|
50
|
+
|
|
51
|
+
Evidence is retained locally in the original plugin checkout under
|
|
52
|
+
`test-results/github-v2-20261107/`. Physical mobile, Safari and Firefox validation
|
|
53
|
+
remain pending. This release does not update the preview website or npm registry.
|
|
54
|
+
|
|
55
|
+
## Live animation save/open verification — 2026-11-02
|
|
56
|
+
|
|
57
|
+
Verified the existing `20261102-f04f34e66b7c` release through the actual Save and
|
|
58
|
+
Open controls on `https://preview.viewstl.com/`, in desktop in-app Chromium.
|
|
59
|
+
No runtime changes or redeployment were needed. Two binary STL fixtures have
|
|
60
|
+
offset geometry centers: one runs reverse X rotation at 3 seconds per turn and
|
|
61
|
+
is paused; the other runs forward Z rotation at 7 seconds per turn.
|
|
62
|
+
|
|
63
|
+
Both VSB and VSJ were downloaded, the page was freshly reloaded, and the downloaded
|
|
64
|
+
files were opened and saved again. **40 checks pass** against the resulting files
|
|
65
|
+
and visible controls: two models, camera, position/scale/appearance, animation
|
|
66
|
+
definition, pivot/origin, pause state, exact paused time and pose, advancing running
|
|
67
|
+
time and a pose consistent with that time. VSB mesh coordinates match both their
|
|
68
|
+
original files and the re-saved archive. VSJ file references remain intact. The
|
|
69
|
+
paused model's elapsed time stayed exactly `7400.434000000001` ms in both formats;
|
|
70
|
+
the running model continued from each saved time instead of restarting.
|
|
71
|
+
|
|
72
|
+
A second pair of files was saved with both models paused. PNGs downloaded before
|
|
73
|
+
saving and after independently reopening each format are **byte-for-byte equal**.
|
|
74
|
+
VSB opens alone; VSJ was opened together with its two referenced STL files. Paused
|
|
75
|
+
models expose Resume with the restored axis, duration and direction. There were
|
|
76
|
+
no console errors on the final restored page. This is desktop-browser evidence,
|
|
77
|
+
not physical mobile or other-browser coverage.
|
|
78
|
+
|
|
79
|
+
The website workspace retains actual downloads, UI-state records, PNGs and
|
|
80
|
+
`verification.json` in `results/animation-roundtrip-20261102/`. Recheck those
|
|
81
|
+
artifacts with `node site/qa/verify-animation-downloads.mjs --images`; regenerate
|
|
82
|
+
the offset STL fixtures with `node site/qa/make-animation-fixtures.mjs`.
|
|
83
|
+
|
|
84
|
+
## Preview-site animation integration — 2026-11-02
|
|
85
|
+
|
|
86
|
+
Deployed to preview as `20261102-f04f34e66b7c`. The optional animation app binding
|
|
87
|
+
is bundled inside viewstl.js; the site's initializer is unchanged. The site adds
|
|
88
|
+
static controls under Models → Animation: axis, seconds per turn, direction and
|
|
89
|
+
Play/Pause/Resume/Stop. Off-center models spin about their center without moving
|
|
90
|
+
their visible pose. Editing uses current transforms, and adding/selecting files
|
|
91
|
+
preserves other models' animation. Print checks pause their targets and offer
|
|
92
|
+
explicit Resume while keeping the results panel open. Reduced-motion preference
|
|
93
|
+
pauses restored playback. Stopped animations also retain an equivalent static
|
|
94
|
+
VSJ pose with the original referenced mesh.
|
|
95
|
+
|
|
96
|
+
All **136 unit tests**, both strict type checks and the legacy guard pass.
|
|
97
|
+
Actual desktop Chromium 156 passes **25 new integration checks** and **96 existing
|
|
98
|
+
site checks**. New coverage includes invalid speed, concurrent models, live-pose
|
|
99
|
+
manual editing, drag entry, print pause/resume, VSB phase/pause restoration,
|
|
100
|
+
stopped off-center VSJ reopening with an identical PNG, callback composition,
|
|
101
|
+
clear/dispose/remount and simulated reduced motion. Keyboard Enter playback was
|
|
102
|
+
also exercised. 320px and 390px viewport checks show no horizontal overflow and
|
|
103
|
+
44px-high playback buttons; these are emulated widths, not physical touch tests.
|
|
104
|
+
|
|
105
|
+
All 29 public HTTPS files match the local SHA-256 manifest. Live browser smoke
|
|
106
|
+
checks cover loading, keyboard playback and print-check interaction. Nginx, relay
|
|
107
|
+
and Certbot remain active; configuration/service/binary hashes match the previous
|
|
108
|
+
release and SELinux remains enforcing. Initial gzip total is 57,897 bytes; the
|
|
109
|
+
viewer entry is 42,150 bytes. No new million-triangle or total-memory benchmark
|
|
110
|
+
was performed for the app controls; the earlier plugin measurement remains below.
|
|
111
|
+
Physical mobile, Safari/Firefox and actual hidden-tab behavior remain unverified.
|
|
112
|
+
|
|
113
|
+
Evidence: the site workspace's `results/animation-integration/` and
|
|
114
|
+
`results/deploy-20261102-f04f34e66b7c/`. Reproduce the browser checks through the
|
|
115
|
+
local-only `site/qa/animation.html` and `site/qa/index.html` pages. The QA harness
|
|
116
|
+
is excluded from deployment. npm is unchanged (`2.0.0-rc.4`); no GitHub push.
|
|
117
|
+
|
|
118
|
+
## Model animation — unreleased development update, 2026-11-02
|
|
119
|
+
|
|
120
|
+
The local plugin now has validated legacy delta/exact playback, per-model
|
|
121
|
+
pause/resume/state queries and transition/completion callbacks. Animation uses
|
|
122
|
+
elapsed frame time, retires finished tracks independently, stops on manual
|
|
123
|
+
transform edits and suspends on document hiding or context loss. VSJ and both
|
|
124
|
+
VSB APIs preserve animation phase, pause state, units and rotation pivot; animated
|
|
125
|
+
VSB meshes retain scale in metadata to avoid applying it twice on reopening.
|
|
126
|
+
The native WebGL2 renderer and existing worker architecture remain in use.
|
|
127
|
+
|
|
128
|
+
- All **132 Node tests pass** on Node.js 24.19.0, Windows. Nine new tests cover
|
|
129
|
+
mixed durations, frame cadence, pause/resume/suspension, manual changes,
|
|
130
|
+
replacement and copied state, scale/statistics invalidation, invalid numeric
|
|
131
|
+
inputs and overflow, scene validation, VSJ/VSB restoration and export snapshots.
|
|
132
|
+
- Browser and server-only strict TypeScript checks pass. The legacy guard passes
|
|
133
|
+
for tracked legacy files and all 14 archived files.
|
|
134
|
+
- **11 animation browser checks pass** in actual desktop Chromium 156 on Windows,
|
|
135
|
+
using workers and WebGL2. These cover constructor playback, concurrent models,
|
|
136
|
+
idle behavior, pause/resume/stop, modern and legacy scene restoration, group
|
|
137
|
+
starts, bad-scene rollback, print-check staleness, mesh/PNG snapshots, forced
|
|
138
|
+
context loss/restoration and resource cleanup. Context loss is deliberately
|
|
139
|
+
triggered with `WEBGL_lose_context`, not a hardware failure.
|
|
140
|
+
- Existing browser compatibility (**15**) and scene/rendering (**11**) checks
|
|
141
|
+
also pass: **37 passing browser checks** in total.
|
|
142
|
+
- A generated **1,000,000-triangle** model animated over 120 measured frame
|
|
143
|
+
intervals: median **16.7 ms**, p95 **16.8 ms**, maximum **16.9 ms**. Geometry
|
|
144
|
+
objects and GPU resources retained identity, with two GPU buffers and
|
|
145
|
+
72,375,000 bytes of resident geometry typed arrays. These are frame intervals
|
|
146
|
+
on one desktop, not GPU timings, allocation profiling or total process memory.
|
|
147
|
+
- The interactive example at `examples/v2/animation.html` runs locally and exposes
|
|
148
|
+
Play, Pause, Resume, Stop and Reset. No models or external assets are fetched.
|
|
149
|
+
|
|
150
|
+
Actual hidden-tab behavior remains unverified: automation tab changes in the
|
|
151
|
+
in-app browser and Chrome did not produce a document `visibilitychange` event.
|
|
152
|
+
The suspension/resumption code is covered by unit tests and the real WebGL
|
|
153
|
+
context-loss check. Firefox, Safari, physical phones/tablets, touch, reduced-motion
|
|
154
|
+
site integration and a total-memory profile have not been tested in this update.
|
|
155
|
+
|
|
156
|
+
Reproduce with `pnpm build`, `pnpm test`, `pnpm check:types`,
|
|
157
|
+
`pnpm check:node-types`, `pnpm check:legacy`, then `pnpm start`. Open
|
|
158
|
+
`tests/v2/animation-browser.html`, `tests/v2/browser.html` and
|
|
159
|
+
`tests/v2/scene-browser.html` and run their checks. The million-triangle and
|
|
160
|
+
background-tab checks have separate buttons on the animation page.
|
|
161
|
+
|
|
162
|
+
Evidence is retained locally in ignored `test-results/animation-*` files. The
|
|
163
|
+
package version is still `2.0.0-rc.4`; this development update has **not** been
|
|
164
|
+
published to npm or deployed. The proposed site work is described in
|
|
165
|
+
[the preview integration plan](v2-animation-site-plan.md).
|
|
166
|
+
|
|
6
167
|
## Runnable server example 2.0.0-rc.4 — 2026-10-20
|
|
7
168
|
|
|
8
169
|
The npm README now contains a clearly labeled server-only example, including
|
|
@@ -486,3 +647,11 @@ explicit close from an empty scene. The panel remains open throughout unrelated
|
|
|
486
647
|
activity while stale reports and active jobs are handled safely. All 112 Node
|
|
487
648
|
tests, strict types and 14 legacy hashes pass again. Evidence: sibling website
|
|
488
649
|
`results/print-persistent/` and `results/deploy-20261017-5b21747c4c8f/`.
|
|
650
|
+
|
|
651
|
+
## 2026-11-07 — rc.6 model tools
|
|
652
|
+
|
|
653
|
+
146 unit tests pass, as do strict browser/Node TypeScript checks and the 37-file legacy hash guard. Actual Windows Chrome 156 runs against the site built from the candidate npm tarball: 25 new model-tools integration checks, 25 animation regressions and 96 existing site regressions pass. New coverage includes locked/nonuniform resize, invalid input recovery, mm/inch separation, copy animation isolation, source references, shared geometry/GPU cleanup, camera presets, bookmark validation/merge, static and animated VSB/VSJ round trips, reset baselines, explicit 3MF/CAD units, and malformed-scene rollback. Surface area and enclosed volume use known closed/open fixtures; source-unit corrections also survive untransformed mesh export.
|
|
654
|
+
|
|
655
|
+
Manual desktop checks cover size inputs, keyboard Apply and on-demand measurements. Narrow widths are viewport emulation, not physical phone tests. No physical touch device, Safari/Firefox or broad large-CAD stress testing is claimed. The bounded detailed mesh checker may return an unavailable/inconclusive volume; source coordinates without units remain assumed mm until corrected.
|
|
656
|
+
|
|
657
|
+
Website evidence is retained outside its public build in `Viewstl/results/rc6/`; local-only reproducible browser harnesses are `site/qa/model-tools.html`, `animation.html` and `index.html`. Generated assets and the whole npm distribution are packaged together.
|
package/legacy/README.md
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
# Preserved legacy versions
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
On the v2 `main` branch, [`v1/`](v1/) contains the complete legacy GitHub
|
|
4
|
+
tree, including its original README, source, build, dependencies and license.
|
|
5
|
+
Its manifest records the original bytes and SHA-256 hashes of all 23 files.
|
|
6
|
+
|
|
7
|
+
The existing [`master` branch](https://github.com/omrips/viewstl/tree/master)
|
|
8
|
+
remains unchanged at the baseline below, preserving explicit master download
|
|
9
|
+
URLs. Existing tags are retained. New v2 source and output live at the root
|
|
10
|
+
under `src/` and `build/` on `main`; callers following the default branch
|
|
11
|
+
receive v2 and should review its migration notes.
|
|
6
12
|
|
|
7
13
|
## GitHub baseline
|
|
8
14
|
|
|
9
15
|
- Repository: https://github.com/omrips/viewstl
|
|
10
|
-
-
|
|
16
|
+
- Legacy branch: `master` (the default before v2)
|
|
11
17
|
- Baseline commit: `fbb7f5c3894862778c3a6c5d2630573e2496d01f`
|
|
12
|
-
-
|
|
13
|
-
- Latest
|
|
18
|
+
- Preservation tag: `legacy-before-v2-2026-09-30`
|
|
19
|
+
- Latest legacy version tag: `v1.13`
|
|
14
20
|
|
|
15
21
|
The baseline commit includes changes after the `v1.13` tag. Do not treat the
|
|
16
|
-
release tag and the
|
|
17
|
-
|
|
22
|
+
release tag and the legacy branch as identical. The v2 release preserves
|
|
23
|
+
both that branch and the existing version tags.
|
|
18
24
|
|
|
19
25
|
## Local website snapshot
|
|
20
26
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omrips/viewstl",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
3
|
+
"version": "2.0.0-rc.6",
|
|
4
4
|
"description": "Local-first STL, OBJ, 3MF, STEP and IGES viewer with native WebGL2 and transferable worker geometry",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,71 +18,54 @@
|
|
|
18
18
|
],
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"access": "public",
|
|
21
|
-
"tag": "
|
|
21
|
+
"tag": "latest",
|
|
22
22
|
"registry": "https://registry.npmjs.org/"
|
|
23
23
|
},
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
26
26
|
"url": "https://github.com/omrips/viewstl.git"
|
|
27
27
|
},
|
|
28
|
-
"main": "./build/
|
|
29
|
-
"module": "./build/
|
|
30
|
-
"types": "./build/
|
|
28
|
+
"main": "./build/viewstl.cjs",
|
|
29
|
+
"module": "./build/viewstl.js",
|
|
30
|
+
"types": "./build/viewstl.d.ts",
|
|
31
31
|
"exports": {
|
|
32
32
|
".": {
|
|
33
33
|
"import": {
|
|
34
|
-
"types": "./build/
|
|
35
|
-
"default": "./build/
|
|
34
|
+
"types": "./build/viewstl.d.ts",
|
|
35
|
+
"default": "./build/viewstl.js"
|
|
36
36
|
},
|
|
37
37
|
"require": {
|
|
38
|
-
"types": "./build/
|
|
39
|
-
"default": "./build/
|
|
38
|
+
"types": "./build/viewstl.d.cts",
|
|
39
|
+
"default": "./build/viewstl.cjs"
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
"./node": {
|
|
43
43
|
"node": {
|
|
44
44
|
"import": {
|
|
45
|
-
"types": "./build/
|
|
46
|
-
"default": "./build/
|
|
45
|
+
"types": "./build/node/index.d.ts",
|
|
46
|
+
"default": "./build/node/index.js"
|
|
47
47
|
},
|
|
48
48
|
"require": {
|
|
49
|
-
"types": "./build/
|
|
50
|
-
"default": "./build/
|
|
49
|
+
"types": "./build/node/index.d.cts",
|
|
50
|
+
"default": "./build/node/index.cjs"
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
|
-
"./worker": "./build/
|
|
55
|
-
"./browser": "./build/
|
|
56
|
-
"./assets/*": "./build
|
|
54
|
+
"./worker": "./build/viewstl.worker.js",
|
|
55
|
+
"./browser": "./build/stl_viewer.min.js",
|
|
56
|
+
"./assets/*": "./build/*",
|
|
57
57
|
"./package.json": "./package.json"
|
|
58
58
|
},
|
|
59
59
|
"files": [
|
|
60
|
-
"build
|
|
60
|
+
"build",
|
|
61
61
|
"LICENSE",
|
|
62
62
|
"docs/v2-usage.md",
|
|
63
63
|
"docs/v2-compatibility.md",
|
|
64
64
|
"docs/v2-verification.md",
|
|
65
|
+
"docs/releases/2.0.0-rc.6.md",
|
|
65
66
|
"legacy/README.md",
|
|
66
67
|
"THIRD-PARTY-NOTICES.txt"
|
|
67
68
|
],
|
|
68
|
-
"scripts": {
|
|
69
|
-
"build": "node scripts/build-v2.mjs",
|
|
70
|
-
"test": "node --test tests/v2/*.test.mjs",
|
|
71
|
-
"check:legacy": "node scripts/check-legacy.mjs",
|
|
72
|
-
"check:types": "tsc --noEmit --strict --module NodeNext --moduleResolution NodeNext --target ES2022 --lib ES2022,DOM tests/v2/types.ts",
|
|
73
|
-
"check:node-types": "tsc --noEmit --strict --module NodeNext --moduleResolution NodeNext --target ES2022 --lib ES2022 --types node tests/v2/node-types.mts tests/v2/node-types.cts",
|
|
74
|
-
"prepack": "node scripts/build-v2.mjs && node scripts/check-legacy.mjs",
|
|
75
|
-
"start": "node scripts/serve-v2.mjs"
|
|
76
|
-
},
|
|
77
|
-
"devDependencies": {
|
|
78
|
-
"@types/node": "^20.19.43",
|
|
79
|
-
"esbuild": "0.28.2",
|
|
80
|
-
"fflate": "0.8.3",
|
|
81
|
-
"occt-import-js": "0.0.23",
|
|
82
|
-
"prettier": "3.9.9",
|
|
83
|
-
"saxes": "6.0.0",
|
|
84
|
-
"typescript": "5.9.3"
|
|
85
|
-
},
|
|
86
69
|
"engines": {
|
|
87
70
|
"node": ">=20"
|
|
88
71
|
}
|
package/build/v2/README.md
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# Native WebGL2 build
|
|
2
|
-
|
|
3
|
-
Generated ViewSTL v2.00 release-candidate artifacts. `stl_viewer.min.js` and `viewstl.min.js` are
|
|
4
|
-
classic scripts exposing `StlViewer`. `viewstl.js` is the ES module;
|
|
5
|
-
`viewstl.cjs` is the CommonJS entry. Keep the module worker, `chunks/` and `cad/`
|
|
6
|
-
directories and license notices beside these files when deploying. See [usage](../../docs/v2-usage.md).
|
|
7
|
-
|
|
8
|
-
The existing `../stl_viewer.min.js` and its companion files remain the
|
|
9
|
-
legacy distribution. A v2 build must never overwrite those files.
|
|
10
|
-
|
|
11
|
-
See [the compatibility requirements](../../docs/v2-compatibility.md).
|
|
12
|
-
|
|
13
|
-
`node/` contains the separate server analysis entry points and worker, exported
|
|
14
|
-
as `@omrips/viewstl/node`. These resolve `cad/` inside the npm package; Node users
|
|
15
|
-
do not need to copy assets to a website.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a,b,c,d}from"./chunk-R3HNTB5A.js";import"./chunk-ZSV4PTIA.js";import"./chunk-JH3H3JWA.js";import"./chunk-JS56KC3I.js";import"./chunk-U33KANV7.js";export{d as parse3MF,a as safePath,b as unzipChecked,c as zipScene};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as k}from"./chunk-JS56KC3I.js";var z=Object.freeze({max_file_bytes:256*1024*1024,max_triangles:5e6,max_uncompressed_bytes:256*1024*1024,max_archive_entries:1024,max_memory_bytes:Number.MAX_SAFE_INTEGER});function O(e){if(typeof e!="string"||!/^#[\da-f]{6}$/i.test(e))throw new Error("Color must be #RRGGBB");return[1,3,5].map(i=>parseInt(e.slice(i,i+2),16)/255)}function U(e,i=null,I=z){if(!(e instanceof Float32Array)||!e.length||e.length%9)throw new Error("Geometry must contain complete triangles");if(e.length/9>I.max_triangles)throw new Error("Triangle limit exceeded");if(k(I,67108864+e.length/9*224),i&&(!(i instanceof Float32Array)||i.length!==e.length))throw new Error("Invalid vertex colors");let u={min:[1/0,1/0,1/0],max:[-1/0,-1/0,-1/0]};for(let r=0;r<e.length;r++){let f=e[r],t=r%3;if(!Number.isFinite(f))throw new Error("Non-finite vertex coordinate");if(u.min[t]=Math.min(u.min[t],f),u.max[t]=Math.max(u.max[t],f),i&&(!Number.isFinite(i[r])||i[r]<0||i[r]>1))throw new Error("Invalid vertex color")}let y=new Float32Array(e.length),b=new Float32Array(Math.ceil(e.length/9/64)*6),h=0,s=0,l=0;for(let r=0;r<e.length;r+=9){let f=e[r+3]-e[r],t=e[r+4]-e[r+1],c=e[r+5]-e[r+2],n=e[r+6]-e[r],o=e[r+7]-e[r+1],x=e[r+8]-e[r+2],w=t*x-c*o,M=c*n-f*x,g=f*o-t*n,E=Math.hypot(w,M,g);h+=E/2,s+=(e[r]*w+e[r+1]*M+e[r+2]*g)/6,E||l++;for(let a=0;a<9;a+=3)y[r+a]=w/(E||1),y[r+a+1]=M/(E||1),y[r+a+2]=g/(E||1);let m=Math.floor(r/9/64)*6;r/9%64===0&&b.set([1/0,1/0,1/0,-1/0,-1/0,-1/0],m);for(let a=0;a<9;a++){let d=a%3;b[m+d]=Math.min(b[m+d],e[r+a]),b[m+3+d]=Math.max(b[m+3+d],e[r+a])}}if(!Number.isFinite(h)||!Number.isFinite(s))throw new Error("Geometry magnitude exceeds numeric limits");return{positions:e,normals:y,colors:i,blocks:b,bounds:u,triangles:e.length/9,area:h,volume:Math.abs(s),degenerateTriangles:l}}function j(e,{smooth:i=!1,edges:I=!1,wire:u=!1,edgeAngle:y=1}={}){let b=new Map,h=new Uint32Array(e.length/3),s=[],l=[];for(let t=0;t<e.length;t+=3){let c=`${e[t]},${e[t+1]},${e[t+2]}`,n=b.get(c);n===void 0&&(n=s.length,b.set(c,n),s.push([e[t],e[t+1],e[t+2]]),l.push([0,0,0])),h[t/3]=n}let r=new Map;for(let t=0;t<e.length;t+=9){let c=e[t+3]-e[t],n=e[t+4]-e[t+1],o=e[t+5]-e[t+2],x=e[t+6]-e[t],w=e[t+7]-e[t+1],M=e[t+8]-e[t+2],g=[n*M-o*w,o*x-c*M,c*w-n*x],E=Math.hypot(...g)||1;for(let m=0;m<3;m++)if(i)for(let a=0;a<3;a++)l[h[t/3+m]][a]+=g[a];if(I||u)for(let m=0;m<3;m++){let a=h[t/3+m],d=h[t/3+(m+1)%3],A=a<d?`${a}:${d}`:`${d}:${a}`,F=g.map(v=>v/E),_=r.get(A);_?(_.count++,_.n.reduce((v,N,T)=>v+N*F[T],0)<Math.cos(y*Math.PI/180)&&(_.sharp=!0)):r.set(A,{a,b:d,n:F,count:1,sharp:!1})}}let f={};if(i){f.smoothNormals=new Float32Array(e.length);for(let t=0;t<h.length;t++){let c=l[h[t]],n=Math.hypot(...c)||1;f.smoothNormals.set(c.map(o=>o/n),t*3)}}for(let[t,c,n]of[[I,"edges",o=>o.count!==2||o.sharp],[u,"wire",()=>!0]])if(t){let o=[...r.values()].filter(n),x=new Float32Array(o.length*6);o.forEach((w,M)=>{x.set(s[w.a],M*6),x.set(s[w.b],M*6+3)}),f[c]=x,c==="edges"&&(f.edgeAngle=y)}return f}function D(e,i=[1,1,1],I=[0,0,0]){let u=new ArrayBuffer(84+e.triangles*50),y=new DataView(u),b=e.positions;new Uint8Array(u).set(new TextEncoder().encode("Binary STL by ViewSTL 2")),y.setUint32(80,e.triangles,!0);for(let h=0;h<e.triangles;h++){let s=84+h*50,l=Array.from({length:9},(n,o)=>(b[h*9+o]-I[o%3])*i[o%3]),r=[l[3]-l[0],l[4]-l[1],l[5]-l[2]],f=[l[6]-l[0],l[7]-l[1],l[8]-l[2]],t=[r[1]*f[2]-r[2]*f[1],r[2]*f[0]-r[0]*f[2],r[0]*f[1]-r[1]*f[0]],c=Math.hypot(...t)||1;for(let n=0;n<3;n++)y.setFloat32(s+n*4,t[n]/c,!0);for(let n=0;n<9;n++)y.setFloat32(s+12+n*4,l[n],!0);if(e.colors){let n=[0,1,2].map(o=>Math.round(e.colors[h*9+o]*31));y.setUint16(s+48,32768|n[0]<<10|n[1]<<5|n[2],!0)}}return u}export{z as a,O as b,U as c,j as d,D as e};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var f=Object.create;var s=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var i=Object.getOwnPropertyNames;var l=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty;var x=(t,r)=>()=>{try{return r||t((r={exports:{}}).exports,r),r.exports}catch(o){throw r=0,o}};var h=(t,r,o,e)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of i(r))!u.call(t,n)&&n!==o&&s(t,n,{get:()=>r[n],enumerable:!(e=c(r,n))||e.enumerable});return t};var M=(t,r,o)=>(o=t!=null?f(l(t)):{},h(r||!t||!t.__esModule?s(o,"default",{value:t,enumerable:!0}):o,t));var A=(t,r)=>t.map((o,e)=>o-r[e]),y=(t,r)=>t.map(o=>o*r);var w=(t,r)=>[t[1]*r[2]-t[2]*r[1],t[2]*r[0]-t[0]*r[2],t[0]*r[1]-t[1]*r[0]],F=t=>y(t,1/(Math.hypot(...t)||1)),I=()=>new Float64Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);function d(t,r){let o=new Float64Array(16);for(let e=0;e<4;e++)for(let n=0;n<4;n++)for(let a=0;a<4;a++)o[e*4+n]+=t[a*4+n]*r[e*4+a];return o}function _(t,r,o=1){let e=t[3]*r[0]+t[7]*r[1]+t[11]*r[2]+t[15]*o;return[0,1,2].map(n=>(t[n]*r[0]+t[4+n]*r[1]+t[8+n]*r[2]+t[12+n]*o)/(o&&e?e:1))}export{x as a,M as b,A as c,w as d,F as e,I as f,d as g,_ as h};
|