@omrips/viewstl 2.0.0-rc.3 → 2.0.0-rc.5
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 -170
- package/build/{v2/THIRD-PARTY-NOTICES.txt → THIRD-PARTY-NOTICES.txt} +1006 -1006
- package/build/{v2/cad → cad}/occt-import-js.source.txt +19 -19
- package/build/chunks/archive-JU75RPTU.js +1 -0
- package/build/{v2/chunks/cad-VY42CMP4.js → chunks/cad-4JYHORYZ.js} +1 -1
- package/build/{v2/chunks/chunk-JH3H3JWA.js → chunks/chunk-OP2L7L4N.js} +1 -1
- package/build/{v2/chunks/chunk-ZMK3UZZE.js → chunks/chunk-PQYEV7WH.js} +1 -1
- package/build/{v2/chunks/chunk-R3HNTB5A.js → chunks/chunk-Y6VY64LY.js} +1 -1
- package/build/{v2/chunks/export-7OP4ZGGJ.js → chunks/export-VM6OQCQJ.js} +3 -3
- package/build/{v2/chunks/export-cad-QPBT756V.js → chunks/export-cad-QXCB6UDU.js} +1 -1
- package/build/{v2/chunks/export-zip-EDCWH5PX.js → chunks/export-zip-PVXETVLK.js} +1 -1
- package/build/{v2/chunks/print-check-2PU7CSL3.js → chunks/print-check-NJ4IONC5.js} +1 -1
- package/build/{v2/chunks/scene-export-KQBS7VRJ.js → chunks/scene-export-ZIXMUNLI.js} +1 -1
- package/build/chunks/scene-reader-JGHERXR2.js +1 -0
- package/build/{v2/node → node}/analysis-worker.js +11 -11
- 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} +752 -125
- package/build/{v2/viewstl.d.cts → viewstl.d.cts} +50 -0
- package/build/{v2/viewstl.d.ts → viewstl.d.ts} +50 -0
- package/build/{v2/viewstl.js → viewstl.js} +752 -125
- package/build/viewstl.min.js +51 -0
- package/build/{v2/viewstl.worker.js → viewstl.worker.js} +1 -1
- package/docs/releases/2.0.0-rc.5.md +46 -0
- package/docs/v2-compatibility.md +5 -5
- package/docs/v2-usage.md +128 -21
- package/docs/v2-verification.md +158 -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/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/cad → cad}/occt-import-js.js +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-U33KANV7.js → chunks/chunk-IK3WL53C.js} +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
|
package/docs/v2-verification.md
CHANGED
|
@@ -3,6 +3,164 @@
|
|
|
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
|
+
## GitHub root-layout release 2.0.0-rc.5 — 2026-11-07
|
|
7
|
+
|
|
8
|
+
The release worktree places the v2 sources/distribution in `src/` and `build/`.
|
|
9
|
+
The complete pre-v2 GitHub tree is archived under `legacy/v1/`; its 23 original
|
|
10
|
+
Git blobs and the 14-file local v1.14 snapshot pass SHA-256/size verification.
|
|
11
|
+
Historical sections below retain the paths and versions used at the time.
|
|
12
|
+
|
|
13
|
+
All **136 unit tests** pass, along with strict browser and Node TypeScript
|
|
14
|
+
consumers. Actual desktop Chrome 156, without device emulation, passes **46
|
|
15
|
+
browser checks**: 15 compatibility, 11 animation, 11 scene and 9 export checks.
|
|
16
|
+
These exercise the relocated classic/ESM entries, module workers, legacy mesh
|
|
17
|
+
bridge, STL/OBJ/3MF/STEP/IGES export/reimport, scene playback, cancellation,
|
|
18
|
+
context restoration and a responsive million-triangle STL export.
|
|
19
|
+
|
|
20
|
+
The packed `@omrips/viewstl@2.0.0-rc.5` tarball installs into a clean consumer
|
|
21
|
+
project. Browser ESM/CommonJS exports, version reporting, worker/CAD asset paths,
|
|
22
|
+
and server analysis of STL, OBJ, 3MF, STEP and IGES pass. Node analysis also
|
|
23
|
+
passes through the CommonJS entry. Archive contents exclude development fixtures,
|
|
24
|
+
legacy runtime copies and site/server files; license notices and lazy assets are included.
|
|
25
|
+
|
|
26
|
+
The layout update also corrects old harness references to the legacy parser and
|
|
27
|
+
worker directory. The compatibility animation assertion now waits for the public
|
|
28
|
+
completion callback and checks the public completed state, rather than assuming
|
|
29
|
+
the old private animation representation or a fixed wall-clock delay.
|
|
30
|
+
|
|
31
|
+
Evidence is retained locally in the original plugin checkout under
|
|
32
|
+
`test-results/github-v2-20261107/`. Physical mobile, Safari and Firefox validation
|
|
33
|
+
remain pending. This release does not update the preview website or npm registry.
|
|
34
|
+
|
|
35
|
+
## Live animation save/open verification — 2026-11-02
|
|
36
|
+
|
|
37
|
+
Verified the existing `20261102-f04f34e66b7c` release through the actual Save and
|
|
38
|
+
Open controls on `https://preview.viewstl.com/`, in desktop in-app Chromium.
|
|
39
|
+
No runtime changes or redeployment were needed. Two binary STL fixtures have
|
|
40
|
+
offset geometry centers: one runs reverse X rotation at 3 seconds per turn and
|
|
41
|
+
is paused; the other runs forward Z rotation at 7 seconds per turn.
|
|
42
|
+
|
|
43
|
+
Both VSB and VSJ were downloaded, the page was freshly reloaded, and the downloaded
|
|
44
|
+
files were opened and saved again. **40 checks pass** against the resulting files
|
|
45
|
+
and visible controls: two models, camera, position/scale/appearance, animation
|
|
46
|
+
definition, pivot/origin, pause state, exact paused time and pose, advancing running
|
|
47
|
+
time and a pose consistent with that time. VSB mesh coordinates match both their
|
|
48
|
+
original files and the re-saved archive. VSJ file references remain intact. The
|
|
49
|
+
paused model's elapsed time stayed exactly `7400.434000000001` ms in both formats;
|
|
50
|
+
the running model continued from each saved time instead of restarting.
|
|
51
|
+
|
|
52
|
+
A second pair of files was saved with both models paused. PNGs downloaded before
|
|
53
|
+
saving and after independently reopening each format are **byte-for-byte equal**.
|
|
54
|
+
VSB opens alone; VSJ was opened together with its two referenced STL files. Paused
|
|
55
|
+
models expose Resume with the restored axis, duration and direction. There were
|
|
56
|
+
no console errors on the final restored page. This is desktop-browser evidence,
|
|
57
|
+
not physical mobile or other-browser coverage.
|
|
58
|
+
|
|
59
|
+
The website workspace retains actual downloads, UI-state records, PNGs and
|
|
60
|
+
`verification.json` in `results/animation-roundtrip-20261102/`. Recheck those
|
|
61
|
+
artifacts with `node site/qa/verify-animation-downloads.mjs --images`; regenerate
|
|
62
|
+
the offset STL fixtures with `node site/qa/make-animation-fixtures.mjs`.
|
|
63
|
+
|
|
64
|
+
## Preview-site animation integration — 2026-11-02
|
|
65
|
+
|
|
66
|
+
Deployed to preview as `20261102-f04f34e66b7c`. The optional animation app binding
|
|
67
|
+
is bundled inside viewstl.js; the site's initializer is unchanged. The site adds
|
|
68
|
+
static controls under Models → Animation: axis, seconds per turn, direction and
|
|
69
|
+
Play/Pause/Resume/Stop. Off-center models spin about their center without moving
|
|
70
|
+
their visible pose. Editing uses current transforms, and adding/selecting files
|
|
71
|
+
preserves other models' animation. Print checks pause their targets and offer
|
|
72
|
+
explicit Resume while keeping the results panel open. Reduced-motion preference
|
|
73
|
+
pauses restored playback. Stopped animations also retain an equivalent static
|
|
74
|
+
VSJ pose with the original referenced mesh.
|
|
75
|
+
|
|
76
|
+
All **136 unit tests**, both strict type checks and the legacy guard pass.
|
|
77
|
+
Actual desktop Chromium 156 passes **25 new integration checks** and **96 existing
|
|
78
|
+
site checks**. New coverage includes invalid speed, concurrent models, live-pose
|
|
79
|
+
manual editing, drag entry, print pause/resume, VSB phase/pause restoration,
|
|
80
|
+
stopped off-center VSJ reopening with an identical PNG, callback composition,
|
|
81
|
+
clear/dispose/remount and simulated reduced motion. Keyboard Enter playback was
|
|
82
|
+
also exercised. 320px and 390px viewport checks show no horizontal overflow and
|
|
83
|
+
44px-high playback buttons; these are emulated widths, not physical touch tests.
|
|
84
|
+
|
|
85
|
+
All 29 public HTTPS files match the local SHA-256 manifest. Live browser smoke
|
|
86
|
+
checks cover loading, keyboard playback and print-check interaction. Nginx, relay
|
|
87
|
+
and Certbot remain active; configuration/service/binary hashes match the previous
|
|
88
|
+
release and SELinux remains enforcing. Initial gzip total is 57,897 bytes; the
|
|
89
|
+
viewer entry is 42,150 bytes. No new million-triangle or total-memory benchmark
|
|
90
|
+
was performed for the app controls; the earlier plugin measurement remains below.
|
|
91
|
+
Physical mobile, Safari/Firefox and actual hidden-tab behavior remain unverified.
|
|
92
|
+
|
|
93
|
+
Evidence: the site workspace's `results/animation-integration/` and
|
|
94
|
+
`results/deploy-20261102-f04f34e66b7c/`. Reproduce the browser checks through the
|
|
95
|
+
local-only `site/qa/animation.html` and `site/qa/index.html` pages. The QA harness
|
|
96
|
+
is excluded from deployment. npm is unchanged (`2.0.0-rc.4`); no GitHub push.
|
|
97
|
+
|
|
98
|
+
## Model animation — unreleased development update, 2026-11-02
|
|
99
|
+
|
|
100
|
+
The local plugin now has validated legacy delta/exact playback, per-model
|
|
101
|
+
pause/resume/state queries and transition/completion callbacks. Animation uses
|
|
102
|
+
elapsed frame time, retires finished tracks independently, stops on manual
|
|
103
|
+
transform edits and suspends on document hiding or context loss. VSJ and both
|
|
104
|
+
VSB APIs preserve animation phase, pause state, units and rotation pivot; animated
|
|
105
|
+
VSB meshes retain scale in metadata to avoid applying it twice on reopening.
|
|
106
|
+
The native WebGL2 renderer and existing worker architecture remain in use.
|
|
107
|
+
|
|
108
|
+
- All **132 Node tests pass** on Node.js 24.19.0, Windows. Nine new tests cover
|
|
109
|
+
mixed durations, frame cadence, pause/resume/suspension, manual changes,
|
|
110
|
+
replacement and copied state, scale/statistics invalidation, invalid numeric
|
|
111
|
+
inputs and overflow, scene validation, VSJ/VSB restoration and export snapshots.
|
|
112
|
+
- Browser and server-only strict TypeScript checks pass. The legacy guard passes
|
|
113
|
+
for tracked legacy files and all 14 archived files.
|
|
114
|
+
- **11 animation browser checks pass** in actual desktop Chromium 156 on Windows,
|
|
115
|
+
using workers and WebGL2. These cover constructor playback, concurrent models,
|
|
116
|
+
idle behavior, pause/resume/stop, modern and legacy scene restoration, group
|
|
117
|
+
starts, bad-scene rollback, print-check staleness, mesh/PNG snapshots, forced
|
|
118
|
+
context loss/restoration and resource cleanup. Context loss is deliberately
|
|
119
|
+
triggered with `WEBGL_lose_context`, not a hardware failure.
|
|
120
|
+
- Existing browser compatibility (**15**) and scene/rendering (**11**) checks
|
|
121
|
+
also pass: **37 passing browser checks** in total.
|
|
122
|
+
- A generated **1,000,000-triangle** model animated over 120 measured frame
|
|
123
|
+
intervals: median **16.7 ms**, p95 **16.8 ms**, maximum **16.9 ms**. Geometry
|
|
124
|
+
objects and GPU resources retained identity, with two GPU buffers and
|
|
125
|
+
72,375,000 bytes of resident geometry typed arrays. These are frame intervals
|
|
126
|
+
on one desktop, not GPU timings, allocation profiling or total process memory.
|
|
127
|
+
- The interactive example at `examples/v2/animation.html` runs locally and exposes
|
|
128
|
+
Play, Pause, Resume, Stop and Reset. No models or external assets are fetched.
|
|
129
|
+
|
|
130
|
+
Actual hidden-tab behavior remains unverified: automation tab changes in the
|
|
131
|
+
in-app browser and Chrome did not produce a document `visibilitychange` event.
|
|
132
|
+
The suspension/resumption code is covered by unit tests and the real WebGL
|
|
133
|
+
context-loss check. Firefox, Safari, physical phones/tablets, touch, reduced-motion
|
|
134
|
+
site integration and a total-memory profile have not been tested in this update.
|
|
135
|
+
|
|
136
|
+
Reproduce with `pnpm build`, `pnpm test`, `pnpm check:types`,
|
|
137
|
+
`pnpm check:node-types`, `pnpm check:legacy`, then `pnpm start`. Open
|
|
138
|
+
`tests/v2/animation-browser.html`, `tests/v2/browser.html` and
|
|
139
|
+
`tests/v2/scene-browser.html` and run their checks. The million-triangle and
|
|
140
|
+
background-tab checks have separate buttons on the animation page.
|
|
141
|
+
|
|
142
|
+
Evidence is retained locally in ignored `test-results/animation-*` files. The
|
|
143
|
+
package version is still `2.0.0-rc.4`; this development update has **not** been
|
|
144
|
+
published to npm or deployed. The proposed site work is described in
|
|
145
|
+
[the preview integration plan](v2-animation-site-plan.md).
|
|
146
|
+
|
|
147
|
+
## Runnable server example 2.0.0-rc.4 — 2026-10-20
|
|
148
|
+
|
|
149
|
+
The npm README now contains a clearly labeled server-only example, including
|
|
150
|
+
installation, the `analyze.mjs` filename, a three-line script that prints JSON,
|
|
151
|
+
and the command to run it. This is a documentation update.
|
|
152
|
+
|
|
153
|
+
The exact example was extracted from the packed README and run with a binary
|
|
154
|
+
STL using the installed package on Node.js 24.19.0 on Windows. The resulting
|
|
155
|
+
JSON contains the expected dimensions, surface area, validated volume and mesh
|
|
156
|
+
checks. All 40 packaged files match the local release sources by SHA-256.
|
|
157
|
+
All 31 existing browser/Node runtime, declaration and CAD assets match the
|
|
158
|
+
public `2.0.0-rc.3` package apart from embedded version strings. The legacy
|
|
159
|
+
guard passes for tracked files and all 14 archived files. No runtime logic was
|
|
160
|
+
changed; the broader API verification below still describes the implementation.
|
|
161
|
+
|
|
162
|
+
Evidence is retained locally in `test-results/npm-2.0.0-rc.4/` (ignored by Git).
|
|
163
|
+
|
|
6
164
|
## Node.js model analysis 2.0.0-rc.3 — 2026-10-20
|
|
7
165
|
|
|
8
166
|
The new `@omrips/viewstl/node` export provides `analyzeFile`, `analyzeBuffer`
|
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.5",
|
|
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.5.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{b as p}from"./chunk-R3HNTB5A.js";import"./chunk-ZSV4PTIA.js";import{b as d}from"./chunk-JH3H3JWA.js";import"./chunk-JS56KC3I.js";import"./chunk-U33KANV7.js";var w=["flat","smooth","wireframe","edges","mesh","xray","studio","orientation"];function h(e,a){if(!w.includes(e))throw new Error("Invalid display mode");if(typeof a!="boolean")throw new Error("smooth_shading must be a boolean");return{display:e,smooth_shading:e==="smooth"||a}}function g(e){if(e==null)return null;if(!["x","y","z"].includes(e.axis))throw new Error("Section axis must be x, y or z");if(!Number.isFinite(e.position)||e.position<0||e.position>1)throw new Error("Section position must be between 0 and 1");if(e.flip!==void 0&&typeof e.flip!="boolean")throw new Error("Section flip must be a boolean");return{axis:e.axis,position:e.position,flip:e.flip??!1}}var c=["x","y","z"],l=(e,a,n=!1)=>{if(typeof e!="number"||!Number.isFinite(e)||n&&e<=0)throw new Error(`Invalid scene ${a}`);return e},u=e=>String(e||"").match(/\.(vsb|vsj)(?:[?#]|$)/i)?.[1].toLowerCase()||"";function m(e,a){if(!e||!Array.isArray(e.models)||!e.models.length||e.models.length>a.max_archive_entries)throw new Error("Invalid, empty or oversized scene manifest");let n={models:[]};for(let o of["center_models","auto_rotate","grid"])if(e[o]!==void 0){if(typeof e[o]!="boolean")throw new Error(`Invalid scene ${o}`);n[o]=e[o]}if(e.bg_color!==void 0&&(e.bg_color!=="transparent"&&d(e.bg_color),n.bg_color=e.bg_color),e.infinite_grid&&(n.infinite_grid={spacing:l(e.infinite_grid.spacing,"grid spacing",!0),height:l(e.infinite_grid.height,"grid height")}),e.camera_state){let o={};for(let r of["position","target","up"])o[r]=Object.fromEntries(c.map(s=>[s,l(e.camera_state[r]?.[s],"camera")]));let t=c.map(r=>o.position[r]-o.target[r]),i=c.map(r=>o.up[r]);if(!Math.hypot(...t)||!Math.hypot(...i)||!Math.hypot(t[1]*i[2]-t[2]*i[1],t[2]*i[0]-t[0]*i[2],t[0]*i[1]-t[1]*i[0]))throw new Error("Invalid scene camera");n.camera_state=o}for(let o of e.models){if(!o||typeof o.filename!="string"||!o.filename||o.filename.length>8192||/[\x00-\x1f\x7f]/.test(o.filename))throw new Error("Scene model filename is missing or invalid");if(u(o.filename))throw new Error("Nested scene references are not supported");let t={filename:o.filename};typeof o.orig_filename=="string"&&(t.orig_filename=o.orig_filename.slice(0,200));for(let i of c)for(let r of["","rotation","scale"]){let s=r+i;o[s]!==void 0&&(t[s]=l(o[s],s,r==="scale"))}if(o.scale!==void 0&&(t.scale=l(o.scale,"scale",!0)),o.opacity!==void 0&&(t.opacity=l(o.opacity,"opacity"),t.opacity<0||t.opacity>1))throw new Error("Invalid scene opacity");if(o.color!=null&&(o.color!=="transparent"&&d(o.color),t.color=o.color),t.units=o.units??"mm",!["mm","inch"].includes(t.units))throw new Error("Invalid scene units");if(Object.assign(t,h(o.display??"flat",o.smooth_shading??o.display==="smooth")),t.section=g(o.section),o.view_edges!==void 0&&typeof o.view_edges!="boolean")throw new Error("Invalid scene edges");t.view_edges=!!o.view_edges,n.models.push(t)}return n}function S(e,a,n){let o=Object.create(null),t=e;if(a==="vsb"){let i=p(e,n);if(t=i.get("json_data.vsj"),!t)throw new Error("VSB manifest json_data.vsj is missing");let r=m(JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(t)),n);for(let s of r.models){let f=i.get(s.filename);if(!f)throw new Error("VSB model file is missing: "+s.filename);o[s.filename]=f.buffer.slice(f.byteOffset,f.byteOffset+f.byteLength)}return{scene:r,files:o}}return{scene:m(JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(t)),n),files:null}}export{S as readSceneDocument};
|