@virtualdisplay.io/client 4.0.0-alpha.3 → 4.0.0-alpha.32
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/CHANGELOG.md +254 -1
- package/README.md +127 -156
- package/dist/browser-7qZ1KQYo.cjs +8 -0
- package/dist/browser-B8yql1bQ.js +1226 -0
- package/dist/index.d.ts +672 -0
- package/dist/rolldown-runtime-5iZMYShA.cjs +1 -0
- package/dist/rolldown-runtime-CYdcPHCu.js +12 -0
- package/dist/virtualdisplay.client.cjs.js +691 -1
- package/dist/virtualdisplay.client.es.js +3142 -458
- package/dist/virtualdisplay.client.umd.js +698 -1
- package/package.json +3 -3
- package/dist/src/attributes/attribute.d.ts +0 -38
- package/dist/src/attributes/attribute.d.ts.map +0 -1
- package/dist/src/attributes/attributes.d.ts +0 -43
- package/dist/src/attributes/attributes.d.ts.map +0 -1
- package/dist/src/attributes/selections.d.ts +0 -16
- package/dist/src/attributes/selections.d.ts.map +0 -1
- package/dist/src/attributes/value.d.ts +0 -13
- package/dist/src/attributes/value.d.ts.map +0 -1
- package/dist/src/camera/camera.d.ts +0 -40
- package/dist/src/camera/camera.d.ts.map +0 -1
- package/dist/src/camera/index.d.ts +0 -4
- package/dist/src/camera/index.d.ts.map +0 -1
- package/dist/src/camera/position.d.ts +0 -43
- package/dist/src/camera/position.d.ts.map +0 -1
- package/dist/src/client/client.d.ts +0 -83
- package/dist/src/client/client.d.ts.map +0 -1
- package/dist/src/client/error.d.ts +0 -26
- package/dist/src/client/error.d.ts.map +0 -1
- package/dist/src/client/iframe-builder.d.ts +0 -25
- package/dist/src/client/iframe-builder.d.ts.map +0 -1
- package/dist/src/client/options.d.ts +0 -17
- package/dist/src/client/options.d.ts.map +0 -1
- package/dist/src/client/ready-state-tracker.d.ts +0 -26
- package/dist/src/client/ready-state-tracker.d.ts.map +0 -1
- package/dist/src/client/types.d.ts +0 -5
- package/dist/src/client/types.d.ts.map +0 -1
- package/dist/src/index.d.ts +0 -11
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/snapshot/index.d.ts +0 -3
- package/dist/src/snapshot/index.d.ts.map +0 -1
- package/dist/src/snapshot/photo.d.ts +0 -47
- package/dist/src/snapshot/photo.d.ts.map +0 -1
- package/dist/src/snapshot/snapshot.d.ts +0 -30
- package/dist/src/snapshot/snapshot.d.ts.map +0 -1
- package/dist/src/ui/viewer-config.d.ts +0 -63
- package/dist/src/ui/viewer-config.d.ts.map +0 -1
- package/dist/src/utils/logger.d.ts +0 -11
- package/dist/src/utils/logger.d.ts.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,264 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 4.0.0-alpha.
|
|
3
|
+
## 4.0.0-alpha.32
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
Add `features` to the app passed to `onAppResolved`: the features switched on for the app's owner, absent when there are none.
|
|
8
|
+
|
|
9
|
+
Let a submit handler registered with `configuration.onSubmit()` reject with a `DOMException` named `AbortError` when the shopper backs out. The button then returns to its label instead of reading done or failed.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
Fix the annotation marker control governing only the first model's pins when the viewer shows several models. One press now shows or hides every model's, including one added after the viewer started.
|
|
14
|
+
|
|
15
|
+
Fix the fullscreen button showing, and doing nothing, inside a frame that does not allow fullscreen.
|
|
16
|
+
|
|
17
|
+
Fix an error thrown while handling a message from the viewer escaping uncaught instead of being logged.
|
|
18
|
+
|
|
19
|
+
Fix the AR QR dialog staying on its loading state when the QR code cannot be drawn. It now shows the link to open on a phone instead.
|
|
20
|
+
|
|
21
|
+
Fix the built-in screenshot button starting a second capture on a repeated click. It now waits for the image, and can be used again if a capture fails.
|
|
22
|
+
|
|
23
|
+
## 4.0.0-alpha.31
|
|
24
|
+
|
|
25
|
+
### Minor Changes
|
|
26
|
+
|
|
27
|
+
Add `label` to `AttributeValue`: the word to show for a value, while `value` stays the key you pass back to `select`. Where the model names none it is the value made readable (`redWine` reads as "Red wine"), and on a measurement it is the size in whole millimetres. The viewer's own interface now renders in the language the model is configured in, where it always rendered English before: the toolbar, the camera controls and the configurator panel.
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
Fix the camera control buttons acting on a different rotation limit than the drag. A limit set on one side only, or a window covering a whole turn, no longer disables a button that bounds nothing, and a window that spans the back of the product now stops the buttons where the drag stops.
|
|
32
|
+
|
|
33
|
+
Darken the configurator's error colour so its button label reads at a higher contrast against it.
|
|
34
|
+
|
|
35
|
+
Fix the loading animation running indefinitely when the viewer never starts. If nothing is heard from the viewer within 30 seconds, the load-failure message is shown instead, so a blocked or unreachable viewer ends on a next step rather than a spinner. If the viewer does start after that, loading resumes instead of staying stuck on the failure message.
|
|
36
|
+
|
|
37
|
+
Round the AR QR code dialog's corners to the same radius as the buttons and controls beside it.
|
|
38
|
+
|
|
39
|
+
## 4.0.0-alpha.30
|
|
40
|
+
|
|
41
|
+
### Minor Changes
|
|
42
|
+
|
|
43
|
+
Export the types that public signatures already hand you. `SelectableSnapshot`, `SelectableAttribute`, `CameraPosition`, `CameraPositionState`, `CameraLimits`, `AnnotationVisibility`, `ViewerSettingsOverride`, `ClientAddress`, `ClientOptionsBase`, `ClientLogger` and `AVAILABILITY` can now be imported by name, so a callback you register or a value you receive can be typed without redeclaring its shape.
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
Drop the internal members from the published type definitions. `camera`, `snapshot`, `focus`, `configuration` and the attribute types now list only what you can call, so editor hover and autocomplete match the documented API.
|
|
48
|
+
|
|
49
|
+
## 4.0.0-alpha.29
|
|
50
|
+
|
|
51
|
+
### Major Changes
|
|
52
|
+
|
|
53
|
+
Rename the two selection events from `ui:select` and `ui:selected` to `vd:select` and `vd:selected`, so every event the client dispatches into your page carries the same `vd:` prefix. Change any `client.on('ui:select', ...)` to `client.on('vd:select', ...)`, and the same for `ui:selected`.
|
|
54
|
+
|
|
55
|
+
### Patch Changes
|
|
56
|
+
|
|
57
|
+
Fix duplicated type names in the published type definitions: `ViewerSettings`, `PricingDocument`, `AppSubmitSettings` and `Availability` no longer show up as `ViewerSettings$1` in editor hover and type errors. Type documentation now describes the API you call instead of how the viewer is built.
|
|
58
|
+
|
|
59
|
+
## 4.0.0-alpha.28
|
|
60
|
+
|
|
61
|
+
### Minor Changes
|
|
62
|
+
|
|
63
|
+
Add a marker toggle button to the viewer action bar for apps set to the `toggle-shown` or `toggle-hidden` annotation mode: the visitor shows or hides the annotation markers themselves, with the starting state you configured. The button only appears when the model has annotations and a toggle mode is active.
|
|
64
|
+
|
|
65
|
+
## 4.0.0-alpha.27
|
|
66
|
+
|
|
67
|
+
### Minor Changes
|
|
68
|
+
|
|
69
|
+
Add the per-app annotation visibility modes to the `viewerSettings.annotations` override: `'hide'`, `'show'`, `'toggle-shown'` and `'toggle-hidden'`, besides the existing booleans (`true` maps to `'show'`, `false` to `'hide'`). Markers now follow the mode configured on the app, and an override only speaks up when it differs from that mode.
|
|
70
|
+
|
|
71
|
+
## 4.0.0-alpha.26
|
|
72
|
+
|
|
73
|
+
### Minor Changes
|
|
74
|
+
|
|
75
|
+
Add `app` option to `ClientOptions` as an alternative to the `license` and `model` pair, mounting one specific app by its link key. The pair keeps working unchanged; when both are supplied, `app` wins and a warning is logged that the pair was ignored.
|
|
76
|
+
|
|
77
|
+
Add `AppType` with the known app types. `ResolvedAppInfo.appType` is typed as a plain string so an app type newer than your bundle still reaches `onAppResolved` for explicit handling.
|
|
78
|
+
|
|
79
|
+
Add a measurement slider for size attributes. A model that offers a size (width, depth, diameter) now renders it as a slider with the formatted value and unit beside it, and the model follows the drag live while only the released value counts as the chosen size.
|
|
80
|
+
|
|
81
|
+
Add `slug` to the `onAppResolved` callback payload: the resolved app's public slug, so a host page can address the app it embeds without knowing the slug in advance.
|
|
82
|
+
|
|
83
|
+
Add `onAppResolved(callback)`. The viewer reports which app it resolved (`appType`, `name`, and public submit settings as `ResolvedAppInfo`), and the callback fires immediately when the report already arrived.
|
|
84
|
+
|
|
85
|
+
## 4.0.0-alpha.25
|
|
86
|
+
|
|
87
|
+
### Minor Changes
|
|
88
|
+
|
|
89
|
+
Add `onSelectableChange(callback)` and `getSelectable(name)` to follow which
|
|
90
|
+
attribute values the buyer can still pick under the current selection. The
|
|
91
|
+
standard sidebar greys out values the selection rules out. Models without
|
|
92
|
+
exclusions behave exactly as before.
|
|
93
|
+
|
|
94
|
+
## 4.0.0-alpha.24
|
|
4
95
|
|
|
5
96
|
### Patch Changes
|
|
6
97
|
|
|
98
|
+
Accept `undefined` for the optional `ClientOptions` fields `language`, `debug` and `traceparent`. Projects that enable `exactOptionalPropertyTypes` can now pass a possibly-undefined value straight through without a type error.
|
|
99
|
+
|
|
100
|
+
## 4.0.0-alpha.23
|
|
101
|
+
|
|
102
|
+
### Patch Changes
|
|
103
|
+
|
|
104
|
+
Fix the sidebar configurator toggle button appearing separated from the AR and fullscreen buttons on narrow embeds. All three controls now sit together in one row instead of the toggle floating above them.
|
|
105
|
+
|
|
106
|
+
## 4.0.0-alpha.22
|
|
107
|
+
|
|
108
|
+
### Patch Changes
|
|
109
|
+
|
|
110
|
+
Fix the 3D model rendering behind the docked sidebar panel instead of next to it. On wide embeds the viewer now narrows to leave room for the panel, instead of the panel floating over part of the model.
|
|
111
|
+
|
|
112
|
+
## 4.0.0-alpha.21
|
|
113
|
+
|
|
114
|
+
### Minor Changes
|
|
115
|
+
|
|
116
|
+
Add `activateAr()` method to `VirtualdisplayClient`. Triggers the AR flow directly, useful when the built-in AR button is hidden with `viewerSettings.ar = false` and a custom control should start AR instead.
|
|
117
|
+
|
|
118
|
+
Add `client.onSyncChange(callback)`: subscribe to whether the viewer is currently live-syncing its configuration with another device in a hand-off (e.g. a desktop and the phone it was scanned to). The callback receives a boolean and fires again each time the connection state changes.
|
|
119
|
+
|
|
120
|
+
### Patch Changes
|
|
121
|
+
|
|
122
|
+
Change the desktop AR button's QR code to open the model in AR on the phone with the shopper's current configuration, instead of a fresh default viewer. The QR dialog now opens immediately and shows the code as soon as it is ready.
|
|
123
|
+
|
|
124
|
+
## 4.0.0-alpha.20
|
|
125
|
+
|
|
126
|
+
### Patch Changes
|
|
127
|
+
|
|
128
|
+
Internal refactoring.
|
|
129
|
+
|
|
130
|
+
## 4.0.0-alpha.19
|
|
131
|
+
|
|
132
|
+
### Patch Changes
|
|
133
|
+
|
|
134
|
+
Fix the AR and fullscreen buttons being hidden behind the configurator open button when the sidebar layout collapses on narrow embeds.
|
|
135
|
+
|
|
136
|
+
## 4.0.0-alpha.18
|
|
137
|
+
|
|
138
|
+
### Patch Changes
|
|
139
|
+
|
|
140
|
+
Internal improvements.
|
|
141
|
+
|
|
142
|
+
## 4.0.0-alpha.17
|
|
143
|
+
|
|
144
|
+
### Minor Changes
|
|
145
|
+
|
|
146
|
+
Add `client.sessionId`: the viewer's tracking session id, available once the viewer has loaded (and `undefined` before). Use it to correlate your own page events, such as a form conversion, with the viewer session the visitor was using.
|
|
147
|
+
|
|
148
|
+
## 4.0.0-alpha.16
|
|
149
|
+
|
|
150
|
+
### Patch Changes
|
|
151
|
+
|
|
152
|
+
Internal: the client now assembles over a shared `@virtualdisplay.io/client-core` engine (transport, base facades, configurator UI). No public API change.
|
|
153
|
+
|
|
154
|
+
## 4.0.0-alpha.15
|
|
155
|
+
|
|
156
|
+
### Patch Changes
|
|
157
|
+
|
|
158
|
+
`snapshot.take()` now fails with `SNAPSHOT_FAILED` if the viewer does not return the capture within 30 seconds, instead of leaving `photo.onError()` waiting forever when the iframe is unresponsive. Also removed unused internal `VirtualdisplayError` factory helpers (`noMapping`, `attributeNotFound`, `snapshotFailed`); the error codes and public constructor are unchanged.
|
|
159
|
+
|
|
160
|
+
## 4.0.0-alpha.14
|
|
161
|
+
|
|
162
|
+
### Major Changes
|
|
163
|
+
|
|
164
|
+
Remove the `cache` option from `ClientOptions`. It was a test-only override and is gone, so remove it from your options if you passed it.
|
|
165
|
+
|
|
166
|
+
## 4.0.0-alpha.13
|
|
167
|
+
|
|
168
|
+
### Minor Changes
|
|
169
|
+
|
|
170
|
+
Add `client.configuration` for configurator commerce: the buyer's selection resolves to a reference and price, read via `client.configuration.current`, `.onChange`, or the bubbling `vd:configuration-change` event. Register a handler with `.onSubmit(cb, { defaultLabel })` to switch on the call-to-action, which renders the price and a customer-labelled button under the controls.
|
|
171
|
+
|
|
172
|
+
Show the submit CTA for a configurator without prices. When no pricing document is present, a registered `onSubmit` handler (with a label) is enough to offer the button, and submitting hands over the buyer's current selection. A model with only attributes, or none at all, can now be submitted. With prices, the CTA stays gated on an `available` price.
|
|
173
|
+
|
|
174
|
+
Add `client.focus` to isolate and frame a single component of a model. `client.focus.set('Seat')` flies the camera to that component and dims the rest; `client.focus.clear()` returns to the overview. Read the current component with `client.focus.current`, react to changes with `client.focus.onChange((state) => ...)`, or listen for the bubbling `vd:focus-change` event (`VD_EVENTS.FOCUS_CHANGE`) on the container. Useful for guiding a buyer through a configurable product part by part.
|
|
175
|
+
|
|
176
|
+
### Patch Changes
|
|
177
|
+
|
|
178
|
+
Remove the unused `AttributeRegistry.defaults()` method and mark
|
|
179
|
+
`MutationFailedEvent` fields as `readonly`, matching the other public event
|
|
180
|
+
types. Internal cleanup with no API change.
|
|
181
|
+
|
|
182
|
+
## 4.0.0-alpha.12
|
|
183
|
+
|
|
184
|
+
### Minor Changes
|
|
185
|
+
|
|
186
|
+
Add `configuratorLayout` to `ViewerSettings`: choose where the attribute selector sits — `'inframe-bottom-left'` (default) or `'sidebar-right'` (a docked, scrollable right-hand panel) — or `'hidden'` to drop it (`client.select()` and `client.onChange()` keep working). Configure it per model in the portal, or override it via `viewerSettings`. This replaces the `attributeControls` field; swap `attributeControls: false` for `configuratorLayout: 'hidden'`.
|
|
187
|
+
|
|
188
|
+
### Patch Changes
|
|
189
|
+
|
|
190
|
+
Internal build-config fix. Align `vite.config.ts` with vite 7 typings: rename `rolldownOptions` to `rollupOptions` and drop the `oxc` minifier (vite 7 only accepts `terser` and `esbuild` and was silently falling back to esbuild). No change to the published bundle.
|
|
191
|
+
|
|
192
|
+
`VirtualdisplayClient.destroy()` now fails any pending `snapshot.take()` captures with `SNAPSHOT_FAILED` and clears registered `onMutationFailed` callbacks. Previously, callers awaiting `photo.onError()` after a destroy would wait forever and listeners outlived the client they were attached to.
|
|
193
|
+
|
|
194
|
+
## 4.0.0-alpha.11
|
|
195
|
+
|
|
196
|
+
### Patch Changes
|
|
197
|
+
|
|
198
|
+
Hide the fullscreen button on iPhone Safari, where the browser has no Fullscreen API for non-video elements. The button continues to work on desktop, iPad, and Android Chrome.
|
|
199
|
+
|
|
200
|
+
## 4.0.0-alpha.10
|
|
201
|
+
|
|
202
|
+
### Patch Changes
|
|
203
|
+
|
|
204
|
+
Fix AR button on mobile to launch native AR (Quick Look on iOS, Scene Viewer on Android) instead of the QR modal. Fix fullscreen button on iPhone Safari.
|
|
205
|
+
|
|
206
|
+
## 4.0.0-alpha.9
|
|
207
|
+
|
|
208
|
+
### Patch Changes
|
|
209
|
+
|
|
210
|
+
Fix state mix-up when multiple `VirtualdisplayClient` instances are mounted on the same page. Each client now correctly receives only its own server replies, so loading state, mapping, and mutation results no longer cross between viewers.
|
|
211
|
+
|
|
212
|
+
## 4.0.0-alpha.8
|
|
213
|
+
|
|
214
|
+
### Minor Changes
|
|
215
|
+
|
|
216
|
+
Add `viewerSettings` option to `ClientOptions`. Pass a partial `ViewerSettings` to override fields like `ar`, `fullscreen`, `cameraControls`, `attributeControls`, or `annotations` without changing the model's metadata.
|
|
217
|
+
|
|
218
|
+
Add annotations API: `client.annotations.setEnabled(enabled)` toggles annotation markers, and `startPlacing()` / `stopPlacing()` / `onPlaced(callback)` enable click-to-place flows for custom annotation editors. New `AnnotationPosition` type is exported.
|
|
219
|
+
|
|
220
|
+
Add `attributeControls` field to `ViewerSettings`. Set to `false` to hide the built-in attribute selector while keeping `client.select()` and `client.onChange()` available.
|
|
221
|
+
|
|
222
|
+
Fix toolbar buttons appearing briefly before the loading indicator clears.
|
|
223
|
+
|
|
224
|
+
Fix annotation markers ignoring `annotations: false` when set via the `viewerSettings` override.
|
|
225
|
+
|
|
226
|
+
Fix loading indicator hanging when model metadata is unavailable.
|
|
227
|
+
|
|
228
|
+
Internal code quality improvements.
|
|
229
|
+
|
|
230
|
+
## 4.0.0-alpha.7
|
|
231
|
+
|
|
232
|
+
### Patch Changes
|
|
233
|
+
|
|
234
|
+
Restructure standard interface layout to use corner slots. Camera controls and screenshot button now share a single card when both are enabled.
|
|
235
|
+
|
|
236
|
+
## 4.0.0-alpha.6
|
|
237
|
+
|
|
238
|
+
### Patch Changes
|
|
239
|
+
|
|
240
|
+
Fix camera control buttons accumulating clicks correctly.
|
|
241
|
+
|
|
242
|
+
## 4.0.0-alpha.5
|
|
243
|
+
|
|
244
|
+
### Patch Changes
|
|
245
|
+
|
|
246
|
+
Internal code quality improvements.
|
|
247
|
+
|
|
7
248
|
Ship complete TypeScript type definitions for all exports.
|
|
8
249
|
|
|
250
|
+
## 4.0.0-alpha.4
|
|
251
|
+
|
|
252
|
+
### Minor Changes
|
|
253
|
+
|
|
254
|
+
Add `language` option to `ClientOptions`. Pass a BCP 47 language tag (e.g. `"nl"`, `"de"`) to override the viewer language at initialisation time. Useful when embedding the same model on multiple pages with different languages.
|
|
255
|
+
|
|
256
|
+
Add built-in standard interface: loading indicator, toolbar (screenshot, AR, fullscreen), camera controls, and attribute controls are now rendered automatically inside the viewer container. UI is driven by `viewerSettings` received from the server and requires no manual setup.
|
|
257
|
+
|
|
258
|
+
### Patch Changes
|
|
259
|
+
|
|
260
|
+
Fix build target: use ESNext in tsconfig to resolve rolldown bundling issues with ES2022 class fields.
|
|
261
|
+
|
|
9
262
|
## 4.0.0-alpha.2
|
|
10
263
|
|
|
11
264
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
TypeScript library for embedding interactive 3D product models in web
|
|
4
4
|
applications.
|
|
5
5
|
|
|
6
|
+
- Built-in viewer UI with loading indicator, product controls, and action bar
|
|
6
7
|
- Simple attribute-based API for product configurators
|
|
7
8
|
- Server-driven configuration, no client-side mapping needed
|
|
8
9
|
- Fire-and-forget messaging with automatic state synchronisation
|
|
@@ -54,49 +55,45 @@ The server defines which attributes and values are available for each model.
|
|
|
54
55
|
The client receives this configuration automatically via postMessage. No
|
|
55
56
|
manual mapping required.
|
|
56
57
|
|
|
58
|
+
### Mounting a specific app
|
|
59
|
+
|
|
60
|
+
A model can have several apps (a plain viewer, a configurator), each with its
|
|
61
|
+
own link and its own configuration. Pass the app's link key as `app` to mount
|
|
62
|
+
that exact app:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { VirtualdisplayClient } from '@virtualdisplay.io/client';
|
|
66
|
+
|
|
67
|
+
const client = new VirtualdisplayClient({
|
|
68
|
+
parent: '#product-container',
|
|
69
|
+
app: 'sofa-deluxe-k3f9dm',
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`license` + `model` keeps working unchanged and shows the model's default
|
|
74
|
+
viewer. If both forms are supplied, `app` wins and a warning is logged that the
|
|
75
|
+
pair was ignored, so adding `app` to an existing integration is additive. One
|
|
76
|
+
of the two forms is required; supplying neither is a compile error.
|
|
77
|
+
|
|
57
78
|
## How it works
|
|
58
79
|
|
|
59
80
|
The 3D server hosts the viewer in an iframe, keeping WebGL complexity isolated
|
|
60
81
|
from your application. The client library handles all communication via
|
|
61
82
|
postMessage.
|
|
62
83
|
|
|
63
|
-
|
|
64
|
-
graph LR
|
|
65
|
-
A[Your application] -->|API calls| B[VirtualdisplayClient]
|
|
66
|
-
B -->|postMessage| C[3D server iframe]
|
|
67
|
-
C -->|Events| B
|
|
68
|
-
B -->|State updates| A
|
|
69
|
-
```
|
|
84
|
+

|
|
70
85
|
|
|
71
|
-
On startup, the server
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
sequenceDiagram
|
|
77
|
-
participant UI as Your UI
|
|
78
|
-
participant Client as VirtualdisplayClient
|
|
79
|
-
participant Server as 3D server
|
|
80
|
-
|
|
81
|
-
UI ->> Client: new VirtualdisplayClient(options)
|
|
82
|
-
Client ->> Client: Create iframe
|
|
83
|
-
Note right of Client: Outgoing messages queued
|
|
84
|
-
Server ->> Client: READY
|
|
85
|
-
Note right of Client: Queue flushed
|
|
86
|
-
opt UI or camera options configured
|
|
87
|
-
Client ->> Server: CONFIG
|
|
88
|
-
end
|
|
89
|
-
Server ->> Client: MAPPING (attributes + values + defaults)
|
|
90
|
-
Client ->> Client: Store attribute definitions
|
|
91
|
-
Server ->> Client: MUTATION result (defaults, isInitial: true)
|
|
92
|
-
Client ->> UI: onReady + onChange callbacks fire
|
|
93
|
-
```
|
|
86
|
+
On startup, the server sends the client its configuration (viewer settings,
|
|
87
|
+
camera limits) and available product attributes. The loading indicator shows
|
|
88
|
+
progress while the model downloads.
|
|
89
|
+
|
|
90
|
+

|
|
94
91
|
|
|
95
92
|
1. Client creates iframe; outgoing messages are queued until the server is ready.
|
|
96
|
-
2. Server sends `
|
|
97
|
-
3.
|
|
98
|
-
4. Server sends `
|
|
99
|
-
5. `
|
|
93
|
+
2. Server sends `HANDSHAKE` when its message listener is active; client flushes queue.
|
|
94
|
+
3. Server sends progress updates while the model downloads. The client displays these in the loading indicator.
|
|
95
|
+
4. Server sends `CONFIG` with viewer settings and camera limits from model metadata.
|
|
96
|
+
5. Server sends `MAPPING` with attribute definitions, values, and defaults. `onReady` fires.
|
|
100
97
|
|
|
101
98
|
## Product configuration
|
|
102
99
|
|
|
@@ -104,23 +101,7 @@ Configure product options by selecting attribute values. The server defines
|
|
|
104
101
|
which attributes exist (e.g. "Color", "Size") and which values each has
|
|
105
102
|
(e.g. "red", "blue"). You select values; the 3D model updates automatically.
|
|
106
103
|
|
|
107
|
-
|
|
108
|
-
sequenceDiagram
|
|
109
|
-
participant UI as Your UI
|
|
110
|
-
participant Client as VirtualdisplayClient
|
|
111
|
-
participant Server as 3D server
|
|
112
|
-
|
|
113
|
-
UI ->> Client: client.select('Color', 'blue')
|
|
114
|
-
Client ->> Server: MUTATION
|
|
115
|
-
Note right of Client: Fire-and-forget
|
|
116
|
-
Server ->> Server: Apply 3D changes
|
|
117
|
-
Server ->> Client: MUTATION result
|
|
118
|
-
alt All succeeded
|
|
119
|
-
Client ->> UI: onChange callbacks fire
|
|
120
|
-
else Some failed
|
|
121
|
-
Client ->> UI: onMutationFailed callbacks fire
|
|
122
|
-
end
|
|
123
|
-
```
|
|
104
|
+

|
|
124
105
|
|
|
125
106
|
- `select()` returns immediately; the result arrives asynchronously.
|
|
126
107
|
- Each attribute in the result has its own `success` flag and optional `error`.
|
|
@@ -134,8 +115,8 @@ client.select('Color', 'blue');
|
|
|
134
115
|
client.select('Size', 'large');
|
|
135
116
|
```
|
|
136
117
|
|
|
137
|
-
Can be called
|
|
138
|
-
|
|
118
|
+
Can be called immediately after construction. Selections are buffered until the
|
|
119
|
+
server handshake completes.
|
|
139
120
|
|
|
140
121
|
### Tracking changes
|
|
141
122
|
|
|
@@ -174,6 +155,14 @@ const colorAttr = client.getAttribute('Color');
|
|
|
174
155
|
if (colorAttr) {
|
|
175
156
|
colorAttr.select('blue');
|
|
176
157
|
colorAttr.getValues(); // AttributeValue[]
|
|
158
|
+
|
|
159
|
+
// Each value carries the word to render. `value` is the key you pass back to
|
|
160
|
+
// `select`; `label` is what to show, which the model may name
|
|
161
|
+
// ({ value: 'RAL3020', label: 'Signaalrood' }). Where the model names none,
|
|
162
|
+
// `label` is the value made readable: `redWine` reads as "Red wine".
|
|
163
|
+
// A measurement is the exception: its values are millimetres, and what to
|
|
164
|
+
// show depends on the model's unit and the reader's locale.
|
|
165
|
+
colorAttr.getValues().map((v) => ({ key: v.value, shown: v.label }));
|
|
177
166
|
colorAttr.getValue('blue'); // AttributeValue | undefined
|
|
178
167
|
colorAttr.onChange((value) => { ... });
|
|
179
168
|
}
|
|
@@ -192,22 +181,7 @@ client.onMutationFailed(({ attribute, value }) => {
|
|
|
192
181
|
Capture the current 3D view as an image. Useful for product shots, social
|
|
193
182
|
sharing, or saving configurations.
|
|
194
183
|
|
|
195
|
-
|
|
196
|
-
sequenceDiagram
|
|
197
|
-
participant UI as Your UI
|
|
198
|
-
participant Client as VirtualdisplayClient
|
|
199
|
-
participant Server as 3D server
|
|
200
|
-
|
|
201
|
-
UI ->> Client: client.snapshot.take('photo.png')
|
|
202
|
-
Client ->> Server: SNAPSHOT request
|
|
203
|
-
alt Success
|
|
204
|
-
Server ->> Client: SNAPSHOT data (base64)
|
|
205
|
-
Client ->> UI: onDeveloped callback fires
|
|
206
|
-
else Failure (e.g. no canvas)
|
|
207
|
-
Server ->> Client: SNAPSHOT error
|
|
208
|
-
Client ->> UI: onError callback fires
|
|
209
|
-
end
|
|
210
|
-
```
|
|
184
|
+

|
|
211
185
|
|
|
212
186
|
- Filename is validated client-side (extension, no path traversal).
|
|
213
187
|
- Server always responds, either with image data or an error reason.
|
|
@@ -236,21 +210,11 @@ Filename must end with `.png`. The server always returns PNG data.
|
|
|
236
210
|
|
|
237
211
|
## Camera
|
|
238
212
|
|
|
239
|
-
|
|
240
|
-
|
|
213
|
+
The standard interface includes built-in camera controls when they are
|
|
214
|
+
enabled in the Virtualdisplay portal. The camera can also be controlled
|
|
215
|
+
programmatically.
|
|
241
216
|
|
|
242
|
-
|
|
243
|
-
sequenceDiagram
|
|
244
|
-
participant UI as Your UI
|
|
245
|
-
participant Client as VirtualdisplayClient
|
|
246
|
-
participant Server as 3D server
|
|
247
|
-
|
|
248
|
-
UI ->> Client: client.camera.rotate(45).tilt(30).set()
|
|
249
|
-
Client ->> Server: CAMERA commands
|
|
250
|
-
Server ->> Client: CAMERA position
|
|
251
|
-
Client ->> UI: camera.onChange callbacks fire
|
|
252
|
-
Note right of Server: Position updates also fire on user<br/>interaction with the 3D viewport
|
|
253
|
-
```
|
|
217
|
+

|
|
254
218
|
|
|
255
219
|
- Commands accumulate via chaining; `.set()` sends them all at once.
|
|
256
220
|
- `.reset()` sends immediately without chaining.
|
|
@@ -263,7 +227,7 @@ sequenceDiagram
|
|
|
263
227
|
client.camera.rotate(45).set();
|
|
264
228
|
client.camera.rotate(90).tilt(45).zoom(150).set();
|
|
265
229
|
|
|
266
|
-
// Reset to
|
|
230
|
+
// Reset to the default position configured in the portal (sends immediately)
|
|
267
231
|
client.camera.reset();
|
|
268
232
|
```
|
|
269
233
|
|
|
@@ -283,49 +247,83 @@ console.log(client.cameraPosition.tilt);
|
|
|
283
247
|
console.log(client.cameraPosition.zoom);
|
|
284
248
|
```
|
|
285
249
|
|
|
286
|
-
##
|
|
250
|
+
## Annotations
|
|
287
251
|
|
|
288
|
-
|
|
289
|
-
|
|
252
|
+
Annotations are interactive markers placed on the 3D model. They are
|
|
253
|
+
configured and saved in the Virtualdisplay portal. The client library
|
|
254
|
+
exposes an API to toggle their visibility.
|
|
290
255
|
|
|
291
|
-
###
|
|
256
|
+
### Toggling annotations
|
|
292
257
|
|
|
293
258
|
```typescript
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
license: 'your-license',
|
|
297
|
-
model: 'product',
|
|
298
|
-
ui: {
|
|
299
|
-
arEnabled: false,
|
|
300
|
-
loadingIndicatorEnabled: false,
|
|
301
|
-
},
|
|
302
|
-
});
|
|
259
|
+
client.annotations.setEnabled(false); // Hide the markers
|
|
260
|
+
client.annotations.setEnabled(true); // Show them again
|
|
303
261
|
```
|
|
304
262
|
|
|
305
|
-
|
|
263
|
+
In an app that shows several models, this toggles the first model's markers.
|
|
264
|
+
`viewerSettings.annotations` (see below) and the marker button in the standard
|
|
265
|
+
interface govern every model's.
|
|
266
|
+
|
|
267
|
+
## Standard interface
|
|
268
|
+
|
|
269
|
+
The client renders a complete viewer UI automatically: loading indicator,
|
|
270
|
+
attribute controls, camera controls, and an action bar with AR, fullscreen,
|
|
271
|
+
and screenshot buttons. Each element is shown or hidden based on viewer
|
|
272
|
+
settings configured in the Virtualdisplay portal.
|
|
273
|
+
|
|
274
|
+
### Available settings
|
|
275
|
+
|
|
276
|
+
| Field | Type | Effect when `false` |
|
|
277
|
+
| -------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
278
|
+
| `ar` | `boolean` | Hides the AR button |
|
|
279
|
+
| `fullscreen` | `boolean` | Hides the fullscreen button |
|
|
280
|
+
| `screenshot` | `boolean` | Hides the screenshot button |
|
|
281
|
+
| `cameraControls` | `boolean` | Hides the camera control buttons |
|
|
282
|
+
| `annotations` | `boolean` | Hides all annotation markers |
|
|
283
|
+
| `language` | `string` | Sets the viewer UI language (BCP 47, e.g. `'nl'`, `'en'`, `'de'`) |
|
|
284
|
+
| `configuratorLayout` | `string` | Where the attribute controls sit, or whether they show: `'inframe-bottom-left'` (default), `'sidebar-right'` (a docked, scrollable right-hand panel), or `'hidden'` (no built-in selector, `client.select()` and `client.onChange()` keep working). |
|
|
285
|
+
|
|
286
|
+
### Overriding settings
|
|
287
|
+
|
|
288
|
+
The portal is the recommended place to change these settings: one source of
|
|
289
|
+
truth, and the viewer behaves the same wherever it is embedded.
|
|
290
|
+
|
|
291
|
+
We know there are situations where the portal alone cannot cover the case at
|
|
292
|
+
hand. For those, `ClientOptions.viewerSettings` accepts a partial override of
|
|
293
|
+
the same fields. Use it sparingly: every override is one more place where
|
|
294
|
+
the embedded viewer disagrees with the portal. Omitted fields fall back to
|
|
295
|
+
the metadata value.
|
|
296
|
+
|
|
297
|
+
Any override that differs from the metadata is logged with `console.warn`.
|
|
298
|
+
The warning is always emitted, so the deviation stays traceable when
|
|
299
|
+
something needs explaining.
|
|
306
300
|
|
|
307
301
|
```typescript
|
|
308
|
-
client
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
302
|
+
const client = new VirtualdisplayClient({
|
|
303
|
+
parent: '#product-container',
|
|
304
|
+
license: 'your-license-key',
|
|
305
|
+
model: 'sneaker',
|
|
306
|
+
viewerSettings: {
|
|
307
|
+
cameraControls: false,
|
|
308
|
+
},
|
|
309
|
+
});
|
|
316
310
|
```
|
|
317
311
|
|
|
318
312
|
## Lifecycle
|
|
319
313
|
|
|
320
314
|
### Ready state
|
|
321
315
|
|
|
322
|
-
Use `onReady` to know when the
|
|
323
|
-
|
|
324
|
-
|
|
316
|
+
Use `onReady` to know when the model and attribute definitions are available.
|
|
317
|
+
Not required before calling `select()` or `onChange()`, those are buffered
|
|
318
|
+
automatically.
|
|
325
319
|
|
|
326
320
|
```typescript
|
|
327
321
|
client.onReady(() => {
|
|
328
|
-
|
|
322
|
+
const values = client.getValues('Color');
|
|
323
|
+
console.log(
|
|
324
|
+
'Available colours:',
|
|
325
|
+
values.map((v) => v.value)
|
|
326
|
+
);
|
|
329
327
|
});
|
|
330
328
|
```
|
|
331
329
|
|
|
@@ -338,76 +336,49 @@ client.destroy();
|
|
|
338
336
|
## Constructor options
|
|
339
337
|
|
|
340
338
|
```typescript
|
|
339
|
+
import type { ViewerSettings } from '@virtualdisplay.io/client';
|
|
340
|
+
|
|
341
341
|
interface ClientOptions {
|
|
342
342
|
parent: string | HTMLElement; // Where to embed the 3D viewer
|
|
343
|
-
|
|
343
|
+
app?: string; // An app's link key: the alternative to license + model (see Mounting a specific app)
|
|
344
|
+
license: string; // License key from your Virtualdisplay account; with model, the classic address form
|
|
344
345
|
model: string; // Which 3D model to load
|
|
345
346
|
debug?: boolean; // Shows console logs for troubleshooting
|
|
346
|
-
language?: string; //
|
|
347
|
-
|
|
348
|
-
// UI elements (all visible by default)
|
|
349
|
-
ui?: {
|
|
350
|
-
arEnabled?: boolean;
|
|
351
|
-
fullscreenEnabled?: boolean;
|
|
352
|
-
loadingIndicatorEnabled?: boolean;
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
// Camera behaviour
|
|
356
|
-
camera?: {
|
|
357
|
-
initialRotate?: number; // Starting view angle (-180 to 180, 0 = front)
|
|
358
|
-
initialTilt?: number; // Starting elevation (0 = top view, 90 = side view)
|
|
359
|
-
initialZoom?: number; // Starting distance (100 = default, may need adjustment)
|
|
360
|
-
minZoom?: number; // Minimum zoom level constraint
|
|
361
|
-
maxZoom?: number; // Maximum zoom level constraint
|
|
362
|
-
minTilt?: number; // Minimum tilt angle constraint
|
|
363
|
-
maxTilt?: number; // Maximum tilt angle constraint
|
|
364
|
-
};
|
|
347
|
+
language?: string; // Viewer language: 'nl', 'en', or 'de'
|
|
348
|
+
viewerSettings?: Partial<ViewerSettings>; // Override fields from model metadata (see Standard interface)
|
|
365
349
|
}
|
|
366
350
|
```
|
|
367
351
|
|
|
352
|
+
One of the two address forms is required: `app`, or `license` + `model`. The
|
|
353
|
+
real type is a union that enforces this at compile time; the block above is the
|
|
354
|
+
flattened reference.
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
type ClientAddress =
|
|
358
|
+
| { app: string } // an app's link key
|
|
359
|
+
| { license: string; model: string }; // the classic address form
|
|
360
|
+
```
|
|
361
|
+
|
|
368
362
|
## Error codes
|
|
369
363
|
|
|
370
364
|
The client throws `VirtualdisplayError` for known error conditions:
|
|
371
365
|
|
|
372
366
|
| Code | Meaning |
|
|
373
|
-
|
|
367
|
+
| --------------------- | ------------------------------------------------ |
|
|
368
|
+
| `NO_MAPPING` | Attribute data not yet available from the server |
|
|
374
369
|
| `ATTRIBUTE_NOT_FOUND` | Requested attribute doesn't exist in the mapping |
|
|
375
370
|
| `VALUE_NOT_FOUND` | Requested value doesn't exist for attribute |
|
|
376
371
|
| `PARENT_NOT_FOUND` | Parent element for iframe not found |
|
|
377
372
|
| `INVALID_PARAMETER` | Invalid parameter (e.g. snapshot filename) |
|
|
378
373
|
| `SNAPSHOT_FAILED` | Server could not capture the snapshot |
|
|
379
374
|
|
|
380
|
-
## Real-world example
|
|
381
|
-
|
|
382
|
-
```typescript
|
|
383
|
-
const client = new VirtualdisplayClient({
|
|
384
|
-
parent: '#product-viewer',
|
|
385
|
-
license: 'your-license',
|
|
386
|
-
model: 'dining-table',
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
// Wire up your product option buttons. Selections are buffered until ready.
|
|
390
|
-
document.querySelectorAll('.color-option').forEach((button) => {
|
|
391
|
-
button.addEventListener('click', () => {
|
|
392
|
-
client.select('topMaterial', button.dataset.value);
|
|
393
|
-
});
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
// Keep buttons in sync with 3D state
|
|
397
|
-
client.onChange('topMaterial', (selectedValue) => {
|
|
398
|
-
document.querySelectorAll('.color-option').forEach((btn) => {
|
|
399
|
-
btn.classList.toggle('active', btn.dataset.value === selectedValue.value);
|
|
400
|
-
});
|
|
401
|
-
});
|
|
402
|
-
```
|
|
403
|
-
|
|
404
375
|
## Troubleshooting
|
|
405
376
|
|
|
406
377
|
**Iframe not loading:**
|
|
407
378
|
|
|
408
379
|
- Check that the parent element exists in the DOM
|
|
409
380
|
- Verify your license key is valid
|
|
410
|
-
- Ensure the model ID matches your
|
|
381
|
+
- Ensure the model ID matches your license
|
|
411
382
|
|
|
412
383
|
**Attributes not working:**
|
|
413
384
|
|