@combeenation/3d-viewer 21.0.1-beta1 → 21.1.0-beta1

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.
Files changed (53) hide show
  1. package/dist/lib-cjs/buildinfo.json +1 -1
  2. package/dist/lib-cjs/commonjs.tsconfig.tsbuildinfo +1 -1
  3. package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js +2 -4
  4. package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js.map +1 -1
  5. package/dist/lib-cjs/internal/cbn-viewer-bridge.d.ts +1 -1
  6. package/dist/lib-cjs/internal/cbn-viewer-bridge.js +2 -5
  7. package/dist/lib-cjs/internal/cbn-viewer-bridge.js.map +1 -1
  8. package/dist/lib-cjs/internal/parameter/paintable-parameter-helper.d.ts +2 -2
  9. package/dist/lib-cjs/internal/parameter/paintable-parameter-helper.js +3 -2
  10. package/dist/lib-cjs/internal/parameter/paintable-parameter-helper.js.map +1 -1
  11. package/dist/lib-cjs/internal/parameter/parameter-helper.d.ts +2 -2
  12. package/dist/lib-cjs/internal/parameter/parameter-helper.js +9 -28
  13. package/dist/lib-cjs/internal/parameter/parameter-helper.js.map +1 -1
  14. package/dist/lib-cjs/internal/parameter/texture-parameter-helper.d.ts +2 -2
  15. package/dist/lib-cjs/internal/parameter/texture-parameter-helper.js +5 -5
  16. package/dist/lib-cjs/internal/parameter/texture-parameter-helper.js.map +1 -1
  17. package/dist/lib-cjs/internal/svg-helper.d.ts +5 -0
  18. package/dist/lib-cjs/internal/svg-helper.js +13 -2
  19. package/dist/lib-cjs/internal/svg-helper.js.map +1 -1
  20. package/dist/lib-cjs/manager/camera-manager.js +6 -6
  21. package/dist/lib-cjs/manager/camera-manager.js.map +1 -1
  22. package/dist/lib-cjs/manager/debug-manager.js +2 -3
  23. package/dist/lib-cjs/manager/debug-manager.js.map +1 -1
  24. package/dist/lib-cjs/manager/material-manager.js +2 -3
  25. package/dist/lib-cjs/manager/material-manager.js.map +1 -1
  26. package/dist/lib-cjs/manager/parameter-manager.d.ts +6 -4
  27. package/dist/lib-cjs/manager/parameter-manager.js +10 -9
  28. package/dist/lib-cjs/manager/parameter-manager.js.map +1 -1
  29. package/dist/lib-cjs/manager/scene-manager.js +8 -5
  30. package/dist/lib-cjs/manager/scene-manager.js.map +1 -1
  31. package/dist/lib-cjs/utils/viewer-utils.d.ts +24 -1
  32. package/dist/lib-cjs/utils/viewer-utils.js +63 -0
  33. package/dist/lib-cjs/utils/viewer-utils.js.map +1 -1
  34. package/dist/lib-cjs/viewer.js +1 -0
  35. package/dist/lib-cjs/viewer.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/internal/cbn-custom-babylon-loader-plugin.ts +3 -5
  38. package/src/internal/cbn-viewer-bridge.ts +1 -3
  39. package/src/internal/parameter/paintable-parameter-helper.ts +4 -3
  40. package/src/internal/parameter/parameter-helper.ts +15 -49
  41. package/src/internal/parameter/texture-parameter-helper.ts +7 -12
  42. package/src/internal/svg-helper.ts +13 -1
  43. package/src/manager/camera-manager.ts +3 -3
  44. package/src/manager/debug-manager.ts +3 -4
  45. package/src/manager/material-manager.ts +3 -4
  46. package/src/manager/parameter-manager.ts +12 -12
  47. package/src/manager/scene-manager.ts +9 -5
  48. package/src/utils/viewer-utils.ts +75 -0
  49. package/src/viewer.ts +2 -0
  50. package/dist/lib-cjs/internal/animation-helper.d.ts +0 -2
  51. package/dist/lib-cjs/internal/animation-helper.js +0 -16
  52. package/dist/lib-cjs/internal/animation-helper.js.map +0 -1
  53. package/src/internal/animation-helper.ts +0 -18
