@preference-sl/pref-viewer 2.16.0-beta.9 → 2.16.1

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 CHANGED
@@ -126,13 +126,22 @@ viewer.loadConfig({
126
126
  shadows: true,
127
127
  },
128
128
  render: {
129
- antiAliasingEnabled: true,
130
129
  ambientOcclusionEnabled: true,
130
+ antiAliasingEnabled: true,
131
131
  iblEnabled: true,
132
132
  shadowsEnabled: false,
133
+ showAnimationMenu: true,
134
+ showLightingTimeOfDay: true,
135
+ lightingTimeOfDay: 0.5,
136
+ highlightEnabled: true,
137
+ highlightColor: "#ff6700",
133
138
  },
134
139
  },
140
+ styles: {
141
+ colorPrimary: "#ff6700",
142
+ },
135
143
  culture: "en-EN",
144
+ forceReload: false,
136
145
  });
137
146
  ```
138
147
 
@@ -175,23 +184,22 @@ Storage descriptors are passed through `model.storage`, `scene.storage`, `materi
175
184
 
176
185
  ## Attributes
177
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
+
178
189
  | Attribute | Description |
179
190
  | --- | --- |
180
- | `config` | JSON string with the full viewer configuration. |
181
- | `model` | JSON string with a model payload. |
182
- | `scene` | JSON string with a scene/environment payload. |
183
- | `materials` | JSON string with a materials payload. |
184
- | `drawing` | JSON string with a 2D drawing payload. |
185
- | `options` | JSON string with viewer options. |
186
- | `culture` | UI locale. Supported values: `en-EN`, `es-ES`. |
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`. |
187
198
  | `mode` | Viewer mode: `3d` or `2d`. Defaults to `3d`. |
188
- | `show-model` | Shows or hides the current model. Use `true` or `false`. |
189
- | `show-scene` | Shows or hides the current scene/environment. Use `true` or `false`. |
190
- | `show-menu` | Shows or hides the 3D render settings menu. Defaults to visible. |
191
- | `accent-color` | Forwarded to the 3D component and menu for theme/accent styling when supported by the internal UI. |
192
- | `show-animation-menu` | Enables or disables the animation menu when animations are available. |
193
- | `highlight-enabled` | Enables or disables hover highlight. |
194
- | `highlight-color` | CSS color used for hover highlight. Defaults to `#ff6700`. |
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`. |
195
203
 
196
204
  ## Public methods
197
205
 
@@ -199,22 +207,17 @@ Storage descriptors are passed through `model.storage`, `scene.storage`, `materi
199
207
 
200
208
  | Method | Description |
201
209
  | --- | --- |
202
- | `loadConfig(config)` | Queues a full configuration update. Accepts an object or JSON string. |
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. |
203
211
  | `loadModel(model)` | Queues a model update. |
204
212
  | `loadScene(scene)` | Queues a scene/environment update. |
205
213
  | `loadMaterials(materials)` | Queues a materials update. |
206
214
  | `loadDrawing(drawing)` | Queues a 2D drawing update. |
207
- | `setOptions(options)` | Queues camera, material, IBL, lighting, or render option updates. |
208
- | `setCulture(culture)` | Changes the active UI locale. |
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`. |
209
219
  | `setMode(mode)` | Switches between `2d` and `3d`. |
210
-
211
- ### Parallel loading helpers
212
-
213
- | Method | Description |
214
- | --- | --- |
215
- | `loadModelParallel(model)` | Loads a model without waiting for the standard task queue. |
216
- | `loadSceneParallel(scene)` | Loads a scene/environment without waiting for the standard task queue. |
217
- | `loadMaterialsParallel(materials)` | Loads materials without waiting for the standard task queue. |
220
+ | `getDebugInfo()` | Returns a 3D runtime diagnostic snapshot when the internal 3D component and controller are available. |
218
221
 
219
222
  ### Visibility and navigation
220
223
 
@@ -227,14 +230,34 @@ Storage descriptors are passed through `model.storage`, `scene.storage`, `materi
227
230
  | `zoomExtentsAll()` | Fits all 2D drawing content in view. |
228
231
  | `zoomIn()` / `zoomOut()` | Controls 2D drawing zoom. |
229
232
  | `focusModel()` | Moves focus to the current model interaction target when available. |
