beckhoff-xts-viewer-3d 5.2.2 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +315 -315
- package/dist/index.cjs +7 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +742 -376
- package/dist/index.d.ts +742 -376
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/docs/screenshots/README.md +123 -123
- package/package.json +198 -194
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
# Screenshots
|
|
2
|
-
|
|
3
|
-
The README and docs-site image strip, captured straight out of the playground
|
|
4
|
-
through the viewer's own `exportScreenshot()` ref method. No external CAD
|
|
5
|
-
render and no hand-editing: every image below was produced by automating the
|
|
6
|
-
playground over `window.__viewer` / `window.__playground`.
|
|
7
|
-
|
|
8
|
-
## How to refresh
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npm i -g playwright && playwright install chromium # once
|
|
12
|
-
pnpm docs:capture-screenshots # the whole strip
|
|
13
|
-
pnpm docs:capture-screenshots --only 07,12 # by number or filename
|
|
14
|
-
pnpm docs:capture-screenshots --list
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
[`scripts/capture-screenshots.mjs`](../../scripts/capture-screenshots.mjs)
|
|
18
|
-
boots the playground's Vite dev server in-process, drives it in headless
|
|
19
|
-
Chromium and writes the files here. Playwright is deliberately not a
|
|
20
|
-
dependency of the repo — CI never runs this script and a browser download in
|
|
21
|
-
every install would not pay for itself.
|
|
22
|
-
|
|
23
|
-
What the script takes care of, and why each part is load-bearing:
|
|
24
|
-
|
|
25
|
-
- **Framing** is computed, not hand-held. A first pass fits the scene AABB to
|
|
26
|
-
the frustum analytically; a second pass renders a 640 × 360 alpha probe,
|
|
27
|
-
measures the bounding box of the non-transparent pixels and dollies + pans
|
|
28
|
-
until the geometry fills 94 % of the frame. An XTS layout is a thin ribbon
|
|
29
|
-
inside a large box, so the box fit alone leaves half the frame empty.
|
|
30
|
-
- **Readiness** is checked in pixels. `getBoundingBox()` goes non-empty as
|
|
31
|
-
soon as the config changes, while the GLBs are still streaming and the scene
|
|
32
|
-
subtree is a Suspense fallback — capturing then yields a blank frame with no
|
|
33
|
-
error. The script waits until an AABB-fit probe actually covers part of its
|
|
34
|
-
frame, and refuses to write a shot whose final frame is under 0.5 % covered.
|
|
35
|
-
- **Fonts are proxied through Node.** Station, area, dimension and annotation
|
|
36
|
-
labels fetch a WOFF from jsDelivr, and the drive-status icons resolve a glyph
|
|
37
|
-
font through `unicode-font-resolver`. A failed label font suspends the whole
|
|
38
|
-
scene; a failed glyph resolve renders a warning icon's "!" as exploded
|
|
39
|
-
geometry. Both are silent, so every font request is served from the Node
|
|
40
|
-
process, which can reach the network through a proxy.
|
|
41
|
-
- **Motion is stopped** before every capture: the mover drivers are switched
|
|
42
|
-
off and each shot sets its mover positions explicitly, so a re-run produces
|
|
43
|
-
the same image.
|
|
44
|
-
|
|
45
|
-
## Format
|
|
46
|
-
|
|
47
|
-
1920 × 1080 WebP at quality 0.92 on a solid `#eef0f3` ground, 4× MSAA. Full HD
|
|
48
|
-
is what the README and the docs site actually display, and the whole strip
|
|
49
|
-
weighs ~1.4 MB — it ships inside the npm tarball (`package.json#files`).
|
|
50
|
-
|
|
51
|
-
The ground is deliberately opaque rather than the transparent alpha the old
|
|
52
|
-
PNGs used: the AT2 housings are anodised anthracite (`#34383c`, see
|
|
53
|
-
[`scripts/materialLibrary.mjs`](../../scripts/materialLibrary.mjs)) and
|
|
54
|
-
disappear into a dark-mode README on a transparent canvas. `--background
|
|
55
|
-
transparent`, `--format png`, `--width`, `--height`, `--samples`, `--quality`
|
|
56
|
-
and `--fill` override the defaults for a one-off.
|
|
57
|
-
|
|
58
|
-
## File map
|
|
59
|
-
|
|
60
|
-
Every shot is taken from one of the machine layouts in
|
|
61
|
-
[`playground/src/configs.ts`](../../playground/src/configs.ts) — closed,
|
|
62
|
-
buildable tracks with the infeed modules, station stops and zones where a real
|
|
63
|
-
line would have them, rather than the calibration chains that visit every
|
|
64
|
-
module type in one run. A unit test pins that each layout closes.
|
|
65
|
-
|
|
66
|
-
| File | Demo key | Camera | Shows |
|
|
67
|
-
| --------------------------- | ----------------- | -------------- | ------------------------------------------------- |
|
|
68
|
-
| `01-packaging-line.webp` | `line-standard` | 3⁄4 isometric | hero — 5 m racetrack, 10 movers |
|
|
69
|
-
| `02-standard-at.webp` | `line-standard` | steep 3⁄4 | Standard AT: AT2001 / AT2000 / AT2050 |
|
|
70
|
-
| `03-eco-at2200.webp` | `line-eco` | 3⁄4 isometric | Eco AT2200 / AT2202 |
|
|
71
|
-
| `04-nct-tools.webp` | `line-nct` | 3⁄4 isometric | NCT modules + AT8200 tool carriers |
|
|
72
|
-
| `05-hygienic-ath.webp` | `line-hygienic` | 3⁄4 isometric | Hygienic ATH |
|
|
73
|
-
| `06-hepco-gfx.webp` | `line-standard` ¹ | 3⁄4 isometric | Hepco GFX2 rail and carriage |
|
|
74
|
-
| `07-materials-closeup.webp` | `line-standard` | close, low | PBR materials, stator packs, type plate |
|
|
75
|
-
| `08-multi-track.webp` | `line-dual` | steep 3⁄4 | two lines placed with `trackTransform` |
|
|
76
|
-
| `09-stations-areas.webp` | `line-standard` | steep 3⁄4 | stations, stops, ghost movers, zones |
|
|
77
|
-
| `10-dimensions.webp` | `line-standard` | steep 3⁄4 | dimensions along the track |
|
|
78
|
-
| `11-stator-heatmap.webp` | `line-standard` | steep 3⁄4 | green → red gradient along the centerline |
|
|
79
|
-
| `12-collision.webp` | `line-standard` | close 3⁄4 | two movers parked at a 1 mm overlap |
|
|
80
|
-
| `13-drive-status.webp` | `drive-status` | steep 3⁄4 | warning / error icons + tinted modules and movers |
|
|
81
|
-
| `14-feed-segments.webp` | `line-standard` | steep 3⁄4 | one strand per infeed, wrapping the loop seam |
|
|
82
|
-
| `15-measurements.webp` | `line-standard` | steep 3⁄4 | distance with ΔX/ΔY guides + two annotations |
|
|
83
|
-
| `16-selection.webp` | `line-standard` | steep 3⁄4 | two modules and one mover selected |
|
|
84
|
-
| `17-plan-view.webp` | `line-standard` | top-down ortho | `exportScreenshot({ mode: 'top-down' })` |
|
|
85
|
-
| `18-shadows.webp` | `line-standard` | low 3⁄4 | PCF-soft shadows + IBL |
|
|
86
|
-
| `19-perf-stress.webp` | `perf-stress` | steep 3⁄4 | 3 ovals × 250 movers = 750 |
|
|
87
|
-
|
|
88
|
-
¹ with `railSystem: 'HepcoGfx'` and a GFX2 1TC carriage.
|
|
89
|
-
|
|
90
|
-
The shot list itself lives at the top of the capture script; adding an image
|
|
91
|
-
means adding one entry there, not writing browser code.
|
|
92
|
-
|
|
93
|
-
## Doing it by hand
|
|
94
|
-
|
|
95
|
-
The playground still exposes the devtools handles the script drives, so a
|
|
96
|
-
one-off shot needs no tooling:
|
|
97
|
-
|
|
98
|
-
1. `pnpm dev`, pick the demo from the sidebar, frame the camera.
|
|
99
|
-
2. In the console:
|
|
100
|
-
|
|
101
|
-
```js
|
|
102
|
-
const r = await window.__viewer.exportScreenshot({
|
|
103
|
-
mode: 'current',
|
|
104
|
-
width: 1920,
|
|
105
|
-
height: 1080,
|
|
106
|
-
samples: 4,
|
|
107
|
-
format: 'webp',
|
|
108
|
-
quality: 0.92,
|
|
109
|
-
backgroundColor: '#eef0f3',
|
|
110
|
-
});
|
|
111
|
-
await fetch('/__save-screenshot?path=docs/screenshots/08-multi-track.webp', {
|
|
112
|
-
method: 'POST',
|
|
113
|
-
body: r.blob,
|
|
114
|
-
headers: { 'content-type': 'image/webp' },
|
|
115
|
-
});
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
`window.__setDemo('<DemoKey>')` switches the sample, `window.__playground`
|
|
119
|
-
holds the sidebar toggles the script uses (shadows, stations, dimensions,
|
|
120
|
-
selection, feed-segment colours, …) and the dev-only `POST
|
|
121
|
-
/__save-screenshot?path=…` middleware in
|
|
122
|
-
[`vite.config.ts`](../../vite.config.ts) writes the body bytes to a
|
|
123
|
-
whitelisted path under `docs/screenshots/`.
|
|
1
|
+
# Screenshots
|
|
2
|
+
|
|
3
|
+
The README and docs-site image strip, captured straight out of the playground
|
|
4
|
+
through the viewer's own `exportScreenshot()` ref method. No external CAD
|
|
5
|
+
render and no hand-editing: every image below was produced by automating the
|
|
6
|
+
playground over `window.__viewer` / `window.__playground`.
|
|
7
|
+
|
|
8
|
+
## How to refresh
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm i -g playwright && playwright install chromium # once
|
|
12
|
+
pnpm docs:capture-screenshots # the whole strip
|
|
13
|
+
pnpm docs:capture-screenshots --only 07,12 # by number or filename
|
|
14
|
+
pnpm docs:capture-screenshots --list
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
[`scripts/capture-screenshots.mjs`](../../scripts/capture-screenshots.mjs)
|
|
18
|
+
boots the playground's Vite dev server in-process, drives it in headless
|
|
19
|
+
Chromium and writes the files here. Playwright is deliberately not a
|
|
20
|
+
dependency of the repo — CI never runs this script and a browser download in
|
|
21
|
+
every install would not pay for itself.
|
|
22
|
+
|
|
23
|
+
What the script takes care of, and why each part is load-bearing:
|
|
24
|
+
|
|
25
|
+
- **Framing** is computed, not hand-held. A first pass fits the scene AABB to
|
|
26
|
+
the frustum analytically; a second pass renders a 640 × 360 alpha probe,
|
|
27
|
+
measures the bounding box of the non-transparent pixels and dollies + pans
|
|
28
|
+
until the geometry fills 94 % of the frame. An XTS layout is a thin ribbon
|
|
29
|
+
inside a large box, so the box fit alone leaves half the frame empty.
|
|
30
|
+
- **Readiness** is checked in pixels. `getBoundingBox()` goes non-empty as
|
|
31
|
+
soon as the config changes, while the GLBs are still streaming and the scene
|
|
32
|
+
subtree is a Suspense fallback — capturing then yields a blank frame with no
|
|
33
|
+
error. The script waits until an AABB-fit probe actually covers part of its
|
|
34
|
+
frame, and refuses to write a shot whose final frame is under 0.5 % covered.
|
|
35
|
+
- **Fonts are proxied through Node.** Station, area, dimension and annotation
|
|
36
|
+
labels fetch a WOFF from jsDelivr, and the drive-status icons resolve a glyph
|
|
37
|
+
font through `unicode-font-resolver`. A failed label font suspends the whole
|
|
38
|
+
scene; a failed glyph resolve renders a warning icon's "!" as exploded
|
|
39
|
+
geometry. Both are silent, so every font request is served from the Node
|
|
40
|
+
process, which can reach the network through a proxy.
|
|
41
|
+
- **Motion is stopped** before every capture: the mover drivers are switched
|
|
42
|
+
off and each shot sets its mover positions explicitly, so a re-run produces
|
|
43
|
+
the same image.
|
|
44
|
+
|
|
45
|
+
## Format
|
|
46
|
+
|
|
47
|
+
1920 × 1080 WebP at quality 0.92 on a solid `#eef0f3` ground, 4× MSAA. Full HD
|
|
48
|
+
is what the README and the docs site actually display, and the whole strip
|
|
49
|
+
weighs ~1.4 MB — it ships inside the npm tarball (`package.json#files`).
|
|
50
|
+
|
|
51
|
+
The ground is deliberately opaque rather than the transparent alpha the old
|
|
52
|
+
PNGs used: the AT2 housings are anodised anthracite (`#34383c`, see
|
|
53
|
+
[`scripts/materialLibrary.mjs`](../../scripts/materialLibrary.mjs)) and
|
|
54
|
+
disappear into a dark-mode README on a transparent canvas. `--background
|
|
55
|
+
transparent`, `--format png`, `--width`, `--height`, `--samples`, `--quality`
|
|
56
|
+
and `--fill` override the defaults for a one-off.
|
|
57
|
+
|
|
58
|
+
## File map
|
|
59
|
+
|
|
60
|
+
Every shot is taken from one of the machine layouts in
|
|
61
|
+
[`playground/src/configs.ts`](../../playground/src/configs.ts) — closed,
|
|
62
|
+
buildable tracks with the infeed modules, station stops and zones where a real
|
|
63
|
+
line would have them, rather than the calibration chains that visit every
|
|
64
|
+
module type in one run. A unit test pins that each layout closes.
|
|
65
|
+
|
|
66
|
+
| File | Demo key | Camera | Shows |
|
|
67
|
+
| --------------------------- | ----------------- | -------------- | ------------------------------------------------- |
|
|
68
|
+
| `01-packaging-line.webp` | `line-standard` | 3⁄4 isometric | hero — 5 m racetrack, 10 movers |
|
|
69
|
+
| `02-standard-at.webp` | `line-standard` | steep 3⁄4 | Standard AT: AT2001 / AT2000 / AT2050 |
|
|
70
|
+
| `03-eco-at2200.webp` | `line-eco` | 3⁄4 isometric | Eco AT2200 / AT2202 |
|
|
71
|
+
| `04-nct-tools.webp` | `line-nct` | 3⁄4 isometric | NCT modules + AT8200 tool carriers |
|
|
72
|
+
| `05-hygienic-ath.webp` | `line-hygienic` | 3⁄4 isometric | Hygienic ATH |
|
|
73
|
+
| `06-hepco-gfx.webp` | `line-standard` ¹ | 3⁄4 isometric | Hepco GFX2 rail and carriage |
|
|
74
|
+
| `07-materials-closeup.webp` | `line-standard` | close, low | PBR materials, stator packs, type plate |
|
|
75
|
+
| `08-multi-track.webp` | `line-dual` | steep 3⁄4 | two lines placed with `trackTransform` |
|
|
76
|
+
| `09-stations-areas.webp` | `line-standard` | steep 3⁄4 | stations, stops, ghost movers, zones |
|
|
77
|
+
| `10-dimensions.webp` | `line-standard` | steep 3⁄4 | dimensions along the track |
|
|
78
|
+
| `11-stator-heatmap.webp` | `line-standard` | steep 3⁄4 | green → red gradient along the centerline |
|
|
79
|
+
| `12-collision.webp` | `line-standard` | close 3⁄4 | two movers parked at a 1 mm overlap |
|
|
80
|
+
| `13-drive-status.webp` | `drive-status` | steep 3⁄4 | warning / error icons + tinted modules and movers |
|
|
81
|
+
| `14-feed-segments.webp` | `line-standard` | steep 3⁄4 | one strand per infeed, wrapping the loop seam |
|
|
82
|
+
| `15-measurements.webp` | `line-standard` | steep 3⁄4 | distance with ΔX/ΔY guides + two annotations |
|
|
83
|
+
| `16-selection.webp` | `line-standard` | steep 3⁄4 | two modules and one mover selected |
|
|
84
|
+
| `17-plan-view.webp` | `line-standard` | top-down ortho | `exportScreenshot({ mode: 'top-down' })` |
|
|
85
|
+
| `18-shadows.webp` | `line-standard` | low 3⁄4 | PCF-soft shadows + IBL |
|
|
86
|
+
| `19-perf-stress.webp` | `perf-stress` | steep 3⁄4 | 3 ovals × 250 movers = 750 |
|
|
87
|
+
|
|
88
|
+
¹ with `railSystem: 'HepcoGfx'` and a GFX2 1TC carriage.
|
|
89
|
+
|
|
90
|
+
The shot list itself lives at the top of the capture script; adding an image
|
|
91
|
+
means adding one entry there, not writing browser code.
|
|
92
|
+
|
|
93
|
+
## Doing it by hand
|
|
94
|
+
|
|
95
|
+
The playground still exposes the devtools handles the script drives, so a
|
|
96
|
+
one-off shot needs no tooling:
|
|
97
|
+
|
|
98
|
+
1. `pnpm dev`, pick the demo from the sidebar, frame the camera.
|
|
99
|
+
2. In the console:
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
const r = await window.__viewer.exportScreenshot({
|
|
103
|
+
mode: 'current',
|
|
104
|
+
width: 1920,
|
|
105
|
+
height: 1080,
|
|
106
|
+
samples: 4,
|
|
107
|
+
format: 'webp',
|
|
108
|
+
quality: 0.92,
|
|
109
|
+
backgroundColor: '#eef0f3',
|
|
110
|
+
});
|
|
111
|
+
await fetch('/__save-screenshot?path=docs/screenshots/08-multi-track.webp', {
|
|
112
|
+
method: 'POST',
|
|
113
|
+
body: r.blob,
|
|
114
|
+
headers: { 'content-type': 'image/webp' },
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`window.__setDemo('<DemoKey>')` switches the sample, `window.__playground`
|
|
119
|
+
holds the sidebar toggles the script uses (shadows, stations, dimensions,
|
|
120
|
+
selection, feed-segment colours, …) and the dev-only `POST
|
|
121
|
+
/__save-screenshot?path=…` middleware in
|
|
122
|
+
[`vite.config.ts`](../../vite.config.ts) writes the body bytes to a
|
|
123
|
+
whitelisted path under `docs/screenshots/`.
|