@@ -1,23 +1,17 @@
1
1
  import {
2
2
  AbstractMesh,
3
- Animation,
4
- AnimationGroup,
5
3
  BuiltInParameter,
6
- Color3,
7
- MaterialManager,
8
4
  PBRMaterial,
9
5
  ParameterManager,
10
6
  StandardMaterial,
11
- Vector3,
7
+ Viewer,
12
8
  ViewerError,
13
9
  ViewerErrorIds,
14
10
  } from '../..';
15
- import { playAnimationGroupOnce } from '../animation-helper';
16
11
  import { getInternalMetadataValue, setInternalMetadataValue } from '../metadata-helper';
17
12
 
18
- type AnimatableProperties = 'albedoColor' | 'position' | 'rotation' | 'scaling' | 'influence';
19
-
20
- export function createBuiltInParameter(parameterManager: ParameterManager, materialManager: MaterialManager): void {
13
+ export function createBuiltInParameter(viewer: Viewer): void {
14
+ const parameterManager = viewer.parameterManager;
21
15
  parameterManager.setParameterObserver(BuiltInParameter.Visible, async ({ nodes, newValue }) => {
22
16
  const visible = ParameterManager.parseBoolean(newValue);
23
17
 
@@ -40,7 +34,7 @@ export function createBuiltInParameter(parameterManager: ParameterManager, mater
40
34
  // => skip the material application in this case, as if it would be done twice
41
35
  const anMaterialToBeSet = getInternalMetadataValue(an, 'materialToBeSet');
42
36
  if (anVisibleNested && anRequestedMaterial && !anMaterialToBeSet) {
43
- await materialManager.setMaterialOnMesh(
37
+ await viewer.materialManager.setMaterialOnMesh(
44
38
  anRequestedMaterial,
45
39
  // this cast is fine, as deferred material can only be set on meshes
46
40
  an as AbstractMesh
@@ -73,7 +67,7 @@ export function createBuiltInParameter(parameterManager: ParameterManager, mater
73
67
  // => skip the material application in this case, as if it would be done twice
74
68
  const anMaterialToBeSet = getInternalMetadataValue(node, 'materialToBeSet');
75
69
  if (!anMaterialToBeSet) {
76
- await materialManager.setMaterialOnMesh(material, node);
70
+ await viewer.materialManager.setMaterialOnMesh(material, node);
77
71
  }
78
72
  } else {
79
73
  setInternalMetadataValue(node, 'deferredMaterial', material);
@@ -86,11 +80,11 @@ export function createBuiltInParameter(parameterManager: ParameterManager, mater
86
80
 
87
81
  for (const node of nodes) {
88
82
  if (options?.animationTimeMs) {
89
- _animateParameter(
83
+ await viewer.utils.animateProperty(
90
84
  node,
91
85
  'position',
92
86
  position,
93
- `${BuiltInParameter.Position}.${node.name}`,
87
+ `${ParameterManager.PARAMETER_ANIMATION_NAME}.${BuiltInParameter.Position}.${node.name}`,
94
88
  options.animationTimeMs
95
89
  );
96
90
  } else {
@@ -108,11 +102,11 @@ export function createBuiltInParameter(parameterManager: ParameterManager, mater
108
102
  // otherwise the animation would just jump to the end value, as there is no start value to interpolate
109
103
  node.rotation = node.rotationQuaternion.toEulerAngles();
110
104
  }
111
- _animateParameter(
105
+ await viewer.utils.animateProperty(
112
106
  node,
113
107
  'rotation',
114
108
  rotation,
115
- `${BuiltInParameter.Rotation}.${node.name}`,
109
+ `${ParameterManager.PARAMETER_ANIMATION_NAME}.${BuiltInParameter.Rotation}.${node.name}`,
116
110
  options.animationTimeMs
117
111
  );
118
112
  } else {
@@ -125,11 +119,11 @@ export function createBuiltInParameter(parameterManager: ParameterManager, mater
125
119
 
126
120
  for (const node of nodes) {
127
121
  if (options?.animationTimeMs) {
128
- _animateParameter(
122
+ await viewer.utils.animateProperty(
129
123
  node,
130
124
  'scaling',
131
125
  scaling,
132
- `${BuiltInParameter.Scaling}.${node.name}`,
126
+ `${ParameterManager.PARAMETER_ANIMATION_NAME}.${BuiltInParameter.Scaling}.${node.name}`,
133
127
  options.animationTimeMs
134
128
  );
135
129
  } else {
@@ -145,11 +139,11 @@ export function createBuiltInParameter(parameterManager: ParameterManager, mater
145
139
  switch (materialCls) {
146
140
  case 'PBRMaterial':
147
141
  if (options?.animationTimeMs) {
148
- _animateParameter(
142
+ await viewer.utils.animateProperty(
149
143
  material as PBRMaterial,
150
144
  'albedoColor',
151
145
  color.toLinearSpace(),
152
- `${BuiltInParameter.Color}.${material.id}`,
146
+ `${ParameterManager.PARAMETER_ANIMATION_NAME}.${BuiltInParameter.Color}.${material.id}`,
153
147
  options.animationTimeMs
154
148
  );
155
149
  } else {
@@ -213,11 +207,11 @@ export function createBuiltInParameter(parameterManager: ParameterManager, mater
213
207
 
214
208
  if (target) {
215
209
  if (options?.animationTimeMs) {
216
- _animateParameter(
210
+ await viewer.utils.animateProperty(
217
211
  target,
218
212
  'influence',
219
213
  morphTargetValue.value,
220
- `${BuiltInParameter.Influence}.${node.name}.${target.name}`,
214
+ `${ParameterManager.PARAMETER_ANIMATION_NAME}.${BuiltInParameter.Influence}.${node.name}.${target.name}`,
221
215
  options.animationTimeMs
222
216
  );
223
217
  } else {
@@ -233,31 +227,3 @@ export function createBuiltInParameter(parameterManager: ParameterManager, mater
233
227
  }
234
228
  });
235
229
  }
236
-
237
- async function _animateParameter<T, K extends Extract<keyof T, AnimatableProperties>>(
238
- target: T,
239
- property: K,
240
- value: T[K],
241
- animationNameSuffix: string,
242
- animationTimeMs: number
243
- ): Promise<void> {
244
- const framesPerSec = 100;
245
- // extend if further `AnimatableProperties` with different types are added
246
- const dataType =
247
- value instanceof Vector3
248
- ? Animation.ANIMATIONTYPE_VECTOR3
249
- : value instanceof Color3
250
- ? Animation.ANIMATIONTYPE_COLOR3
251
- : Animation.ANIMATIONTYPE_FLOAT;
252
-
253
- const animationGroup = new AnimationGroup(`${ParameterManager.PARAMETER_ANIMATION_NAME}.${animationNameSuffix}`);
254
-
255
- const animation = new Animation(property, property, framesPerSec, dataType);
256
- animation.setKeys([
257
- { frame: 0, value: target[property] },
258
- { frame: framesPerSec, value: value },
259
- ]);
260
- animationGroup.addTargetedAnimation(animation, target);
261
-
262
- await playAnimationGroupOnce(animationGroup, framesPerSec, Math.max(animationTimeMs, 0));
263
- }
@@ -2,16 +2,15 @@ import {
2
2
  BaseTexture,
3
3
  BuiltInParameter,
4
4
  Material,
5
- MaterialManager,
6
5
  PBRMaterial,
7
6
  ParameterManager,
8
- Scene,
9
7
  Texture,
10
8
  TextureManager,
9
+ Viewer,
11
10
  ViewerError,
12
11
  ViewerErrorIds,
13
12
  } from '../..';
14
- import { embedAssets } from '../svg-helper';
13
+ import { createSvgDataUri, embedAssets } from '../svg-helper';
15
14
  import isSvg from 'is-svg';
16
15
 
17
16
  /**
@@ -51,11 +50,8 @@ export const ParameterTextureChannels = {
51
50
  };
52
51
  export type ParameterTextureChannelsKeys = keyof typeof ParameterTextureChannels;
53
52
 
54
- export function createBuiltInTextureParameter(
55
- parameterManager: ParameterManager,
56
- materialManager: MaterialManager,
57
- scene: Scene
58
- ): void {
53
+ export function createBuiltInTextureParameter(viewer: Viewer): void {
54
+ const parameterManager = viewer.parameterManager;
59
55
  // create parameter observer for each channel
60
56
  (Object.values(ParameterTextureChannels) as ParameterTextureChannelsKeys[]).forEach(channel => {
61
57
  parameterManager.setParameterObserver(
@@ -72,8 +68,7 @@ export function createBuiltInTextureParameter(
72
68
  // However the rescaling functionality of "Dynamic Textures" is not required and therefore it can be
73
69
  // implemented as a plain "Texture"
74
70
  const svgWithAssetsEmbedded = await embedAssets(image);
75
- // convert into a base64 string, as this can be directly interpreted as "url", at least for Babylon.js
76
- url = 'data:image/svg+xml;base64,' + btoa(svgWithAssetsEmbedded);
71
+ url = createSvgDataUri(svgWithAssetsEmbedded);
77
72
  } else if (image.includes('<svg') && image.includes('</svg>')) {
78
73
  // seems like the user tried to use a SVG string, as <svg> tags are used
79
74
  // inform the user that this is not a valid SVG string
@@ -105,13 +100,13 @@ export function createBuiltInTextureParameter(
105
100
  } else if (url) {
106
101
  // no texture, or wrong type => create texture from scratch
107
102
  // first we check if some settings were provided in the material definition
108
- const addMatSettings = await materialManager.getMaterialDefinition(pbrMaterial.id);
103
+ const addMatSettings = await viewer.materialManager.getMaterialDefinition(pbrMaterial.id);
109
104
  const textureSettings = addMatSettings ? _getTextureObjFromParameterChannel(addMatSettings, channel) : {};
110
105
 
111
106
  // overwrite the name with the url, as this is what the texture parser expects
112
107
  (textureSettings as any).name = url;
113
108
  // use parser instead of constructor to keep the original texture settings
114
- const newTexture = Texture.Parse(textureSettings, scene, '') as Texture;
109
+ const newTexture = Texture.Parse(textureSettings, viewer.scene, '') as Texture;
115
110
 
116
111
  if (!newTexture) {
117
112
  throw new ViewerError({
@@ -2,7 +2,7 @@
2
2
  * Replaces all supported image & font URLs in the given SVG with their base64 representation.
3
3
  */
4
4
  export async function embedAssets(svgSrc: string): Promise<string> {
5
- const _imageExtensions = ['png', 'gif', 'jpg', 'jpeg', 'svg', 'bmp'];
5
+ const _imageExtensions = ['png', 'gif', 'jpg', 'jpeg', 'svg', 'bmp', 'webp'];
6
6
  const _fontExtensions = ['woff2', 'woff', 'ttf', 'otf'];
7
7
  const _assetExtensions = [..._imageExtensions, ..._fontExtensions];
8
8
  // Regex copied from https://stackoverflow.com/a/8943487/1273551, not "stress tested"...
@@ -22,6 +22,18 @@ export async function embedAssets(svgSrc: string): Promise<string> {
22
22
  return assetFetcherResults.reduce((svgSrc, x) => svgSrc.replace(x.url, x.base64), svgSrc);
23
23
  }
24
24
 
25
+ /**
26
+ * Converts an SVG string into a base64-encoded data URI that can be used as a texture URL.
27
+ * Uses `TextEncoder` to correctly handle non-ASCII characters (e.g. umlauts) before base64-encoding.
28
+ */
29
+ export function createSvgDataUri(svgSrc: string): string {
30
+ const utf8Bytes = new TextEncoder().encode(svgSrc);
31
+ const binary = Array.from(utf8Bytes, b => String.fromCharCode(b)).join('');
32
+ const dataUri = 'data:image/svg+xml;base64,' + btoa(binary);
33
+
34
+ return dataUri;
35
+ }
36
+
25
37
  /**
26
38
  * Fetch asset (image or font) and convert it to base64 string representation.
27
39
  */
@@ -11,7 +11,6 @@ import {
11
11
  ViewerErrorIds,
12
12
  ViewerEvent,
13
13
  } from '../index';
14
- import { playAnimationGroupOnce } from '../internal/animation-helper';
15
14
  import { downloadFile } from '../internal/export-helper';
16
15
  import { nodeMatchesAnyCriteria } from '../internal/node-helper';
17
16
  import { createScreenshotCanvas, trimCanvas } from '../internal/screenshot-helper';
@@ -271,10 +270,11 @@ export class CameraManager {
271
270
 
272
271
  if (durationMs === 0) {
273
272
  // instant movement without animation
273
+ activeCamera.target = position.target ?? activeCamera.target;
274
274
  activeCamera.alpha = position.alpha ?? activeCamera.alpha;
275
275
  activeCamera.beta = position.beta ?? activeCamera.beta;
276
276
  activeCamera.radius = position.radius ?? activeCamera.radius;
277
- activeCamera.target = position.target ?? activeCamera.target;
277
+ return;
278
278
  }
279
279
 
280
280
  const framesPerSec = 100;
@@ -334,7 +334,7 @@ export class CameraManager {
334
334
  );
335
335
  }
336
336
 
337
- await playAnimationGroupOnce(animationGroup, framesPerSec, durationMs);
337
+ await this.viewer.utils.playAnimationGroupOnce(animationGroup, framesPerSec, durationMs);
338
338
  }
339
339
 
340
340
  /**
@@ -15,7 +15,7 @@ import {
15
15
  Viewer,
16
16
  ViewerEvent,
17
17
  } from '../index';
18
- import { getCbnViewerBridge } from '../internal/cbn-viewer-bridge';
18
+ import { CbnViewerBridge } from '../internal/cbn-viewer-bridge';
19
19
  import { nodeHasLeftHandedScaling } from '../internal/math-helper';
20
20
 
21
21
  /**
@@ -57,14 +57,13 @@ export class DebugManager {
57
57
  * @returns Signalizes if inspector could be loaded
58
58
  */
59
59
  public async showInspector(options?: IInspectorOptions): Promise<boolean> {
60
- const cbnWindowBridge = getCbnViewerBridge();
61
60
  if (process.env.NODE_ENV === 'development') {
62
61
  const inspModule = await import(/* webpackChunkName: "inspector"*/ '@babylonjs/inspector');
63
62
 
64
63
  const parentEl =
65
64
  this._parentDomElementForInspector ??
66
65
  // fallback to legacy `window.Cbn` call to support "old" cfgrs (pre Editor V2)
67
- cbnWindowBridge?.utils?.Viewer3dHelper?.getCfgrParentDomElementForInspector?.();
66
+ CbnViewerBridge?.utils?.Viewer3dHelper?.getCfgrParentDomElementForInspector?.();
68
67
 
69
68
  if (!options && parentEl) {
70
69
  // special case for usage in Combeenation configurator:
@@ -83,7 +82,7 @@ export class DebugManager {
83
82
  return true;
84
83
  } else {
85
84
  // inspector not available, set according warning message in console
86
- if (cbnWindowBridge) {
85
+ if (CbnViewerBridge) {
87
86
  console.warn(`Inspector not loaded.
88
87
  The inspector can only be used in development builds (e.g. during development with watch mode, in the configurator preview, ...)
89
88
  but not in production (e.g. production build of Custom JS, published configurator, ...).`);
@@ -9,7 +9,7 @@ import {
9
9
  ViewerErrorIds,
10
10
  ViewerEvent,
11
11
  } from '../index';
12
- import { getCbnViewerBridge } from '../internal/cbn-viewer-bridge';
12
+ import { CbnViewerBridge } from '../internal/cbn-viewer-bridge';
13
13
  import * as CloningHelper from '../internal/cloning-helper';
14
14
  import {
15
15
  clearInternalMetadataValue,
@@ -201,11 +201,10 @@ export class MaterialManager {
201
201
  return definition;
202
202
  }
203
203
 
204
- const cbnWindowBridge = getCbnViewerBridge();
205
- if (!definition && cbnWindowBridge?.Assets?.getMaterial) {
204
+ if (!definition && CbnViewerBridge?.Assets?.getMaterial) {
206
205
  // fallback to legacy `Cbn.Assets.getMaterial` call to support "old" cfgrs (pre Editor V2)
207
206
  // don't store the result in material defintions, as this code is just here for backwards compatibility`
208
- definition = cbnWindowBridge.Assets.getMaterial(materialId) as MaterialDefinition | undefined;
207
+ definition = CbnViewerBridge.Assets.getMaterial(materialId) as MaterialDefinition | undefined;
209
208
  }
210
209
 
211
210
  if (!definition) {
@@ -272,9 +272,7 @@ export class ParameterManager {
272
272
  protected _parameterObserver: { [parameterName: ParameterName]: ParameterObserver } = {};
273
273
 
274
274
  /** @internal */
275
- public constructor(protected viewer: Viewer) {
276
- this._addBuiltInParameterObservers();
277
- }
275
+ public constructor(protected viewer: Viewer) {}
278
276
 
279
277
  /**
280
278
  * Set parameter value for a certain node and calls the corresponding observer if the value has changed
@@ -417,6 +415,17 @@ export class ParameterManager {
417
415
  console.table(printable);
418
416
  }
419
417
 
418
+ /**
419
+ * Parameter observer implementation of default parameters
420
+ *
421
+ * @internal
422
+ */
423
+ public addBuiltInParameterObservers(): void {
424
+ createBuiltInParameter(this.viewer);
425
+ createBuiltInTextureParameter(this.viewer);
426
+ createPaintableParameter(this.viewer);
427
+ }
428
+
420
429
  /**
421
430
  * Applies all existing parameter entries to a certain "model", as defined in the {@link ModelManager}.\
422
431
  * This can be useful when updating the model before showing it in the scene.
@@ -579,15 +588,6 @@ export class ParameterManager {
579
588
  return inputValue;
580
589
  }
581
590
 
582
- /**
583
- * Parameter observer implementation of default parameters
584
- */
585
- protected _addBuiltInParameterObservers(): void {
586
- createBuiltInParameter(this, this.viewer.materialManager);
587
- createBuiltInTextureParameter(this, this.viewer.materialManager, this.viewer.scene);
588
- createPaintableParameter(this, this.viewer.scene);
589
- }
590
-
591
591
  /**
592
592
  * Change parameter value in array of existing parameter entries or create a new entry
593
593
  *
@@ -8,6 +8,7 @@ import {
8
8
  CubeTexture,
9
9
  DeepPartial,
10
10
  IShadowGenerator,
11
+ InstancedMesh,
11
12
  NodeDescription,
12
13
  TransformNode,
13
14
  Vector3,
@@ -366,11 +367,14 @@ export class SceneManager {
366
367
 
367
368
  const shadowCasterMeshes: AbstractMesh[] = [];
368
369
  this.viewer.scene.meshes.forEach(mesh => {
369
- mesh.receiveShadows = !nodeMatchesAnyCriteria(mesh, {
370
- isInList: settings?.excludeReceiverNodes,
371
- isHtmlAnchorMesh: true,
372
- isDimensionLine: true,
373
- });
370
+ // setting `receiveShadows` for instanced meshes has no effect and creates a warning in the console
371
+ if (!(mesh instanceof InstancedMesh)) {
372
+ mesh.receiveShadows = !nodeMatchesAnyCriteria(mesh, {
373
+ isInList: settings?.excludeReceiverNodes,
374
+ isHtmlAnchorMesh: true,
375
+ isDimensionLine: true,
376
+ });
377
+ }
374
378
 
375
379
  // exclude "helper meshes" (e.g. skybox, ground, dimension lines, html anchors) here to reduce the size of the
376
380
  // poisson filters auto shadow plane calculation, which will result in better shadow resolution
@@ -1,4 +1,7 @@
1
1
  import {
2
+ Animation,
3
+ AnimationGroup,
4
+ Color3,
2
5
  FloatArray,
3
6
  Geometry,
4
7
  Mesh,
@@ -13,6 +16,8 @@ import {
13
16
  Viewer,
14
17
  } from '../index';
15
18
 
19
+ export type AnimatableProperties = 'albedoColor' | 'position' | 'rotation' | 'scaling' | 'influence';
20
+
16
21
  export type BakeGeometrySettings = {
17
22
  keepTransformation?: boolean;
18
23
  };
@@ -165,6 +170,76 @@ export class ViewerUtils {
165
170
  return this.findParentNode(parent, criteria);
166
171
  }
167
172
  }
173
+
174
+ /**
175
+ * Animates a single property of a target object from its current value to a given target value.\
176
+ * Supported property types are defined by {@link AnimatableProperties} (i.e. `number`, `Vector3`, `Color3`).
177
+ *
178
+ * @param target The object whose property should be animated
179
+ * @param property The name of the property to animate. Must be a key of `target` whose value type is supported.
180
+ * @param value The target value the property should reach at the end of the animation.
181
+ * @param animationName Name given to the internally created animation group.\
182
+ * Use a stable, unique name per animated property so that concurrent calls can be
183
+ * identified (e.g. `"$parameterAnimation.position.MyNode"`).
184
+ * @param animationTimeMs Duration of the animation in milliseconds.
185
+ */
186
+ public async animateProperty<T, K extends Extract<keyof T, AnimatableProperties>>(
187
+ target: T,
188
+ property: K,
189
+ value: T[K],
190
+ animationName: string,
191
+ animationTimeMs: number
192
+ ): Promise<void> {
193
+ const framesPerSec = 100;
194
+ // extend if further `AnimatableProperties` with different types are added
195
+ const dataType =
196
+ value instanceof Vector3
197
+ ? Animation.ANIMATIONTYPE_VECTOR3
198
+ : value instanceof Color3
199
+ ? Animation.ANIMATIONTYPE_COLOR3
200
+ : Animation.ANIMATIONTYPE_FLOAT;
201
+
202
+ const animationGroup = new AnimationGroup(animationName);
203
+
204
+ const animation = new Animation(property, property, framesPerSec, dataType);
205
+ animation.setKeys([
206
+ { frame: 0, value: target[property] },
207
+ { frame: framesPerSec, value: value },
208
+ ]);
209
+ animationGroup.addTargetedAnimation(animation, target);
210
+
211
+ await this.playAnimationGroupOnce(animationGroup, framesPerSec, Math.max(animationTimeMs, 0));
212
+ }
213
+
214
+ /**
215
+ * Plays an animation group exactly in a certain duration, then disposes it.
216
+ *
217
+ * The animation group is expected to span exactly `framesPerSec` frames (i.e. one "logical second").\
218
+ * The speed ratio is derived from that assumption: `speedRatio = 1000 / durationMs`.
219
+ *
220
+ * Due to this strict convention, the method is marked as @internal and should not be used directly by a consumer.
221
+ */
222
+ public playAnimationGroupOnce(
223
+ animationGroup: AnimationGroup,
224
+ framesPerSec: number,
225
+ durationMs: number
226
+ ): Promise<void> {
227
+ if (durationMs <= 0) {
228
+ animationGroup.dispose();
229
+ return Promise.resolve();
230
+ }
231
+
232
+ // animation is created for 1 second (100 frames), adjust speed ratio according to desired movement time
233
+ const speedRatio = 1000 / durationMs;
234
+
235
+ return new Promise<void>(resolve => {
236
+ animationGroup.onAnimationGroupEndObservable.addOnce(() => {
237
+ animationGroup.dispose();
238
+ resolve();
239
+ });
240
+ animationGroup.start(false, speedRatio, 0, framesPerSec);
241
+ });
242
+ }
168
243
  }
169
244
 
170
245
  /**
package/src/viewer.ts CHANGED
@@ -301,6 +301,8 @@ export class Viewer {
301
301
  // call would already throw
302
302
  this._sceneManager.applyDefaultSettingsToScene();
303
303
 
304
+ this._parameterManager.addBuiltInParameterObservers();
305
+
304
306
  this._debugManager.registerAutofocusStartListener();
305
307
 
306
308
  engine.runRenderLoop(() => {
@@ -1,2 +0,0 @@
1
- import { AnimationGroup } from '../index';
2
- export declare function playAnimationGroupOnce(animationGroup: AnimationGroup, framesPerSec: number, durationMs: number): Promise<void>;
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.playAnimationGroupOnce = void 0;
4
- function playAnimationGroupOnce(animationGroup, framesPerSec, durationMs) {
5
- // animation is created for 1 second (100 frames), adjust speed ratio according to desired movement time
6
- const speedRatio = 1000 / durationMs;
7
- return new Promise(resolve => {
8
- animationGroup.onAnimationGroupEndObservable.addOnce(() => {
9
- animationGroup.dispose();
10
- resolve();
11
- });
12
- animationGroup.start(false, speedRatio, 0, framesPerSec);
13
- });
14
- }
15
- exports.playAnimationGroupOnce = playAnimationGroupOnce;
16
- //# sourceMappingURL=animation-helper.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"animation-helper.js","sourceRoot":"","sources":["../../../src/internal/animation-helper.ts"],"names":[],"mappings":";;;AAEA,SAAgB,sBAAsB,CACpC,cAA8B,EAC9B,YAAoB,EACpB,UAAkB;IAElB,wGAAwG;IACxG,MAAM,UAAU,GAAG,IAAI,GAAG,UAAU,CAAC;IAErC,OAAO,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;QACjC,cAAc,CAAC,6BAA6B,CAAC,OAAO,CAAC,GAAG,EAAE;YACxD,cAAc,CAAC,OAAO,EAAE,CAAC;YACzB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC;AAfD,wDAeC"}
@@ -1,18 +0,0 @@
1
- import { AnimationGroup } from '../index';
2
-
3
- export function playAnimationGroupOnce(
4
- animationGroup: AnimationGroup,
5
- framesPerSec: number,
6
- durationMs: number
7
- ): Promise<void> {
8
- // animation is created for 1 second (100 frames), adjust speed ratio according to desired movement time
9
- const speedRatio = 1000 / durationMs;
10
-
11
- return new Promise<void>(resolve => {
12
- animationGroup.onAnimationGroupEndObservable.addOnce(() => {
13
- animationGroup.dispose();
14
- resolve();
15
- });
16
- animationGroup.start(false, speedRatio, 0, framesPerSec);
17
- });
18
- }