230
- | `getDebugState()` | Returns a 3D runtime debug snapshot when the internal 3D component exposes one. |
233
+
234
+ ### Semantic selection and turnable state
235
+
236
+ | Method | Description |
237
+ | --- | --- |
238
+ | `setSelectableElements(elements)` | Defines and renders selectable SVG ids in yellow (`#FFFF00`, opacity `0.5`). Accepts strings or objects with `id`/`Id`. |
239
+ | `setSelectedElements(elements)` | Defines and renders selected highlights in red (`#FF0000`, opacity `0.5`). Accepts strings or objects with `id`/`Id` and optional `highlights`/`Highlights`. |
240
+ | `applySelectionState(state)` | Applies selectable and selected state to the semantic snapshot and 2D drawing in one call. Accepts `selectableIds`/`selectables` and `selectedItems`/`selectedIds`/`selected`; state supplied before a drawing is reapplied after load. |
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` with exactly `{ ids: string[] }` from a string, descriptor, collection, or `{ ids }` input. This replaces the provisional `detail.element` payload. |
246
+ | `appendSvgNode(id, svgId, svg)` | Adds a host-owned SVG node to the interactive 2D drawing. The node's identified geometry participates in hit-testing and selection. Returns `false` for a duplicate `svgId` or absent node. |
247
+ | `removeAppendedSvgNodes()` | Removes every SVG node previously added through `appendSvgNode` and reconciles the current visual selection layers. |
248
+ | `startTurnable(options)` | Starts semantic turnable state and emits `pref-viewer-3d-turnable-changed`. |
249
+ | `stopTurnable()` | Stops semantic turnable state. |
250
+ | `toggleTurnable(options)` | Toggles semantic turnable state. |
251
+ | `getTurnableState()` | Returns `{ running, speed, direction }`. |
252
+
253
+ Selection colors are rendered through disposable SVG clones; the loaded base SVG and shared definitions are not modified. Selectable clones are inserted before selected clones so red selection remains visible above yellow availability. Reapplying state is idempotent, and replacing the drawing removes dynamic nodes and prior visual layers before the current semantic snapshot is rendered again.
231
254
 
232
255
  ### Animation controls
233
256
 
234
257
  | Method | Description |
235
258
  | --- | --- |
236
- | `getAnimations()` | Returns available model animations. |
237
- | `playAnimation(name, action)` | Plays, pauses, stops, or otherwise controls a named animation. |
259
+ | `getAnimations()` | Returns available model animations with state, progress, loop, and affected node ids. |
260
+ | `playAnimation(name, action)` | Controls a named animation. Supported actions are delegated to `BabylonJSAnimationController`. |
238
261
  | `setAnimationProgress(name, progress)` | Sets animation progress from `0` to `1`. |
239
262
  | `setAnimationLoop(name, loop)` | Enables or disables looping for a named animation. |
240
263
 
@@ -262,10 +285,9 @@ These setters are convenience bridges for framework bindings and property-based
262
285
  | `materials` | Forwards to `loadMaterials(value)`. |
263
286
  | `drawing` | Forwards to `loadDrawing(value)`. |
264
287
  | `options` | Forwards to `setOptions(value)`. |
288
+ | `styles` | Forwards to `setStyles(value)`. |
265
289
  | `culture` | Forwards to `setCulture(value)`. |
266
290
  | `mode` | Forwards to `setMode(value)`. |
267
- | `highlightEnabled` | Reflects to the `highlight-enabled` attribute. |
268
- | `highlightColor` | Reflects to the `highlight-color` attribute. |
269
291
 
270
292
  ### Getters
271
293
 
@@ -277,92 +299,65 @@ These setters are convenience bridges for framework bindings and property-based
277
299
  | `isLoading` | Whether a load operation is currently in progress. |
278
300
  | `isMode2D` | `true` when the current mode is `2d`. |
279
301
  | `isMode3D` | `true` when the current mode is `3d`. |
302
+
280
303
  ## Events
281
304
 
282
- The component emits custom events so host applications can integrate loading indicators, error states, and viewer controls.
305
+ 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"`).
283
306
 
