From 6d09319c3155b3c59ffca19c1e973aadaa593543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 5 Nov 2024 11:01:42 +0100 Subject: [PATCH 1/6] feat(experimental): Add Image360Intersection to Any-intersection result --- .../packages/360-images/src/Image360Facade.ts | 7 ++++- .../visual-tests/Image360.VisualTest.ts | 4 +-- .../api/src/api-helpers/Image360ApiHelper.ts | 10 ++++--- .../src/public/migration/Cognite3DViewer.ts | 29 ++++++++++--------- .../api/src/public/migration/types.ts | 21 +++++++++++++- 5 files changed, 49 insertions(+), 22 deletions(-) diff --git a/viewer/packages/360-images/src/Image360Facade.ts b/viewer/packages/360-images/src/Image360Facade.ts index 48582d00dc5..bbde60b1cde 100644 --- a/viewer/packages/360-images/src/Image360Facade.ts +++ b/viewer/packages/360-images/src/Image360Facade.ts @@ -14,6 +14,7 @@ import { Image360RevisionEntity } from './entity/Image360RevisionEntity'; import { Image360AnnotationFilterOptions } from './annotation/types'; import { AsyncSequencer } from '@reveal/utilities/src/AsyncSequencer'; import { DataSourceType } from '@reveal/data-providers'; +import { Image360Collection } from 'api-entry-points/core'; export class Image360Facade { private readonly _image360Collections: DefaultImage360Collection[]; @@ -121,7 +122,10 @@ export class Image360Facade { return imageCollection[0]; } - public intersect(coords: THREE.Vector2, camera: THREE.Camera): Image360Entity | undefined { + public intersect( + coords: THREE.Vector2, + camera: THREE.Camera + ): [DefaultImage360Collection, Image360Entity] | undefined { const cameraDirection = camera.getWorldDirection(new THREE.Vector3()); const cameraPosition = camera.position.clone(); const collectionMatrix = new THREE.Matrix4(); @@ -144,6 +148,7 @@ export class Image360Facade { .filter(isInFrontOfCamera) .sort(byDistanceToCamera) .map(selectEntity) + .map(entity => [collection, entity] as [Image360Collection, Image360Entity]) ); return first(intersections); diff --git a/viewer/packages/360-images/visual-tests/Image360.VisualTest.ts b/viewer/packages/360-images/visual-tests/Image360.VisualTest.ts index 9984ebf7bbf..b399bb1d52d 100644 --- a/viewer/packages/360-images/visual-tests/Image360.VisualTest.ts +++ b/viewer/packages/360-images/visual-tests/Image360.VisualTest.ts @@ -107,7 +107,7 @@ export default class Image360VisualTestFixture extends StreamingVisualTestFixtur renderer.domElement.addEventListener('click', async event => { const { x, y } = event; const ndcCoordinates = getNormalizedPixelCoordinates(renderer.domElement, x, y); - const entity = facade.intersect(new THREE.Vector2(ndcCoordinates.x, ndcCoordinates.y), camera); + const [_, entity] = facade.intersect(new THREE.Vector2(ndcCoordinates.x, ndcCoordinates.y), camera); if (entity === undefined) { this.render(); @@ -193,7 +193,7 @@ export default class Image360VisualTestFixture extends StreamingVisualTestFixtur renderer.domElement.addEventListener('mousemove', async event => { const { x, y } = event; const ndcCoordinates = getNormalizedPixelCoordinates(renderer.domElement, x, y); - const entity = facade.intersect(new THREE.Vector2(ndcCoordinates.x, ndcCoordinates.y), camera); + const [_, entity] = facade.intersect(new THREE.Vector2(ndcCoordinates.x, ndcCoordinates.y), camera); if (entity === undefined) { this.render(); return; diff --git a/viewer/packages/api/src/api-helpers/Image360ApiHelper.ts b/viewer/packages/api/src/api-helpers/Image360ApiHelper.ts index a478a03e522..35ca590b1cd 100644 --- a/viewer/packages/api/src/api-helpers/Image360ApiHelper.ts +++ b/viewer/packages/api/src/api-helpers/Image360ApiHelper.ts @@ -568,20 +568,22 @@ export class Image360ApiHelper { if (this._transitionInProgress) { return Promise.resolve(false); } - const entity = this.intersect360ImageIcons(event.offsetX, event.offsetY); + const [_, entity] = this.intersect360ImageIcons(event.offsetX, event.offsetY); if (entity === undefined) { return Promise.resolve(false); } return this.enter360ImageInternal(entity); } - public intersect360ImageIcons(offsetX: number, offsetY: number): Image360Entity | undefined { + public intersect360ImageIcons( + offsetX: number, + offsetY: number + ): [DefaultImage360Collection, Image360Entity] | undefined { const ndcCoordinates = getNormalizedPixelCoordinates(this._domElement, offsetX, offsetY); - const entity = this._image360Facade.intersect( + return this._image360Facade.intersect( new Vector2(ndcCoordinates.x, ndcCoordinates.y), this._activeCameraManager.getCamera() ); - return entity; } public intersect360ImageAnnotations(offsetX: number, offsetY: number): Image360AnnotationIntersection | undefined { diff --git a/viewer/packages/api/src/public/migration/Cognite3DViewer.ts b/viewer/packages/api/src/public/migration/Cognite3DViewer.ts index f3491ab884d..413ab93d6ea 100644 --- a/viewer/packages/api/src/public/migration/Cognite3DViewer.ts +++ b/viewer/packages/api/src/public/migration/Cognite3DViewer.ts @@ -48,7 +48,8 @@ import { ResolutionOptions, RenderParameters, AnyIntersection, - AddModelOptions + AddModelOptions, + Image360IconIntersection } from './types'; import { RevealManager } from '../RevealManager'; import { CogniteModel, Image360WithCollection } from '../types'; @@ -1659,7 +1660,7 @@ export class Cognite3DViewer> { - if (this.isIntersecting360Icon(new THREE.Vector2(offsetX, offsetY))) { + if (this.intersect360Icons(new THREE.Vector2(offsetX, offsetY)) !== undefined) { return null; } return this.intersectModels(offsetX, offsetY) as Promise | null>; @@ -1682,8 +1683,9 @@ export class Cognite3DViewer boolean; } ): Promise | undefined> { - if ((options?.stopOnHitting360Icon ?? true) && this.isIntersecting360Icon(pixelCoords)) { - return undefined; + const image360IconIntersection = this.intersect360Icons(pixelCoords); + if (this.intersect360Icons(pixelCoords) !== undefined) { + return image360IconIntersection; } const predicate = options?.predicate; @@ -1740,18 +1742,17 @@ export class Cognite3DViewer | undefined { + const intersectedImage = this._image360ApiHelper?.intersect360ImageIcons(vector.x, vector.y); + if (intersectedImage === undefined) { + return undefined; } - return false; + return { + type: 'image360Icon', + collection: intersectedImage[0], + image360: intersectedImage[1] + }; } /** diff --git a/viewer/packages/api/src/public/migration/types.ts b/viewer/packages/api/src/public/migration/types.ts index 1b05e759ee2..dd4aff486f7 100644 --- a/viewer/packages/api/src/public/migration/types.ts +++ b/viewer/packages/api/src/public/migration/types.ts @@ -14,7 +14,7 @@ import { EdlOptions } from '@reveal/rendering'; import { Cognite3DViewer } from './Cognite3DViewer'; import { DefaultCameraManager } from '@reveal/camera-manager'; import { CdfModelIdentifier, CommonModelOptions } from '@reveal/data-providers'; -import { Image360AnnotationFilterOptions } from '@reveal/360-images'; +import { Image360, Image360AnnotationFilterOptions, Image360Collection } from '@reveal/360-images'; import type { Vector2, WebGLRenderTarget, WebGLRenderer, Matrix4, Vector3 } from 'three'; import { CustomObjectIntersection } from '@reveal/utilities'; import { ClassicDataSourceType, DataSourceType, DMDataSourceType } from '@reveal/data-providers'; @@ -294,6 +294,24 @@ export type Intersection = | CadIntersection | PointCloudIntersection; +/** + * Represents the result from a 360 intersection test + */ +export type Image360IconIntersection = { + /** + * The intersection type. + */ + type: 'image360Icon'; + /** + * The image360 that was intersected + */ + image360: Image360; + /** + * The image360 collection that was intersected. + */ + collection: Image360Collection; +}; + /** * Represents the result from {@link Cognite3DViewer.getAnyIntersectionFromPixel}. * @module @cognite/reveal @@ -302,6 +320,7 @@ export type Intersection = export type AnyIntersection = | CadIntersection | PointCloudIntersection + | Image360IconIntersection | CustomObjectIntersection; /** From 8346d9223318f2af9baac1f94efb53a9e30eea75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 5 Nov 2024 11:04:23 +0100 Subject: [PATCH 2/6] chore: mark as beta --- viewer/packages/api/src/public/migration/types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/viewer/packages/api/src/public/migration/types.ts b/viewer/packages/api/src/public/migration/types.ts index dd4aff486f7..74be68eddb0 100644 --- a/viewer/packages/api/src/public/migration/types.ts +++ b/viewer/packages/api/src/public/migration/types.ts @@ -296,6 +296,8 @@ export type Intersection = /** * Represents the result from a 360 intersection test + * @module @cognite/reveal + * @beta */ export type Image360IconIntersection = { /** From ccf8809db53251438268c1271d402f6f143dbc8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 5 Nov 2024 11:18:55 +0100 Subject: [PATCH 3/6] chore: make return type more clean --- .../packages/360-images/src/Image360Facade.ts | 26 +++++++++++++------ viewer/packages/360-images/src/types.ts | 11 ++++++++ .../visual-tests/Image360.VisualTest.ts | 11 +++++--- .../api/src/api-helpers/Image360ApiHelper.ts | 13 ++++++---- .../src/public/migration/Cognite3DViewer.ts | 7 +++-- .../api/src/public/migration/types.ts | 10 ++++++- 6 files changed, 56 insertions(+), 22 deletions(-) diff --git a/viewer/packages/360-images/src/Image360Facade.ts b/viewer/packages/360-images/src/Image360Facade.ts index bbde60b1cde..b7c0fb158b6 100644 --- a/viewer/packages/360-images/src/Image360Facade.ts +++ b/viewer/packages/360-images/src/Image360Facade.ts @@ -15,6 +15,8 @@ import { Image360AnnotationFilterOptions } from './annotation/types'; import { AsyncSequencer } from '@reveal/utilities/src/AsyncSequencer'; import { DataSourceType } from '@reveal/data-providers'; import { Image360Collection } from 'api-entry-points/core'; +import { Image360IconIntersectionData } from './types'; +import { Vector } from 'html2canvas/dist/types/render/vector'; export class Image360Facade { private readonly _image360Collections: DefaultImage360Collection[]; @@ -122,10 +124,7 @@ export class Image360Facade { return imageCollection[0]; } - public intersect( - coords: THREE.Vector2, - camera: THREE.Camera - ): [DefaultImage360Collection, Image360Entity] | undefined { + public intersect(coords: THREE.Vector2, camera: THREE.Camera): Image360IconIntersectionData | undefined { const cameraDirection = camera.getWorldDirection(new THREE.Vector3()); const cameraPosition = camera.position.clone(); const collectionMatrix = new THREE.Matrix4(); @@ -147,8 +146,9 @@ export class Image360Facade { .map(intersectionToCameraSpace) .filter(isInFrontOfCamera) .sort(byDistanceToCamera) - .map(selectEntity) - .map(entity => [collection, entity] as [Image360Collection, Image360Entity]) + .map(([entity, intersectionPoint]) => + createIntersection(collection, entity, intersectionPoint, camera.position) + ) ); return first(intersections); @@ -212,8 +212,18 @@ export class Image360Facade { return a.lengthSq() - b.lengthSq(); } - function selectEntity([entity, _]: [Image360Entity, THREE.Vector3]): Image360Entity { - return entity; + function createIntersection( + image360Collection: DefaultImage360Collection, + image360: Image360Entity, + intersectionPoint: THREE.Vector3, + cameraPosition: THREE.Vector3 + ): Image360IconIntersectionData { + return { + image360, + image360Collection, + point: intersectionPoint, + distanceToCamera: intersectionPoint.distanceTo(cameraPosition) + }; } } diff --git a/viewer/packages/360-images/src/types.ts b/viewer/packages/360-images/src/types.ts index 040117cb95c..0134f998fd6 100644 --- a/viewer/packages/360-images/src/types.ts +++ b/viewer/packages/360-images/src/types.ts @@ -2,8 +2,12 @@ * Copyright 2023 Cognite AS */ +import { Vector3 } from 'three'; import { Image360 } from './entity/Image360'; import { Image360Revision } from './entity/Image360Revision'; +import { DataSourceType, DefaultCameraManager, Image360Collection } from 'api-entry-points/core'; +import { Image360Entity } from './entity/Image360Entity'; +import { DefaultImage360Collection } from './collection/DefaultImage360Collection'; /** * Delegate for 360 image mode entered events. @@ -14,3 +18,10 @@ export type Image360EnteredDelegate = (image360: Image360, revision: Image360Rev * Delegate for 360 image mode exited events. */ export type Image360ExitedDelegate = () => void; + +export type Image360IconIntersectionData = { + image360Collection: DefaultImage360Collection; + image360: Image360Entity; + point: Vector3; + distanceToCamera: number; +}; diff --git a/viewer/packages/360-images/visual-tests/Image360.VisualTest.ts b/viewer/packages/360-images/visual-tests/Image360.VisualTest.ts index b399bb1d52d..48a4c4a4197 100644 --- a/viewer/packages/360-images/visual-tests/Image360.VisualTest.ts +++ b/viewer/packages/360-images/visual-tests/Image360.VisualTest.ts @@ -107,13 +107,15 @@ export default class Image360VisualTestFixture extends StreamingVisualTestFixtur renderer.domElement.addEventListener('click', async event => { const { x, y } = event; const ndcCoordinates = getNormalizedPixelCoordinates(renderer.domElement, x, y); - const [_, entity] = facade.intersect(new THREE.Vector2(ndcCoordinates.x, ndcCoordinates.y), camera); + const intersection = facade.intersect(new THREE.Vector2(ndcCoordinates.x, ndcCoordinates.y), camera); - if (entity === undefined) { + if (intersection === undefined) { this.render(); return; } + const entity = intersection.image360; + await facade.preload(entity, entity.getActiveRevision()); entity.image360Visualization.visible = true; entity.icon.setVisible(false); @@ -193,11 +195,12 @@ export default class Image360VisualTestFixture extends StreamingVisualTestFixtur renderer.domElement.addEventListener('mousemove', async event => { const { x, y } = event; const ndcCoordinates = getNormalizedPixelCoordinates(renderer.domElement, x, y); - const [_, entity] = facade.intersect(new THREE.Vector2(ndcCoordinates.x, ndcCoordinates.y), camera); - if (entity === undefined) { + const intersection = facade.intersect(new THREE.Vector2(ndcCoordinates.x, ndcCoordinates.y), camera); + if (intersection === undefined) { this.render(); return; } + const entity = intersection.image360; entity.icon.selected = true; await facade.preload(entity, entity.getActiveRevision()); entity.image360Visualization.visible = false; diff --git a/viewer/packages/api/src/api-helpers/Image360ApiHelper.ts b/viewer/packages/api/src/api-helpers/Image360ApiHelper.ts index 35ca590b1cd..79dcf0f83ea 100644 --- a/viewer/packages/api/src/api-helpers/Image360ApiHelper.ts +++ b/viewer/packages/api/src/api-helpers/Image360ApiHelper.ts @@ -46,6 +46,7 @@ import { Image360WithCollection } from '../public/types'; import { DEFAULT_IMAGE_360_OPACITY } from '@reveal/360-images/src/entity/Image360VisualizationBox'; import { Image360History } from '@reveal/360-images/src/Image360History'; import { Image360Action } from '@reveal/360-images/src/Image360Action'; +import { Image360IconIntersectionData } from '@reveal/360-images/src/types'; export class Image360ApiHelper { private readonly _image360Facade: Image360Facade; @@ -568,17 +569,17 @@ export class Image360ApiHelper { if (this._transitionInProgress) { return Promise.resolve(false); } - const [_, entity] = this.intersect360ImageIcons(event.offsetX, event.offsetY); - if (entity === undefined) { + const intersection = this.intersect360ImageIcons(event.offsetX, event.offsetY); + if (intersection === undefined) { return Promise.resolve(false); } - return this.enter360ImageInternal(entity); + return this.enter360ImageInternal(intersection.image360); } public intersect360ImageIcons( offsetX: number, offsetY: number - ): [DefaultImage360Collection, Image360Entity] | undefined { + ): Image360IconIntersectionData | undefined { const ndcCoordinates = getNormalizedPixelCoordinates(this._domElement, offsetX, offsetY); return this._image360Facade.intersect( new Vector2(ndcCoordinates.x, ndcCoordinates.y), @@ -613,11 +614,13 @@ export class Image360ApiHelper { this._interactionState.lastMousePosition = { offsetX, offsetY }; this._image360Facade.allIconsSelected = false; const ndcCoordinates = getNormalizedPixelCoordinates(this._domElement, offsetX, offsetY); - const entity = this._image360Facade.intersect( + const intersection = this._image360Facade.intersect( new Vector2(ndcCoordinates.x, ndcCoordinates.y), this._activeCameraManager.getCamera() ); + const entity = intersection?.image360; + if (entity === this._interactionState.currentImage360Hovered) { entity?.icon.updateHoverSpriteScale(); return; diff --git a/viewer/packages/api/src/public/migration/Cognite3DViewer.ts b/viewer/packages/api/src/public/migration/Cognite3DViewer.ts index 413ab93d6ea..79728c8a748 100644 --- a/viewer/packages/api/src/public/migration/Cognite3DViewer.ts +++ b/viewer/packages/api/src/public/migration/Cognite3DViewer.ts @@ -1743,15 +1743,14 @@ export class Cognite3DViewer | undefined { - const intersectedImage = this._image360ApiHelper?.intersect360ImageIcons(vector.x, vector.y); - if (intersectedImage === undefined) { + const iconIntersection = this._image360ApiHelper?.intersect360ImageIcons(vector.x, vector.y); + if (iconIntersection === undefined) { return undefined; } return { type: 'image360Icon', - collection: intersectedImage[0], - image360: intersectedImage[1] + ...iconIntersection }; } diff --git a/viewer/packages/api/src/public/migration/types.ts b/viewer/packages/api/src/public/migration/types.ts index 74be68eddb0..18117005ead 100644 --- a/viewer/packages/api/src/public/migration/types.ts +++ b/viewer/packages/api/src/public/migration/types.ts @@ -311,7 +311,15 @@ export type Image360IconIntersection /** * The image360 collection that was intersected. */ - collection: Image360Collection; + image360Collection: Image360Collection; + /** + * Coordinate of the intersection. + */ + point: Vector3; + /** + * Distance from the camera to the intersection. + */ + distanceToCamera: number; }; /** From 93a14e818271954d5482af3b2a0602a6b87372db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 5 Nov 2024 11:19:50 +0100 Subject: [PATCH 4/6] chore: lint fix and update API --- viewer/packages/360-images/src/Image360Facade.ts | 2 -- viewer/packages/360-images/src/types.ts | 2 +- viewer/packages/api/src/public/migration/types.ts | 4 ++-- viewer/reveal.api.md | 11 ++++++++++- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/viewer/packages/360-images/src/Image360Facade.ts b/viewer/packages/360-images/src/Image360Facade.ts index b7c0fb158b6..4c3430f7245 100644 --- a/viewer/packages/360-images/src/Image360Facade.ts +++ b/viewer/packages/360-images/src/Image360Facade.ts @@ -14,9 +14,7 @@ import { Image360RevisionEntity } from './entity/Image360RevisionEntity'; import { Image360AnnotationFilterOptions } from './annotation/types'; import { AsyncSequencer } from '@reveal/utilities/src/AsyncSequencer'; import { DataSourceType } from '@reveal/data-providers'; -import { Image360Collection } from 'api-entry-points/core'; import { Image360IconIntersectionData } from './types'; -import { Vector } from 'html2canvas/dist/types/render/vector'; export class Image360Facade { private readonly _image360Collections: DefaultImage360Collection[]; diff --git a/viewer/packages/360-images/src/types.ts b/viewer/packages/360-images/src/types.ts index 0134f998fd6..e719fe14292 100644 --- a/viewer/packages/360-images/src/types.ts +++ b/viewer/packages/360-images/src/types.ts @@ -5,7 +5,7 @@ import { Vector3 } from 'three'; import { Image360 } from './entity/Image360'; import { Image360Revision } from './entity/Image360Revision'; -import { DataSourceType, DefaultCameraManager, Image360Collection } from 'api-entry-points/core'; +import { DataSourceType } from 'api-entry-points/core'; import { Image360Entity } from './entity/Image360Entity'; import { DefaultImage360Collection } from './collection/DefaultImage360Collection'; diff --git a/viewer/packages/api/src/public/migration/types.ts b/viewer/packages/api/src/public/migration/types.ts index 18117005ead..3293c26b5d9 100644 --- a/viewer/packages/api/src/public/migration/types.ts +++ b/viewer/packages/api/src/public/migration/types.ts @@ -295,7 +295,7 @@ export type Intersection = | PointCloudIntersection; /** - * Represents the result from a 360 intersection test + * Represents the result from a 360 intersection test. * @module @cognite/reveal * @beta */ @@ -305,7 +305,7 @@ export type Image360IconIntersection */ type: 'image360Icon'; /** - * The image360 that was intersected + * The image360 that was intersected. */ image360: Image360; /** diff --git a/viewer/reveal.api.md b/viewer/reveal.api.md index 171b38e667c..b3c2b235b51 100644 --- a/viewer/reveal.api.md +++ b/viewer/reveal.api.md @@ -58,7 +58,7 @@ export class AnnotationIdPointCloudObjectCollection extends PointCloudAnnotation } // @beta -export type AnyIntersection = CadIntersection | PointCloudIntersection | CustomObjectIntersection; +export type AnyIntersection = CadIntersection | PointCloudIntersection | Image360IconIntersection | CustomObjectIntersection; // @public export interface AreaCollection { @@ -1307,6 +1307,15 @@ export type Image360EnteredDelegate = (image360: Image360, revision: Image360Rev // @public export type Image360ExitedDelegate = () => void; +// @beta +export type Image360IconIntersection = { + type: 'image360Icon'; + image360: Image360; + image360Collection: Image360Collection; + point: Vector3; + distanceToCamera: number; +}; + // @public export type Image360IconStyle = { color?: Color; From deb3b91cd7f2b504c59e03b1f8aecded2e57b149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 5 Nov 2024 12:23:34 +0100 Subject: [PATCH 5/6] chore: fix import path --- viewer/packages/360-images/src/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/viewer/packages/360-images/src/types.ts b/viewer/packages/360-images/src/types.ts index e719fe14292..c4858c8164e 100644 --- a/viewer/packages/360-images/src/types.ts +++ b/viewer/packages/360-images/src/types.ts @@ -5,7 +5,7 @@ import { Vector3 } from 'three'; import { Image360 } from './entity/Image360'; import { Image360Revision } from './entity/Image360Revision'; -import { DataSourceType } from 'api-entry-points/core'; +import { DataSourceType } from '@reveal/data-providers'; import { Image360Entity } from './entity/Image360Entity'; import { DefaultImage360Collection } from './collection/DefaultImage360Collection'; From fb90bbabb6b60b0d90a57c81df987f1c696f3e66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 5 Nov 2024 12:35:36 +0100 Subject: [PATCH 6/6] chore: bump react version to 4.21.0 --- viewer/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/viewer/package.json b/viewer/package.json index a6181588abf..3fa9263cd6b 100644 --- a/viewer/package.json +++ b/viewer/package.json @@ -1,6 +1,6 @@ { "name": "@cognite/reveal", - "version": "4.20.1", + "version": "4.21.0", "description": "WebGL based 3D viewer for CAD and point clouds processed in Cognite Data Fusion.", "homepage": "https://github.com/cognitedata/reveal/tree/master/viewer", "repository": {