diff --git a/CHANGELOG.md b/CHANGELOG.md
index 09331650e037a36714dd2574c9794d902e3513a8..699af760ab352300b81cf8b826f03678dd4935bb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ Note that since we don't clearly distinguish between a public and private interf
     - Factor out common code in `Dnatco` extension
     - Add `NtC tube` visual. Applicable for structures with NtC annotation
     - [Breaking] Rename `DnatcoConfalPyramids` to `DnatcoNtCs`
+- Improve boundary calculation performance
 
 ## [v3.29.0] - 2023-01-15
 
diff --git a/src/mol-geo/geometry/cylinders/cylinders.ts b/src/mol-geo/geometry/cylinders/cylinders.ts
index 41eadfd43cb4bb2c99baa2b03caa9e8441c499f1..9bd680028391fe252d46d5ddbea5063470900cc2 100644
--- a/src/mol-geo/geometry/cylinders/cylinders.ts
+++ b/src/mol-geo/geometry/cylinders/cylinders.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2020-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -214,7 +214,7 @@ export namespace Cylinders {
 
         const padding = getMaxSize(size) * props.sizeFactor;
         const invariantBoundingSphere = Sphere3D.clone(cylinders.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount, 0);
 
         return {
             dGeometryType: ValueCell.create('cylinders'),
@@ -272,7 +272,7 @@ export namespace Cylinders {
 
     function updateBoundingSphere(values: CylindersValues, cylinders: Cylinders) {
         const invariantBoundingSphere = Sphere3D.clone(cylinders.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value, 0);
 
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere);
diff --git a/src/mol-geo/geometry/direct-volume/direct-volume.ts b/src/mol-geo/geometry/direct-volume/direct-volume.ts
index a298d597e4bf3bae58a710702756399d563d98a4..0ae8d5f9ccc784208bcc089d9e3644a8a89a04dd 100644
--- a/src/mol-geo/geometry/direct-volume/direct-volume.ts
+++ b/src/mol-geo/geometry/direct-volume/direct-volume.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -223,7 +223,7 @@ export namespace DirectVolume {
         const counts = { drawCount: VolumeBox.indices.length, vertexCount: x * y * z, groupCount, instanceCount };
 
         const invariantBoundingSphere = Sphere3D.clone(directVolume.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount, 0);
 
         const controlPoints = getControlPointsFromVec2Array(props.controlPoints);
         const transferTex = createTransferFunctionTexture(controlPoints);
@@ -295,7 +295,7 @@ export namespace DirectVolume {
 
     function updateBoundingSphere(values: DirectVolumeValues, directVolume: DirectVolume) {
         const invariantBoundingSphere = Sphere3D.clone(directVolume.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value, 0);
 
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere);
diff --git a/src/mol-geo/geometry/image/image.ts b/src/mol-geo/geometry/image/image.ts
index cd4e1992272a9324bae51ebe851d94c6569df819..d3eecaf6fabecd5a5fec34ed91891a2b56fe249f 100644
--- a/src/mol-geo/geometry/image/image.ts
+++ b/src/mol-geo/geometry/image/image.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2020-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -154,7 +154,7 @@ namespace Image {
         const counts = { drawCount: QuadIndices.length, vertexCount: QuadPositions.length / 3, groupCount, instanceCount };
 
         const invariantBoundingSphere = Sphere3D.clone(image.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount, 0);
 
         return {
             dGeometryType: ValueCell.create('image'),
@@ -199,7 +199,7 @@ namespace Image {
 
     function updateBoundingSphere(values: ImageValues, image: Image) {
         const invariantBoundingSphere = Sphere3D.clone(image.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value, 0);
 
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere);
diff --git a/src/mol-geo/geometry/lines/lines.ts b/src/mol-geo/geometry/lines/lines.ts
index ecf1aa21b50583167562dd3c4feac7f8e2badf04..6b75f593be60ea3b25d44bfb62e8ef2384c3582b 100644
--- a/src/mol-geo/geometry/lines/lines.ts
+++ b/src/mol-geo/geometry/lines/lines.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -219,7 +219,7 @@ export namespace Lines {
         const counts = { drawCount: lines.lineCount * 2 * 3, vertexCount: lines.lineCount * 4, groupCount, instanceCount };
 
         const invariantBoundingSphere = Sphere3D.clone(lines.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount, 0);
 
         return {
             dGeometryType: ValueCell.create('lines'),
@@ -263,7 +263,7 @@ export namespace Lines {
 
     function updateBoundingSphere(values: LinesValues, lines: Lines) {
         const invariantBoundingSphere = Sphere3D.clone(lines.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value, 0);
 
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere);
diff --git a/src/mol-geo/geometry/mesh/mesh.ts b/src/mol-geo/geometry/mesh/mesh.ts
index 10b9c9b058105fa54e6fd2d95f743f36dec8d059..ab75ad195f667fc08a9ce05a65815aa6f2b84949 100644
--- a/src/mol-geo/geometry/mesh/mesh.ts
+++ b/src/mol-geo/geometry/mesh/mesh.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author David Sehnal <david.sehnal@gmail.com>
@@ -680,7 +680,7 @@ export namespace Mesh {
         const counts = { drawCount: mesh.triangleCount * 3, vertexCount: mesh.vertexCount, groupCount, instanceCount };
 
         const invariantBoundingSphere = Sphere3D.clone(mesh.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount, 0);
 
         return {
             dGeometryType: ValueCell.create('mesh'),
@@ -735,7 +735,7 @@ export namespace Mesh {
 
     function updateBoundingSphere(values: MeshValues, mesh: Mesh) {
         const invariantBoundingSphere = Sphere3D.clone(mesh.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value, 0);
 
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere);
diff --git a/src/mol-geo/geometry/points/points.ts b/src/mol-geo/geometry/points/points.ts
index e6c2fbd2defb792b0c6e58b3124c024085677de4..1d318ce57bdd45427bacea249406104f9452d712 100644
--- a/src/mol-geo/geometry/points/points.ts
+++ b/src/mol-geo/geometry/points/points.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -181,7 +181,7 @@ export namespace Points {
         const counts = { drawCount: points.pointCount, vertexCount: points.pointCount, groupCount, instanceCount };
 
         const invariantBoundingSphere = Sphere3D.clone(points.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount, 0);
 
         return {
             dGeometryType: ValueCell.create('points'),
@@ -222,7 +222,7 @@ export namespace Points {
 
     function updateBoundingSphere(values: PointsValues, points: Points) {
         const invariantBoundingSphere = Sphere3D.clone(points.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value, 0);
 
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere);
diff --git a/src/mol-geo/geometry/spheres/spheres.ts b/src/mol-geo/geometry/spheres/spheres.ts
index 0b82bb7da1ccf980b1543cc212d7cf2f3de60947..b8d3b246d50062dccac3dd3918a0589e9be06572 100644
--- a/src/mol-geo/geometry/spheres/spheres.ts
+++ b/src/mol-geo/geometry/spheres/spheres.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -184,7 +184,7 @@ export namespace Spheres {
 
         const padding = spheres.boundingSphere.radius ? getMaxSize(size) * props.sizeFactor : 0;
         const invariantBoundingSphere = Sphere3D.expand(Sphere3D(), spheres.boundingSphere, padding);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount, 0);
 
         return {
             dGeometryType: ValueCell.create('spheres'),
@@ -242,7 +242,7 @@ export namespace Spheres {
             ? getMaxSize(values) * values.uSizeFactor.ref.value
             : 0;
         const invariantBoundingSphere = Sphere3D.expand(Sphere3D(), spheres.boundingSphere, padding);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value, 0);
 
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere);
diff --git a/src/mol-geo/geometry/text/text.ts b/src/mol-geo/geometry/text/text.ts
index c68cae99e1fb883dadc2828317a265461c6158fa..e673f00189ea822b7c847131075ec14105670cb6 100644
--- a/src/mol-geo/geometry/text/text.ts
+++ b/src/mol-geo/geometry/text/text.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -223,7 +223,7 @@ export namespace Text {
 
         const padding = getPadding(text.mappingBuffer.ref.value, text.depthBuffer.ref.value, text.charCount, getMaxSize(size));
         const invariantBoundingSphere = Sphere3D.expand(Sphere3D(), text.boundingSphere, padding);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount, 0);
 
         return {
             dGeometryType: ValueCell.create('text'),
@@ -290,7 +290,7 @@ export namespace Text {
     function updateBoundingSphere(values: TextValues, text: Text) {
         const padding = getPadding(values.aMapping.ref.value, values.aDepth.ref.value, text.charCount, getMaxSize(values));
         const invariantBoundingSphere = Sphere3D.expand(Sphere3D(), text.boundingSphere, padding);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value, 0);
 
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere);
diff --git a/src/mol-geo/geometry/texture-mesh/texture-mesh.ts b/src/mol-geo/geometry/texture-mesh/texture-mesh.ts
index 585a9284319c2500d79e57635191eb07b68bd7f4..50654c2dd2cd6a176b0ba2e9badd0d42b67fad98 100644
--- a/src/mol-geo/geometry/texture-mesh/texture-mesh.ts
+++ b/src/mol-geo/geometry/texture-mesh/texture-mesh.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -187,7 +187,7 @@ export namespace TextureMesh {
         const counts = { drawCount: textureMesh.vertexCount, vertexCount: textureMesh.vertexCount, groupCount, instanceCount };
 
         const invariantBoundingSphere = Sphere3D.clone(textureMesh.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount, 0);
 
         return {
             dGeometryType: ValueCell.create('textureMesh'),
@@ -244,7 +244,7 @@ export namespace TextureMesh {
 
     function updateBoundingSphere(values: TextureMeshValues, textureMesh: TextureMesh) {
         const invariantBoundingSphere = Sphere3D.clone(textureMesh.boundingSphere);
-        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value);
+        const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value, 0);
 
         if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
             ValueCell.update(values.boundingSphere, boundingSphere);
diff --git a/src/mol-gl/renderable/util.ts b/src/mol-gl/renderable/util.ts
index c642c6507a62e48bfda5e4d0a3cdc131a5e1ec49..d9f4d45404da3e4571aeaffa2b8d6c307175d791 100644
--- a/src/mol-gl/renderable/util.ts
+++ b/src/mol-gl/renderable/util.ts
@@ -165,9 +165,9 @@ export function calculateInvariantBoundingSphere(position: Float32Array, positio
 
 const _mat4 = Mat4();
 
-export function calculateTransformBoundingSphere(invariantBoundingSphere: Sphere3D, transform: Float32Array, transformCount: number): Sphere3D {
+export function calculateTransformBoundingSphere(invariantBoundingSphere: Sphere3D, transform: Float32Array, transformCount: number, transformOffset: number): Sphere3D {
     if (transformCount === 1) {
-        Mat4.fromArray(_mat4, transform, 0);
+        Mat4.fromArray(_mat4, transform, transformOffset);
         const s = Sphere3D.clone(invariantBoundingSphere);
         return Mat4.isIdentity(_mat4) ? s : Sphere3D.transform(s, s, _mat4);
     }
@@ -181,25 +181,25 @@ export function calculateTransformBoundingSphere(invariantBoundingSphere: Sphere
     if (extrema && transformCount <= 14) {
         for (let i = 0, _i = transformCount; i < _i; ++i) {
             for (const e of extrema) {
-                v3transformMat4Offset(v, e, transform, 0, 0, i * 16);
+                v3transformMat4Offset(v, e, transform, 0, 0, i * 16 + transformOffset);
                 boundaryHelper.includePosition(v);
             }
         }
         boundaryHelper.finishedIncludeStep();
         for (let i = 0, _i = transformCount; i < _i; ++i) {
             for (const e of extrema) {
-                v3transformMat4Offset(v, e, transform, 0, 0, i * 16);
+                v3transformMat4Offset(v, e, transform, 0, 0, i * 16 + transformOffset);
                 boundaryHelper.radiusPosition(v);
             }
         }
     } else {
         for (let i = 0, _i = transformCount; i < _i; ++i) {
-            v3transformMat4Offset(v, center, transform, 0, 0, i * 16);
+            v3transformMat4Offset(v, center, transform, 0, 0, i * 16 + transformOffset);
             boundaryHelper.includePositionRadius(v, radius);
         }
         boundaryHelper.finishedIncludeStep();
         for (let i = 0, _i = transformCount; i < _i; ++i) {
-            v3transformMat4Offset(v, center, transform, 0, 0, i * 16);
+            v3transformMat4Offset(v, center, transform, 0, 0, i * 16 + transformOffset);
             boundaryHelper.radiusPositionRadius(v, radius);
         }
     }
@@ -209,7 +209,7 @@ export function calculateTransformBoundingSphere(invariantBoundingSphere: Sphere
 
 export function calculateBoundingSphere(position: Float32Array, positionCount: number, transform: Float32Array, transformCount: number, padding = 0, stepFactor = 1): { boundingSphere: Sphere3D, invariantBoundingSphere: Sphere3D } {
     const invariantBoundingSphere = calculateInvariantBoundingSphere(position, positionCount, stepFactor);
-    const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform, transformCount);
+    const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform, transformCount, 0);
     Sphere3D.expand(boundingSphere, boundingSphere, padding);
     Sphere3D.expand(invariantBoundingSphere, invariantBoundingSphere, padding);
     return { boundingSphere, invariantBoundingSphere };
diff --git a/src/mol-math/geometry/boundary-helper.ts b/src/mol-math/geometry/boundary-helper.ts
index 6f91c16ea78f011c7a4b63be520df1fbfc942b6e..78322c5048d05d64ac66416002b4419409291ef4 100644
--- a/src/mol-math/geometry/boundary-helper.ts
+++ b/src/mol-math/geometry/boundary-helper.ts
@@ -9,6 +9,11 @@ import { CentroidHelper } from './centroid-helper';
 import { Sphere3D } from '../geometry';
 import { Box3D } from './primitives/box3d';
 
+// avoiding namespace lookup improved performance in Chrome (Aug 2020)
+const v3dot = Vec3.dot;
+const v3copy = Vec3.copy;
+const v3scaleAndSub = Vec3.scaleAndSub;
+
 // implementing http://www.ep.liu.se/ecp/034/009/ecp083409.pdf
 
 export class BoundaryHelper {
@@ -21,28 +26,29 @@ export class BoundaryHelper {
     centroidHelper = new CentroidHelper();
 
     private computeExtrema(i: number, p: Vec3) {
-        const d = Vec3.dot(this.dir[i], p);
+        const d = v3dot(this.dir[i], p);
 
         if (d < this.minDist[i]) {
             this.minDist[i] = d;
-            Vec3.copy(this.extrema[i * 2], p);
+            v3copy(this.extrema[i * 2], p);
         }
         if (d > this.maxDist[i]) {
             this.maxDist[i] = d;
-            Vec3.copy(this.extrema[i * 2 + 1], p);
+            v3copy(this.extrema[i * 2 + 1], p);
         }
     }
 
     private computeSphereExtrema(i: number, center: Vec3, radius: number) {
-        const d = Vec3.dot(this.dir[i], center);
+        const di = this.dir[i];
+        const d = v3dot(di, center);
 
         if (d - radius < this.minDist[i]) {
             this.minDist[i] = d - radius;
-            Vec3.scaleAndSub(this.extrema[i * 2], center, this.dir[i], radius);
+            v3scaleAndSub(this.extrema[i * 2], center, di, radius);
         }
         if (d + radius > this.maxDist[i]) {
             this.maxDist[i] = d + radius;
-            Vec3.scaleAndAdd(this.extrema[i * 2 + 1], center, this.dir[i], radius);
+            v3scaleAndSub(this.extrema[i * 2 + 1], center, di, radius);
         }
     }
 
@@ -94,7 +100,7 @@ export class BoundaryHelper {
     }
 
     getSphere(sphere?: Sphere3D) {
-        return Sphere3D.setExtrema(this.centroidHelper.getSphere(sphere), [...this.extrema]);
+        return Sphere3D.setExtrema(this.centroidHelper.getSphere(sphere), this.extrema.slice());
     }
 
     getBox(box?: Box3D) {
diff --git a/src/mol-math/geometry/centroid-helper.ts b/src/mol-math/geometry/centroid-helper.ts
index 32c67e8665a815898780218c2865e821195da3b2..3f7dd01297deecd7300296f533f6d8fb50f192fb 100644
--- a/src/mol-math/geometry/centroid-helper.ts
+++ b/src/mol-math/geometry/centroid-helper.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -8,6 +8,11 @@
 import { Vec3 } from '../../mol-math/linear-algebra/3d/vec3';
 import { Sphere3D } from './primitives/sphere3d';
 
+// avoiding namespace lookup improved performance in Chrome (Aug 2020)
+const v3add = Vec3.add;
+const v3squaredDistance = Vec3.squaredDistance;
+const v3distance = Vec3.distance;
+
 export { CentroidHelper };
 
 class CentroidHelper {
@@ -23,7 +28,7 @@ class CentroidHelper {
     }
 
     includeStep(p: Vec3) {
-        Vec3.add(this.center, this.center, p);
+        v3add(this.center, this.center, p);
         this.count++;
     }
 
@@ -33,12 +38,12 @@ class CentroidHelper {
     }
 
     radiusStep(p: Vec3) {
-        const d = Vec3.squaredDistance(p, this.center);
+        const d = v3squaredDistance(p, this.center);
         if (d > this.radiusSq) this.radiusSq = d;
     }
 
     radiusSphereStep(center: Vec3, radius: number) {
-        const _d = Vec3.distance(center, this.center) + radius;
+        const _d = v3distance(center, this.center) + radius;
         const d = _d * _d;
         if (d > this.radiusSq) this.radiusSq = d;
     }
diff --git a/src/mol-repr/visual.ts b/src/mol-repr/visual.ts
index 4a3f41ebb38bef03cf66c8ec2d0f4ae026f0ba8b..f6a5c0f1a8bf421f160d7648cc015e86ba4c61a5 100644
--- a/src/mol-repr/visual.ts
+++ b/src/mol-repr/visual.ts
@@ -374,7 +374,7 @@ namespace Visual {
             ValueCell.update(values.extraTransform, values.extraTransform.ref.value);
         }
         updateTransformData(values);
-        const boundingSphere = calculateTransformBoundingSphere(values.invariantBoundingSphere.ref.value, values.aTransform.ref.value, values.instanceCount.ref.value);
+        const boundingSphere = calculateTransformBoundingSphere(values.invariantBoundingSphere.ref.value, values.aTransform.ref.value, values.instanceCount.ref.value, 0);
         ValueCell.update(values.boundingSphere, boundingSphere);
     }
 }
\ No newline at end of file