284
- | Event | Description |
285
- | --- | --- |
286
- | `scene-loading` | A 3D scene/model/material operation has started. |
287
- | `scene-loaded` | A 3D scene/model/material operation completed. Includes operation details when available. |
288
- | `scene-error` | A scene operation failed. |
289
- | `scene-setting-options` | Viewer options are being applied. |
290
- | `scene-set-options` | Viewer options were applied. |
291
- | `model-loading` | A parallel model load started. |
292
- | `model-loaded` | A model container loaded successfully. In the parallel path, this means the independent model load completed. |
293
- | `model-error` | A parallel model load failed. |
294
- | `environment-loaded` | The environment/scene container loaded successfully. |
295
- | `materials-loading` | A parallel materials load started. |
296
- | `materials-loaded` | A parallel materials load completed. |
297
- | `materials-error` | A parallel materials load failed. |
298
- | `drawing-loading` | A 2D drawing load started. |
299
- | `drawing-loaded` | A 2D drawing load completed. |
300
- | `drawing-zoom-changed` | The 2D drawing zoom changed. |
301
- | `model-first-painted` | The first frame for a newly loaded model was painted. |
302
- | `prefviewer-animation-changed` | A model animation state changed. |
303
- | `pref-viewer-menu-3d-apply` | The 3D settings menu submitted render-setting changes. |
304
- | `scene-load-assets-complete` | Performance/progress event emitted after asset-container loading completes. |
305
- | `scene-load-merge-complete` | Performance/progress event emitted after loaded containers are merged into the scene. |
306
- | `scene-load-shaders-complete` | Performance/progress event emitted after render/shader work completes. |
307
- | `scene-load-container-complete` | Performance/progress event emitted after an independent container load completes. |
307
+ ### General Events
308
308
 
309
- Example:
309
+ | Event | Emitted by | Legacy alias | Description |
310
+ | --- | --- | --- | --- |
311
+ | `pref-viewer-initialized` | `<pref-viewer>` | None | The root component has been mounted and initialized. |
312
+ | `pref-viewer-loading` | `<pref-viewer>` | None | A 2D or 3D load operation has started. Includes `detail.mode` with the current root mode. |
313
+ | `pref-viewer-loaded` | `<pref-viewer>` | None | A 2D or 3D load operation completed. Includes `detail.mode` with the current root mode. |
314
+ | `pref-viewer-error` | `<pref-viewer>` | None | A 2D or 3D operation failed. Includes `detail.mode` with the current root mode. |
315
+ | `pref-viewer-selection-state-changed` | `<pref-viewer>` | None | The semantic selection state changed. |
316
+ | `pref-viewer-element-click` | `<pref-viewer>` | None | A semantic SVG element was clicked or forwarded by the host. Geometry without its own id resolves the nearest id-bearing ancestor inside the drawing. `detail` is exactly `{ ids: string[] }`; clicks are emitted independently of the current selectable set. |
310
317
 
311
- ```js
312
- const viewer = document.querySelector("pref-viewer");
313
-
314
- viewer.addEventListener("scene-loaded", (event) => {
315
- console.log("Viewer scene loaded", event.detail);
316
- });
318
+ ### 3D Events
317
319
 
318
- viewer.addEventListener("scene-error", (event) => {
319
- console.error("Viewer scene failed", event.detail);
320
- });
321
- ```
320
+ | Event | Emitted by | Legacy alias | Description |
321
+ | --- | --- | --- | --- |
322
+ | `pref-viewer-3d-loading` | `<pref-viewer>`, `<pref-viewer-3d>` | `scene-loading` | A 3D scene/model/material/options operation has started. |
323
+ | `pref-viewer-3d-loaded` | `<pref-viewer>`, `<pref-viewer-3d>` | `scene-loaded` | A 3D scene/model/material/options operation completed. Includes operation details when available. |
324
+ | `pref-viewer-3d-error` | `<pref-viewer>` | `scene-error` | A 3D operation failed. |
325
+ | `pref-viewer-3d-options-applying` | `<pref-viewer-3d>` | `scene-setting-options` | 3D viewer options are being applied. |
326
+ | `pref-viewer-3d-options-applied` | `<pref-viewer-3d>` | `scene-set-options` | 3D viewer options were applied. |
327
+ | `pref-viewer-3d-render-settings-change-requested` | `<pref-viewer-menu-3d>` | None | The 3D settings menu requested render-setting changes. |
328
+ | `pref-viewer-3d-animation-changed` | Opening animation controller | None | A model animation state changed. |
329
+ | `pref-viewer-3d-turnable-changed` | `<pref-viewer>` | None | The semantic turnable state changed. |
322
330
 
