@preference-sl/pref-viewer 2.16.0-beta.1 → 2.16.0-beta.11

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.md ADDED
@@ -0,0 +1,13 @@
1
+ # Proprietary License
2
+
3
+ Copyright © 2026 Preference S.L.
4
+ All rights reserved.
5
+
6
+ This software and its associated documentation are proprietary to Preference S.L.
7
+ The package is made available to authorized customers and partners only for use under the applicable commercial agreement, subscription, order form, statement of work, or other written agreement with Preference S.L.
8
+
9
+ Unless expressly permitted by Preference S.L. in writing, you may not copy, modify, sublicense, redistribute, resell, publish, reverse engineer, or make this software available to third parties.
10
+
11
+ No open-source license is granted by this package. In particular, publication to npm does not grant permission to use the software outside the rights expressly provided by Preference S.L.
12
+
13
+ For licensing questions, contact Preference S.L.
package/README.md ADDED
@@ -0,0 +1,486 @@
1
+ # @preference-sl/pref-viewer
2
+
3
+ `@preference-sl/pref-viewer` is a framework-agnostic Web Component for embedding an interactive 2D/3D product viewer in web applications. It renders glTF/GLB models with Babylon.js, supports SVG drawings, localized UI controls, runtime render settings, asset caching, and export flows for GLB, glTF ZIP, and USDZ.
4
+
5
+ ## Features
6
+
7
+ - Native custom elements: `<pref-viewer>`, `<pref-viewer-2d>`, `<pref-viewer-3d>`, `<pref-viewer-dialog>`, and `<pref-viewer-menu-3d>`.
8
+ - Babylon.js-based 3D visualization for glTF and GLB assets.
9
+ - 2D SVG drawing support with pan and zoom controls.
10
+ - Unified `<pref-viewer>` wrapper that coordinates 2D, 3D, menu, dialog, localization, and loading lifecycle.
11
+ - Sequential task queue for deterministic config, model, scene, materials, drawing, options, and culture updates.
12
+ - Direct URL, base64/data URI, and IndexedDB-backed asset loading.
13
+ - File cache validation using size and timestamp metadata.
14
+ - Runtime render settings for anti-aliasing, ambient occlusion, IBL, shadows, lighting time of day, and hover highlight.
15
+ - Localized UI copy for `en-EN` and `es-ES`.
16
+ - Export helpers for model, scene, or combined model + scene downloads.
17
+ - Type declarations for TypeScript and JSX usage.
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install @preference-sl/pref-viewer
23
+ ```
24
+
25
+ ## Basic usage
26
+
27
+ Import the package once in your application entry point. The import registers the custom elements globally.
28
+
29
+ ```js
30
+ import "@preference-sl/pref-viewer";
31
+ ```
32
+
33
+ Then use the element in HTML:
34
+
35
+ ```html
36
+ <pref-viewer
37
+ style="display: block; width: 100%; height: 600px;"
38
+ mode="3d"
39
+ culture="en-EN"
40
+ config='{
41
+ "model": {
42
+ "storage": {
43
+ "url": "https://example.com/assets/model.glb"
44
+ },
45
+ "visible": true
46
+ },
47
+ "scene": {
48
+ "storage": {
49
+ "url": "https://example.com/assets/scene.gltf"
50
+ },
51
+ "visible": true
52
+ }
53
+ }'
54
+ ></pref-viewer>
55
+ ```
56
+
57
+ ## JavaScript API usage
58
+
59
+ You can configure the viewer declaratively with attributes or imperatively with JavaScript. Prefer the JavaScript API when passing large objects, dynamic values, or user-driven updates.
60
+
61
+ ```js
62
+ const viewer = document.querySelector("pref-viewer");
63
+
64
+ viewer.loadConfig({
65
+ model: {
66
+ storage: {
67
+ url: "https://example.com/assets/model.glb",
68
+ },
69
+ visible: true,
70
+ },
71
+ scene: {
72
+ storage: {
73
+ url: "https://example.com/assets/scene.gltf",
74
+ },
75
+ visible: true,
76
+ },
77
+ culture: "en-EN",
78
+ });
79
+
80
+ viewer.setOptions({
81
+ camera: "MainCamera",
82
+ ibl: {
83
+ url: "https://example.com/assets/environment.hdr",
84
+ intensity: 1,
85
+ shadows: true,
86
+ },
87
+ lighting: {
88
+ timeOfDay: 0.5,
89
+ },
90
+ });
91
+ ```
92
+
93
+ ## Configuration model
94
+
95
+ The main `config` payload can include model, scene, materials, drawing, options, and culture data.
96
+
97
+ ```js
98
+ viewer.loadConfig({
99
+ model: {
100
+ storage: {
101
+ url: "https://example.com/model.glb",
102
+ },
103
+ visible: true,
104
+ },
105
+ scene: {
106
+ storage: {
107
+ url: "https://example.com/scene.gltf",
108
+ },
109
+ visible: true,
110
+ },
111
+ materials: {
112
+ storage: {
113
+ url: "https://example.com/materials.glb",
114
+ },
115
+ },
116
+ drawing: {
117
+ storage: {
118
+ url: "https://example.com/drawing.svg",
119
+ },
120
+ },
121
+ options: {
122
+ camera: "MainCamera",
123
+ ibl: {
124
+ url: "https://example.com/environment.hdr",
125
+ intensity: 1,
126
+ shadows: true,
127
+ },
128
+ render: {
129
+ ambientOcclusionEnabled: true,
130
+ antiAliasingEnabled: true,
131
+ iblEnabled: true,
132
+ shadowsEnabled: false,
133
+ showAnimationMenu: true,
134
+ showLightingTimeOfDay: true,
135
+ lightingTimeOfDay: 0.5,
136
+ highlightEnabled: true,
137
+ highlightColor: "#ff6700",
138
+ },
139
+ },
140
+ styles: {
141
+ colorPrimary: "#ff6700",
142
+ },
143
+ culture: "en-EN",
144
+ forceReload: false,
145
+ });
146
+ ```
147
+
148
+ ## Asset storage descriptors
149
+
150
+ Storage descriptors are passed through `model.storage`, `scene.storage`, `materials.storage`, or `drawing.storage`.
151
+
152
+ ### Remote URL
153
+
154
+ ```js
155
+ {
156
+ storage: {
157
+ url: "https://example.com/assets/model.glb"
158
+ }
159
+ }
160
+ ```
161
+
162
+ ### IndexedDB-backed asset
163
+
164
+ ```js
165
+ {
166
+ storage: {
167
+ db: "PrefConfiguratorDB",
168
+ table: "gltfModels",
169
+ id: "product-model-id",
170
+ url: "https://example.com/assets/fallback-model.glb"
171
+ }
172
+ }
173
+ ```
174
+
175
+ ### Base64 or data URI
176
+
177
+ ```js
178
+ {
179
+ storage: {
180
+ url: "data:model/gltf-binary;base64,BASE64_CONTENT"
181
+ }
182
+ }
183
+ ```
184
+
185
+ ## Attributes
186
+
187
+ `<pref-viewer>` observes the following attributes directly. When they change, the host component queues the corresponding load/configuration action or updates its own UI state.
188
+
189
+ | Attribute | Description |
190
+ | --- | --- |
191
+ | `config` | JSON string with the full viewer configuration. Forwards to `loadConfig(value)`. |
192
+ | `model` | JSON string with a model payload. Forwards to `loadModel(value)`. |
193
+ | `scene` | JSON string with a scene/environment payload. Forwards to `loadScene(value)`. |
194
+ | `materials` | JSON string with a materials payload. Forwards to `loadMaterials(value)`. |
195
+ | `drawing` | JSON string with a 2D drawing payload. Forwards to `loadDrawing(value)`. |
196
+ | `options` | JSON string with viewer options. Forwards to `setOptions(value)`. Use this for runtime render changes such as highlight, animation menu, IBL, shadows, and lighting time of day. |
197
+ | `culture` | UI locale. Supported values: `en-EN`, `es-ES`. Persists the resolved locale in `localStorage`. |
198
+ | `mode` | Viewer mode: `3d` or `2d`. Defaults to `3d`. |
199
+ | `show-model` | Shows or hides the current 3D model. Use `true` or `false`. |
200
+ | `show-scene` | Shows or hides the current 3D scene/environment. Use `true` or `false`. |
201
+ | `show-render-menu` | Shows or hides the floating 3D render settings menu. Defaults to visible. |
202
+ | `styles` | JSON string with supported style overrides. Currently supports `colorPrimary`, applies it as `--pref-viewer-color-primary`, updates `PrefViewerStyleVariables.colorPrimary`, and persists it in `localStorage`. |
203
+
204
+ ## Public methods
205
+
206
+ ### Loading and configuration
207
+
208
+ | Method | Description |
209
+ | --- | --- |
210
+ | `loadConfig(config)` | Queues a full configuration update. Accepts an object or JSON string with model, scene, materials, drawing, options, culture, styles, and visibility descriptors. |
211
+ | `loadModel(model)` | Queues a model update. |
212
+ | `loadScene(scene)` | Queues a scene/environment update. |
213
+ | `loadMaterials(materials)` | Queues a materials update. |
214
+ | `loadDrawing(drawing)` | Queues a 2D drawing update. |
215
+ | `setOptions(options)` | Queues camera, material, IBL, lighting, animation-menu, highlight, and render option updates. |
216
+ | `setStyles(styles)` | Queues supported runtime style overrides. Currently supports `{ colorPrimary }`, persists it in `localStorage`, updates `PrefViewerStyleVariables.colorPrimary`, and applies `--pref-viewer-color-primary`. |
217
+ | `setIBL(ibl)` | Convenience wrapper for `setOptions({ ibl })`. |
218
+ | `setCulture(culture)` | Changes the active UI locale and persists it in `localStorage`. |
219
+ | `setMode(mode)` | Switches between `2d` and `3d`. |
220
+ | `getDebugInfo()` | Returns a 3D runtime diagnostic snapshot when the internal 3D component and controller are available. |
221
+
222
+ ### Visibility and navigation
223
+
224
+ | Method | Description |
225
+ | --- | --- |
226
+ | `showModel()` / `hideModel()` | Shows or hides the loaded model. |
227
+ | `showScene()` / `hideScene()` | Shows or hides the loaded scene/environment. |
228
+ | `syncVisibility(name, isVisible)` | Synchronizes `model` or `scene` visibility with the corresponding reflected attribute. |
229
+ | `zoomCenter()` | Centers the 2D drawing view. |
230
+ | `zoomExtentsAll()` | Fits all 2D drawing content in view. |
231
+ | `zoomIn()` / `zoomOut()` | Controls 2D drawing zoom. |
232
+ | `focusModel()` | Moves focus to the current model interaction target when available. |
233
+
234
+ ### Semantic selection and turnable state
235
+
236
+ | Method | Description |
237
+ | --- | --- |
238
+ | `setSelectableElements(elements)` | Defines which host element ids are selectable. Accepts strings or objects with `id`/`Id`. |
239
+ | `setSelectedElements(elements)` | Defines selected elements. Accepts strings or objects with `id`/`Id` and optional `highlights`/`Highlights`. |
240
+ | `applySelectionState(state)` | Applies selectable and selected state in one call. Accepts `selectableIds`/`selectables` and `selectedItems`/`selectedIds`/`selected`. |
241
+ | `clearSelectedElements()` | Clears selected elements while preserving the selectable set. |
242
+ | `clearSelectableElements()` | Clears selectable elements while preserving the selected set. |
243
+ | `clearSelectionState()` | Clears all semantic selection state. |
244
+ | `getSelectionState()` | Returns `{ selectableIds, selectedIds, selectedItems }`. |
245
+ | `notifyElementClick(element)` | Emits `pref-viewer-element-click` from a host-forwarded element id or detail object. |
246
+ | `startTurnable(options)` | Starts semantic turnable state and emits `pref-viewer-3d-turnable-changed`. |
247
+ | `stopTurnable()` | Stops semantic turnable state. |
248
+ | `toggleTurnable(options)` | Toggles semantic turnable state. |
249
+ | `getTurnableState()` | Returns `{ running, speed, direction }`. |
250
+
251
+ ### Animation controls
252
+
253
+ | Method | Description |
254
+ | --- | --- |
255
+ | `getAnimations()` | Returns available model animations with state, progress, loop, and affected node ids. |
256
+ | `playAnimation(name, action)` | Controls a named animation. Supported actions are delegated to `BabylonJSAnimationController`. |
257
+ | `setAnimationProgress(name, progress)` | Sets animation progress from `0` to `1`. |
258
+ | `setAnimationLoop(name, loop)` | Enables or disables looping for a named animation. |
259
+
260
+ ### Dialogs and downloads
261
+
262
+ | Method | Description |
263
+ | --- | --- |
264
+ | `openDialog(title, content, footer)` | Opens a viewer dialog. |
265
+ | `closeDialog()` | Closes the active viewer dialog. |
266
+ | `downloadModelGLB()` / `downloadModelGLTF()` / `downloadModelUSDZ()` | Exports the current model. |
267
+ | `downloadSceneGLB()` / `downloadSceneGLTF()` / `downloadSceneUSDZ()` | Exports the current scene/environment. |
268
+ | `downloadModelAndSceneGLB()` / `downloadModelAndSceneGLTF()` / `downloadModelAndSceneUSDZ()` | Exports the combined model and scene. |
269
+
270
+ ## Public properties
271
+
272
+ ### Setters
273
+
274
+ These setters are convenience bridges for framework bindings and property-based integration.
275
+
276
+ | Property | Description |
277
+ | --- | --- |
278
+ | `config` | Forwards to `loadConfig(value)`. |
279
+ | `model` | Forwards to `loadModel(value)`. |
280
+ | `scene` | Forwards to `loadScene(value)`. |
281
+ | `materials` | Forwards to `loadMaterials(value)`. |
282
+ | `drawing` | Forwards to `loadDrawing(value)`. |
283
+ | `options` | Forwards to `setOptions(value)`. |
284
+ | `styles` | Forwards to `setStyles(value)`. |
285
+ | `culture` | Forwards to `setCulture(value)`. |
286
+ | `mode` | Forwards to `setMode(value)`. |
287
+
288
+ ### Getters
289
+
290
+ | Property | Description |
291
+ | --- | --- |
292
+ | `culture` | Current resolved locale. |
293
+ | `isInitialized` | Whether the root viewer has completed initialization. |
294
+ | `isLoaded` | Whether the root viewer considers the current load complete. |
295
+ | `isLoading` | Whether a load operation is currently in progress. |
296
+ | `isMode2D` | `true` when the current mode is `2d`. |
297
+ | `isMode3D` | `true` when the current mode is `3d`. |
298
+
299
+ ## Events
300
+
301
+ The component emits custom events so host applications can integrate loading indicators, error states, and viewer controls. Public event payloads do not include `source`. Only root-level events without an explicit 2D/3D scope include `detail.mode`, and that value is always the current `<pref-viewer>` mode (`"2d"` or `"3d"`).
302
+
303
+ ### General Events
304
+
305
+ | Event | Emitted by | Legacy alias | Description |
306
+ | --- | --- | --- | --- |
307
+ | `pref-viewer-initialized` | `<pref-viewer>` | None | The root component has been mounted and initialized. |
308
+ | `pref-viewer-loading` | `<pref-viewer>` | None | A 2D or 3D load operation has started. Includes `detail.mode` with the current root mode. |
309
+ | `pref-viewer-loaded` | `<pref-viewer>` | None | A 2D or 3D load operation completed. Includes `detail.mode` with the current root mode. |
310
+ | `pref-viewer-error` | `<pref-viewer>` | None | A 2D or 3D operation failed. Includes `detail.mode` with the current root mode. |
311
+ | `pref-viewer-selection-state-changed` | `<pref-viewer>` | None | The semantic selection state changed. |
312
+ | `pref-viewer-element-click` | `<pref-viewer>` | None | A selectable element was clicked or forwarded by the host integration. |
313
+
314
+ ### 3D Events
315
+
316
+ | Event | Emitted by | Legacy alias | Description |
317
+ | --- | --- | --- | --- |
318
+ | `pref-viewer-3d-loading` | `<pref-viewer>`, `<pref-viewer-3d>` | `scene-loading` | A 3D scene/model/material/options operation has started. |
319
+ | `pref-viewer-3d-loaded` | `<pref-viewer>`, `<pref-viewer-3d>` | `scene-loaded` | A 3D scene/model/material/options operation completed. Includes operation details when available. |
320
+ | `pref-viewer-3d-error` | `<pref-viewer>` | `scene-error` | A 3D operation failed. |
321
+ | `pref-viewer-3d-options-applying` | `<pref-viewer-3d>` | `scene-setting-options` | 3D viewer options are being applied. |
322
+ | `pref-viewer-3d-options-applied` | `<pref-viewer-3d>` | `scene-set-options` | 3D viewer options were applied. |
323
+ | `pref-viewer-3d-render-settings-change-requested` | `<pref-viewer-menu-3d>` | None | The 3D settings menu requested render-setting changes. |
324
+ | `pref-viewer-3d-animation-changed` | Opening animation controller | None | A model animation state changed. |
325
+ | `pref-viewer-3d-turnable-changed` | `<pref-viewer>` | None | The semantic turnable state changed. |
326
+
327
+ ### 2D Events
328
+
329
+ | Event | Emitted by | Legacy alias | Description |
330
+ | --- | --- | --- | --- |
331
+ | `pref-viewer-2d-loading` | `<pref-viewer>`, `<pref-viewer-2d>` | `drawing-loading` | A 2D drawing load started. |
332
+ | `pref-viewer-2d-loaded` | `<pref-viewer>`, `<pref-viewer-2d>` | `drawing-loaded` | A 2D drawing load completed. |
333
+ | `pref-viewer-2d-error` | `<pref-viewer>`, `<pref-viewer-2d>` | `drawing-error` | A 2D drawing operation failed. |
334
+ | `pref-viewer-2d-viewport-changed` | `<pref-viewer>`, `<pref-viewer-2d>` | None | The 2D drawing pan/zoom viewport changed. |
335
+
336
+ ### Internal Listeners
337
+
338
+ `<pref-viewer>` listens to `pref-viewer-2d-viewport-changed` from `<pref-viewer-2d>`, `pref-viewer-3d-loaded` and `pref-viewer-3d-error` from `<pref-viewer-3d>`, and `pref-viewer-3d-render-settings-change-requested` from `<pref-viewer-menu-3d>`. `BabylonJSController` listens to `pref-viewer-3d-animation-changed` from the nearest `<pref-viewer-3d>` host.
339
+
340
+ Example:
341
+
342
+ ```js
343
+ const viewer = document.querySelector("pref-viewer");
344
+
345
+ viewer.addEventListener("pref-viewer-3d-loaded", (event) => {
346
+ console.log("Viewer 3D loaded", event.detail);
347
+ });
348
+
349
+ viewer.addEventListener("pref-viewer-3d-error", (event) => {
350
+ console.error("Viewer 3D failed", event.detail);
351
+ });
352
+ ```
353
+
354
+ ## Render settings
355
+
356
+ Render settings can be passed through `setOptions`, `loadConfig({ options: { render } })`, property setters, or the built-in 3D menu.
357
+
358
+ ```js
359
+ viewer.setOptions({
360
+ render: {
361
+ antiAliasingEnabled: true,
362
+ ambientOcclusionEnabled: true,
363
+ iblEnabled: true,
364
+ shadowsEnabled: false,
365
+ showAnimationMenu: true,
366
+ highlightEnabled: true,
367
+ highlightColor: "#ff6700",
368
+ showLightingTimeOfDay: true,
369
+ lightingTimeOfDay: 0.5,
370
+ },
371
+ });
372
+ ```
373
+
374
+ | Setting | Type | Behavior |
375
+ | --- | --- | --- |
376
+ | `antiAliasingEnabled` | `boolean` | Enables/disables antialiasing. Changes are persisted and can trigger a render-settings reload. |
377
+ | `ambientOcclusionEnabled` | `boolean` | Enables/disables SSAO. Changes are persisted and can trigger a render-settings reload. |
378
+ | `iblEnabled` | `boolean` | Enables/disables image-based lighting. Changes are persisted and can trigger a render-settings reload. |
379
+ | `shadowsEnabled` | `boolean` | Enables/disables shadows. Changes are persisted and can trigger a render-settings reload. |
380
+ | `showAnimationMenu` | `boolean`/`"false"` | Enables the animation control menu when model animations are available. Applies immediately, persists, and refreshes menu availability. |
381
+ | `highlightEnabled` | `boolean`/`"false"` | Enables/disables hover highlight for animation openings. Applies immediately and persists. |
382
+ | `highlightColor` | `string` | Hex color used by hover highlight. Applies immediately and persists. |
383
+ | `showLightingTimeOfDay` | `boolean`/`"false"` | Shows or hides the time-of-day slider. When set to `false` without an explicit `lightingTimeOfDay`, the viewer resets `lightingTimeOfDay` to the default `0.5`. |
384
+ | `lightingTimeOfDay` | `number` | Normalized time of day from `0` to `1`; `0.5` is the default noon/day value. Applies immediately and persists unless `persist: false` is used by transient playback. |
385
+
386
+ Render settings are persisted in `localStorage` under the `pref-viewer/render-settings` key when changed through the runtime settings flow. The menu is always synchronized from the effective controller settings after changes from the menu, `setOptions`, or `loadConfig`.
387
+
388
+ ## Runtime styles
389
+
390
+ Runtime styles can be passed through the `styles` attribute, the `styles` property setter, `setStyles(styles)`, or `loadConfig({ styles })`.
391
+
392
+ ```html
393
+ <pref-viewer styles='{"colorPrimary":"#0055cc"}'></pref-viewer>
394
+ ```
395
+
396
+ ```js
397
+ viewer.setStyles({
398
+ colorPrimary: "#0055cc",
399
+ });
400
+ ```
401
+
402
+ Only `colorPrimary` is currently supported. The value updates `PrefViewerStyleVariables.colorPrimary`, is exposed on the host as `--pref-viewer-color-primary`, and is persisted in `localStorage` under `pref-viewer/styles`. Persisted styles are restored when a new `<pref-viewer>` instance is created and connected.
403
+
404
+ ## Localization
405
+
406
+ The default locale is `en-EN`. The viewer currently includes translations for:
407
+
408
+ - `en-EN`
409
+ - `es-ES`
410
+
411
+ ```html
412
+ <pref-viewer culture="es-ES"></pref-viewer>
413
+ ```
414
+
415
+ ```js
416
+ viewer.setCulture("en-EN");
417
+ ```
418
+
419
+ ## Development
420
+
421
+ Install dependencies:
422
+
423
+ ```bash
424
+ npm install
425
+ ```
426
+
427
+ Run tests:
428
+
429
+ ```bash
430
+ npm test
431
+ ```
432
+
433
+ Start the local playground:
434
+
435
+ ```bash
436
+ npm start
437
+ ```
438
+
439
+ The playground is available from `playground/index.html` and serves the project through `http-server` after bundling the local source.
440
+
441
+ ## Package scripts
442
+
443
+ | Script | Description |
444
+ | --- | --- |
445
+ | `npm run build` | Bundles `src/index.js` into `dist/bundle.js` with esbuild. This is the standard ESM playground/runtime build. |
446
+ | `npm run build:prefweb` | Creates a production webpack UMD build for PrefWeb consumption. It limits output to a single chunk and emits `dist/bundle-umd.js`. |
447
+ | `npm run build:prefweb:dev` | Creates a development webpack UMD build with external source maps for PrefWeb/browser debugging. Source map module names point back to project source paths. |
448
+ | `npm start` | Builds the standard bundle and starts a local HTTP server on port `8080`. |
449
+ | `npm test` | Runs the Vitest test suite. |
450
+ | `npm run release` | Creates a standard-version release. |
451
+ | `npm run release:beta` | Creates a beta prerelease with standard-version. |
452
+
453
+ ## TypeScript and JSX
454
+
455
+ The package ships `index.d.ts`, including JSX support for `<pref-viewer>`.
456
+
457
+ ```tsx
458
+ export function ProductViewer() {
459
+ return (
460
+ <pref-viewer
461
+ model={JSON.stringify({
462
+ storage: {
463
+ url: "https://example.com/assets/model.glb",
464
+ },
465
+ })}
466
+ />
467
+ );
468
+ }
469
+ ```
470
+
471
+ ## Notes for integrators
472
+
473
+ - The component is a Web Component, so it can be used from plain HTML, React, Vue, Angular, or any framework that supports custom elements.
474
+ - Give the element an explicit width and height. Babylon.js needs a measurable canvas container.
475
+ - Use object-based JavaScript APIs for complex payloads. Attributes must be valid JSON strings.
476
+ - Remote assets must be reachable by the browser and must satisfy the expected CORS policy.
477
+ - glTF files with external resources are resolved and cached by the viewer when possible.
478
+ - Avoid repeatedly replacing large assets if only visibility, camera, lighting, render, or material options changed.
479
+ - Use `pref-viewer-initialized` only as a component-readiness signal. If a host generates model data asynchronously, wait for the host data-ready signal before calling `loadConfig()`.
480
+ - For PrefWeb integration, consume the webpack UMD build (`bundle-umd.js`) and prefer development UMD builds while debugging source maps.
481
+
482
+ ## License
483
+
484
+ Proprietary. Copyright (c) 2026 Preference S.L. All rights reserved.
485
+
486
+ This package is published for authorized Preference S.L. customers and partners. Use, distribution, and access are governed by the applicable commercial agreement with Preference S.L. See [LICENSE.md](./LICENSE.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preference-sl/pref-viewer",
3
- "version": "2.16.0-beta.1",
3
+ "version": "2.16.0-beta.11",
4
4
  "description": "Web Component to preview GLTF models with Babylon.js",
5
5
  "author": "Alex Moreno Palacio <amoreno@preference.es>",
6
6
  "scripts": {
@@ -19,7 +19,7 @@
19
19
  "publishConfig": {
20
20
  "access": "public"
21
21
  },
22
- "license": "MIT",
22
+ "license": "SEE LICENSE IN LICENSE.md",
23
23
  "type": "module",
24
24
  "main": "src/index.js",
25
25
  "types": "index.d.ts",
@@ -35,11 +35,11 @@
35
35
  "index.d.ts"
36
36
  ],
37
37
  "dependencies": {
38
- "@babylonjs/core": "^8.50.5",
39
- "@babylonjs/loaders": "^8.50.5",
40
- "@babylonjs/serializers": "^8.50.5",
41
- "@panzoom/panzoom": "^4.6.0",
42
- "babylonjs-gltf2interface": "^8.50.5",
38
+ "@babylonjs/core": "^9.11.0",
39
+ "@babylonjs/loaders": "^9.11.0",
40
+ "@babylonjs/serializers": "^9.11.0",
41
+ "@panzoom/panzoom": "^4.6.2",
42
+ "babylonjs-gltf2interface": "^9.11.0",
43
43
  "buffer": "^6.0.3",
44
44
  "idb": "^8.0.3",
45
45
  "is-svg": "^6.1.0",
@@ -8,7 +8,7 @@ import OpeningAnimationMenu from "./babylonjs-animation-opening-menu.js";
8
8
  * - Tracks animation state (paused, closed, opened, opening, closing).
9
9
  * - Synchronizes animation progress and UI controls.
10
10
  * - Handles loop mode and progress threshold logic.
11
- * - Dispatches `prefviewer-animation-update` events with animation state snapshots.
11
+ * - Dispatches `pref-viewer-3d-animation-changed` events with animation state snapshots.
12
12
  * - Provides methods for play, pause, go to opened/closed, and progress control.
13
13
  * - Manages the animation control menu (OpeningAnimationMenu) and its callbacks.
14
14
  *
@@ -20,12 +20,17 @@ import OpeningAnimationMenu from "./babylonjs-animation-opening-menu.js";
20
20
  * - pause(): Pauses the current animation.
21
21
  * - goToOpened(): Moves animation to the fully opened state.
22
22
  * - goToClosed(): Moves animation to the fully closed state.
23
+ * - setProgress(progress): Seeks the animation to a normalized position (0–1), snapping to ends when within the threshold.
24
+ * - setLoop(loop): Enables or disables loop mode and syncs the control menu if visible.
23
25
  * - showControls(canvas, openingAnimations): Displays the animation control menu and sets up callbacks.
24
26
  * - hideControls(): Hides the animation control menu.
25
27
  * - isControlsVisible(): Returns true if the control menu is visible for this animation.
26
28
  *
27
29
  * Public Properties:
28
- * - state: Returns the current animation state.
30
+ * - state: Returns the current animation state (one of OpeningAnimation.states).
31
+ * - progress: Returns the normalized progress (0–1) derived from the current frame position.
32
+ * - loop: Returns whether loop mode is currently enabled.
33
+ * - nodes: Returns a copy of the node ID array affected by this animation.
29
34
  *
30
35
  * Private Methods:
31
36
  * - #getNodesFromAnimationGroups(): Collects node IDs affected by the animation groups.
@@ -39,7 +44,7 @@ import OpeningAnimationMenu from "./babylonjs-animation-opening-menu.js";
39
44
  * - #getProgress(): Calculates progress (0-1) from current frame.
40
45
  * - #getPrefViewer3DComponent(): Resolves and caches the nearest `pref-viewer-3d` host element.
41
46
  * - #checkProgress(progress): Applies threshold logic to progress.
42
- * - #notifyStateChange(): Emits `prefviewer-animation-update` with state/progress/loop metadata.
47
+ * - #notifyStateChange(): Emits `pref-viewer-3d-animation-changed` with state/progress/loop metadata.
43
48
  * - #updateControlsSlider(): Updates the slider in the control menu.
44
49
  * - #updateControls(): Emits state updates and syncs controls when the menu is visible.
45
50
  */
@@ -315,7 +320,7 @@ export default class OpeningAnimation {
315
320
  }
316
321
 
317
322
  /**
318
- * Dispatches a `prefviewer-animation-update` CustomEvent from the nearest `pref-viewer-3d` host.
323
+ * Dispatches a `pref-viewer-3d-animation-changed` CustomEvent from the nearest `pref-viewer-3d` host.
319
324
  * The event bubbles and crosses shadow DOM boundaries, exposing the current animation snapshot
320
325
  * (`name`, `state`, `progress`, and `loop`) in `event.detail`.
321
326
  * @private
@@ -329,6 +334,7 @@ export default class OpeningAnimation {
329
334
 
330
335
  const customEventOptions = {
331
336
  bubbles: true,
337
+ cancelable: false,
332
338
  composed: true,
333
339
  detail: {
334
340
  name: this.name,
@@ -337,7 +343,7 @@ export default class OpeningAnimation {
337
343
  loop: this.#loop,
338
344
  },
339
345
  };
340
- this.#prefViewer3D.dispatchEvent(new CustomEvent("prefviewer-animation-changed", customEventOptions));
346
+ this.#prefViewer3D.dispatchEvent(new CustomEvent("pref-viewer-3d-animation-changed", customEventOptions));
341
347
  return true;
342
348
  }
343
349