323
- ## Progressive model loading / eager model path
331
+ ### 2D Events
324
332
 
325
- `loadModelParallel(model)` is the eager/progressive model-loading API. It bypasses the root task queue and asks the 3D controller to load the model container independently while the existing render loop keeps running.
333
+ | Event | Emitted by | Legacy alias | Description |
334
+ | --- | --- | --- | --- |
335
+ | `pref-viewer-2d-loading` | `<pref-viewer>`, `<pref-viewer-2d>` | `drawing-loading` | A 2D drawing load started. |
336
+ | `pref-viewer-2d-loaded` | `<pref-viewer>`, `<pref-viewer-2d>` | `drawing-loaded` | A 2D drawing load completed. |
337
+ | `pref-viewer-2d-error` | `<pref-viewer>`, `<pref-viewer-2d>` | `drawing-error` | A 2D drawing operation failed. |
338
+ | `pref-viewer-2d-viewport-changed` | `<pref-viewer>`, `<pref-viewer-2d>` | None | The 2D drawing pan/zoom viewport changed. `detail` contains numeric `x`, `y`, `scale` and boolean `moved`, `scaled`, `maximized`, `minimized`; it does not contain `centered` or any private `desde2d`, `mode`, or `source` marker. |
326
339
 
327
- How it behaves:
340
+ ### Internal Listeners
328
341
 
329
- 1. The model payload is parsed from an object or JSON string.
330
- 2. `model-loading` is dispatched immediately from `<pref-viewer>`.
331
- 3. The 3D component calls `loadModelIndependent(model)`.
332
- 4. The Babylon controller uses `loadContainerIndependent("model", ...)`.
333
- 5. If the model is not already claimed by a full scene load, it follows the optimistic `par` path: download/prepare the glTF container immediately, then merge it atomically.
334
- 6. If a full scene load already claimed the model container, it follows the `claimed` path to avoid a double-load conflict while still letting the independent path own the replacement.
335
- 7. The previous model is replaced without rebuilding camera-dependent effects during the merge (`releaseEffects: false`), reducing gray-frame/flicker risk.
336
- 8. After merge, the controller requests a few render frames and waits for paint before dispatching `model-first-painted`.
337
- 9. The returned detail includes `success`, `error`, `loadedContainers`, and `loadSessionId` when provided by the payload.
342
+ `<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.
338
343
 
339
344
  Example:
340
345
 
341
346
  ```js
342
- const loadSessionId = crypto.randomUUID();
347
+ const viewer = document.querySelector("pref-viewer");
343
348
 
344
- viewer.addEventListener("model-first-painted", (event) => {
345
- console.log("Model first painted", event.detail);
349
+ viewer.addEventListener("pref-viewer-3d-loaded", (event) => {
350
+ console.log("Viewer 3D loaded", event.detail);
346
351
  });
347
352
 
348
- await viewer.loadModelParallel({
349
- loadSessionId,
350
- storage: {
351
- url: "https://example.com/assets/model.glb",
352
- },
353
- visible: true,
353
+ viewer.addEventListener("pref-viewer-3d-error", (event) => {
354
+ console.error("Viewer 3D failed", event.detail);
354
355
  });
355
356
  ```
356
357
 
357
- Important constraints:
358
-
359
- - The eager model path requires the internal Babylon scene to already exist. If there is no scene, the controller returns `success: false` with `No scene available`.
360
- - Only one independent model load can run at a time. A concurrent call returns `success: false` with `Already loading model independently`.
361
- - `model-loaded` means the model container load finished; `model-first-painted` is the stronger signal for UI handoff because it waits for the browser to paint after the atomic merge.
362
- - Use this path when the product model should appear as soon as possible while slower scene/environment/material work continues. Use `loadConfig()` when deterministic sequential loading is more important than progressive display.
363
358
  ## Render settings
364
359
 
365
- Render settings can be passed through `setOptions`, initial config, or the built-in 3D menu.
360
+ Render settings can be passed through `setOptions`, `loadConfig({ options: { render } })`, property setters, or the built-in 3D menu.
366
361
 
367
362
  ```js
368
363
  viewer.setOptions({
@@ -371,14 +366,44 @@ viewer.setOptions({
371
366
  ambientOcclusionEnabled: true,
372
367
  iblEnabled: true,
373
368
  shadowsEnabled: false,
374
- lightingTimeOfDay: 0.5,
369
+ showAnimationMenu: true,
375
370
  highlightEnabled: true,
376
371
  highlightColor: "#ff6700",
372
+ showLightingTimeOfDay: true,
373
+ lightingTimeOfDay: 0.5,
377
374
  },
378
375
  });
379
376
  ```
380
377
 
381
- Render settings are persisted in `localStorage` under the `pref-viewer/render-settings` key when changed through the runtime settings flow.
378
+ | Setting | Type | Behavior |
379
+ | --- | --- | --- |
380
+ | `antiAliasingEnabled` | `boolean` | Enables/disables antialiasing. Changes are persisted and can trigger a render-settings reload. |
381
+ | `ambientOcclusionEnabled` | `boolean` | Enables/disables SSAO. Changes are persisted and can trigger a render-settings reload. |
382
+ | `iblEnabled` | `boolean` | Enables/disables image-based lighting. Changes are persisted and can trigger a render-settings reload. |
383
+ | `shadowsEnabled` | `boolean` | Enables/disables shadows. Changes are persisted and can trigger a render-settings reload. |
384
+ | `showAnimationMenu` | `boolean`/`"false"` | Enables the animation control menu when model animations are available. Applies immediately, persists, and refreshes menu availability. |
385
+ | `highlightEnabled` | `boolean`/`"false"` | Enables/disables hover highlight for animation openings. Applies immediately and persists. |
386
+ | `highlightColor` | `string` | Hex color used by hover highlight. Applies immediately and persists. |
387
+ | `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`. |
388
+ | `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. |
389
+
390
+ 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`.
391
+
392
+ ## Runtime styles
393
+
394
+ Runtime styles can be passed through the `styles` attribute, the `styles` property setter, `setStyles(styles)`, or `loadConfig({ styles })`.
395
+
396
+ ```html
397
+ <pref-viewer styles='{"colorPrimary":"#0055cc"}'></pref-viewer>
398
+ ```
399
+
400
+ ```js
401
+ viewer.setStyles({
402
+ colorPrimary: "#0055cc",
403
+ });
404
+ ```
405
+
406
+ 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.
382
407
 
383
408
  ## Localization
384
409
 
@@ -421,10 +446,10 @@ The playground is available from `playground/index.html` and serves the project
421
446
 
422
447
  | Script | Description |
423
448
  | --- | --- |
424
- | `npm run build` | Bundles `src/index.js` into `dist/bundle.js` with esbuild. |
425
- | `npm run build:prefweb` | Creates a production webpack build. |
426
- | `npm run build:prefweb:dev` | Creates a development webpack build. |
427
- | `npm start` | Builds the bundle and starts a local HTTP server on port `8080`. |
449
+ | `npm run build` | Bundles `src/index.js` into `dist/bundle.js` with esbuild. This is the standard ESM playground/runtime build. |
450
+ | `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`. |
451
+ | `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. |
452
+ | `npm start` | Builds the standard bundle and starts a local HTTP server on port `8080`. |
428
453
  | `npm test` | Runs the Vitest test suite. |
429
454
  | `npm run release` | Creates a standard-version release. |
430
455
  | `npm run release:beta` | Creates a beta prerelease with standard-version. |
@@ -454,7 +479,9 @@ export function ProductViewer() {
454
479
  - Use object-based JavaScript APIs for complex payloads. Attributes must be valid JSON strings.
455
480
  - Remote assets must be reachable by the browser and must satisfy the expected CORS policy.
456
481
  - glTF files with external resources are resolved and cached by the viewer when possible.
457
- - Avoid repeatedly replacing large assets if only visibility, camera, lighting, or material options changed.
482
+ - Avoid repeatedly replacing large assets if only visibility, camera, lighting, render, or material options changed.
483
+ - 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()`.
484
+ - For PrefWeb integration, consume the webpack UMD build (`bundle-umd.js`) and prefer development UMD builds while debugging source maps.
458
485
 
459
486
  ## License
460
487