diff --git a/CHANGELOG.md b/CHANGELOG.md
index 039025ad5747a97cba46c7417d0754915a019610..fa13409da664c06f55a1509f21873d7520ddb2db 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,9 +6,9 @@ Note that since we don't clearly distinguish between a public and private interf
 
 ## [Unreleased]
 
-- Change the position of the camera based on the PCA of the structure and the following rules.
+- Change the position of the camera based on the PCA of the structure and the following rules:
     - The first residue should be in first quadrant if there is only one chain
-    - The average position of the residues of the first chain should be in the first residue if there are more than one chain.
+    - The average position of the residues of the first chain should be in the first quadrant if there is more than one chain
 - Add `HeadlessPluginContext` and `HeadlessScreenshotHelper` to be used in Node.js
 - Add example `image-renderer`
 - Fix wrong offset when rendering text with orthographic projection
diff --git a/src/mol-canvas3d/camera.ts b/src/mol-canvas3d/camera.ts
index 50ba8fe635fd7b535c291df209c61a1a25b1616a..72b788c2320df29ed697cba1e7bc41f64574292c 100644
--- a/src/mol-canvas3d/camera.ts
+++ b/src/mol-canvas3d/camera.ts
@@ -119,11 +119,11 @@ class Camera implements ICamera {
         return Camera.targetDistance(radius, this.state.fov, this.viewport.width, this.viewport.height);
     }
 
-    getFocus(target: Vec3, radius: number, up?: Vec3, dir?: Vec3): Partial<Camera.Snapshot> {
+    getFocus(target: Vec3, radius: number, up?: Vec3, dir?: Vec3, snapshot?: Partial<Camera.Snapshot>): Partial<Camera.Snapshot> {
         const r = Math.max(radius, 0.01);
         const targetDistance = this.getTargetDistance(r);
 
-        Vec3.sub(this.deltaDirection, this.target, this.position);
+        Vec3.sub(this.deltaDirection, snapshot?.target ?? this.target, snapshot?.position ?? this.position);
         if (dir) Vec3.matchDirection(this.deltaDirection, dir, this.deltaDirection);
         Vec3.setMagnitude(this.deltaDirection, this.deltaDirection, targetDistance);
         Vec3.sub(this.newPosition, target, this.deltaDirection);
diff --git a/src/mol-plugin-state/manager/camera.ts b/src/mol-plugin-state/manager/camera.ts
index 5a3cfa94091662a570d2f0f1e4793eaecc24b2f8..60dbc65c247b6080f5b3baa1801ea83d64474f2e 100644
--- a/src/mol-plugin-state/manager/camera.ts
+++ b/src/mol-plugin-state/manager/camera.ts
@@ -117,9 +117,7 @@ export class CameraManager {
         const radius = Math.max(sphere.radius + extraRadius, minRadius);
 
         if (options?.principalAxes) {
-            this.plugin.canvas3d?.camera.setState(Camera.createDefaultSnapshot());
-            const { origin, dirA, dirC } = pcaFocus(this.plugin, options);
-            const snapshot = this.plugin.canvas3d?.camera.getFocus(origin, radius, dirA, dirC);
+            const snapshot = pcaFocus(this.plugin, radius, options as { principalAxes: PrincipalAxes, positionToFlip?: Vec3 });
             this.plugin.canvas3d?.requestCameraReset({ durationMs, snapshot });
         } else {
             const snapshot = canvas3d.camera.getFocus(sphere.center, radius);
diff --git a/src/mol-plugin-state/manager/focus-camera/focus-first-residue.ts b/src/mol-plugin-state/manager/focus-camera/focus-first-residue.ts
index 545d9b76bffd50995a8c30aba88377554729917d..529fe6fe39229c46a7f0ad0439d8769f8f523385 100644
--- a/src/mol-plugin-state/manager/focus-camera/focus-first-residue.ts
+++ b/src/mol-plugin-state/manager/focus-camera/focus-first-residue.ts
@@ -1,36 +1,51 @@
 /**
- * Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2022-23 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Ke Ma <mark.ma@rcsb.org>
+ * @author David Sehnal <david.sehnal@gmail.com>
  */
 import { Structure } from '../../../mol-model/structure';
 import { Vec3 } from '../../..//mol-math/linear-algebra/3d/vec3';
 import { PluginContext } from '../../../mol-plugin/context';
-import { CameraFocusOptions } from '../camera';
 import { PrincipalAxes } from '../../../mol-math/linear-algebra/matrix/principal-axes';
 import { StructureComponentRef } from '../structure/hierarchy-state';
-import { deepClone } from '../../../mol-util/object';
-import { ChunkedArray } from '../../../mol-data/util/chunked-array';
+import { Camera } from '../../../mol-canvas3d/camera';
 
 
-export function getPolymerPositions(polymerStructure: Structure): Float32Array {
-    const tmpMatrix = Vec3.zero();
-    const cAdd3 = ChunkedArray.add3;
-    const positions = ChunkedArray.create(Float32Array, 3, 1024, polymerStructure.atomicResidueCount);
-    for (let i = 0; i < polymerStructure.units.length; i++) {
-        const unit = polymerStructure.units[i];
+function getPolymerPositions(structure: Structure): Float32Array | undefined {
+    if (structure.atomicResidueCount === 1) return undefined;
+
+    let polymerElementCount = 0;
+    for (const unit of structure.units) {
+        polymerElementCount += unit.props.polymerElements?.length ?? 0;
+    }
+
+    if (polymerElementCount <= 1) return undefined;
+
+    const stride = 2 ** Math.max(Math.ceil(Math.log10(polymerElementCount / 1000)), 0);
+    const size = stride === 1
+        ? polymerElementCount
+        : Math.ceil(polymerElementCount / stride) + structure.units.length;
+
+    const tmpPos = Vec3.zero();
+    const positions = new Float32Array(3 * size);
+    let o = 0;
+    for (const unit of structure.units) {
         const { polymerElements } = unit.props;
-        const readPosition = unit.conformation.position;
+        const { position } = unit.conformation;
         if (polymerElements) {
-            for (let j = 0; j < polymerElements.length; j++) {
-                readPosition(polymerElements[j], tmpMatrix);
-                cAdd3(positions, tmpMatrix[0], tmpMatrix[1], tmpMatrix[2]);
+            for (let i = 0; i < polymerElements.length; i += stride) {
+                position(polymerElements[i], tmpPos);
+                Vec3.toArray(tmpPos, positions, 3 * o);
+                o++;
             }
         }
     }
-    return ChunkedArray.compact(positions) as Float32Array;
+    if (positions.length !== o) return positions.slice(0, 3 * o);
+    return positions;
 }
-export function calculateDisplacement(position: Vec3, origin: Vec3, normalDir: Vec3) {
+
+function calculateDisplacement(position: Vec3, origin: Vec3, normalDir: Vec3) {
     const A = normalDir[0];
     const B = normalDir[1];
     const C = normalDir[2];
@@ -44,104 +59,98 @@ export function calculateDisplacement(position: Vec3, origin: Vec3, normalDir: V
     return displacement;
 }
 
-export function getAxesToFlip(position: Vec3, origin: Vec3, up: Vec3, normalDir: Vec3) {
+function getAxesToFlip(position: Vec3, origin: Vec3, up: Vec3, normalDir: Vec3) {
     const toYAxis = calculateDisplacement(position, origin, normalDir);
     const toXAxis = calculateDisplacement(position, origin, up);
-    const axes: ('aroundX' | 'aroundY')[] = [];
-    if (toYAxis < 0) axes.push('aroundY');
-    if (toXAxis < 0) axes.push('aroundX');
-    return axes;
+    return {
+        aroundX: toXAxis < 0,
+        aroundY: toYAxis < 0,
+    };
 }
 
-export function getFirstResidueOrAveragePosition(structure: Structure, caPositions: Float32Array): Vec3 {
+function getFirstResidueOrAveragePosition(structure: Structure, polymerPositions: Float32Array): Vec3 {
     if (structure.units.length === 1) {
         // if only one chain => first residue coordinates
-        return Vec3.create(caPositions[0], caPositions[1], caPositions[2]);
+        return Vec3.create(polymerPositions[0], polymerPositions[1], polymerPositions[2]);
     } else {
         // if more than one chain => average of coordinates of the first chain
-        const tmpMatrixPos = Vec3.zero();
-        const atomIndices = structure.units[0].props.polymerElements;
-        const firstChainPositions = [];
-        if (atomIndices) {
-            for (let i = 0; i < atomIndices.length; i++) {
-                const coordinates = structure.units[0].conformation.position(atomIndices[i], tmpMatrixPos);
-                for (let j = 0; j < coordinates.length; j++) {
-                    firstChainPositions.push(coordinates[j]);
-                }
-            }
-            let sumX = 0;
-            let sumY = 0;
-            let sumZ = 0;
-            for (let i = 0; i < firstChainPositions.length; i += 3) {
-                sumX += firstChainPositions[i];
-                sumY += firstChainPositions[i + 1];
-                sumZ += firstChainPositions[i + 2];
+        const polymerElements = structure.units.find(u => u.props.polymerElements)?.props.polymerElements;
+        if (polymerElements?.length) {
+            const pos = Vec3.zero();
+            const center = Vec3.zero();
+            const { position } = structure.units[0].conformation;
+            for (let i = 0; i < polymerElements.length; i++) {
+                position(polymerElements[i], pos);
+                Vec3.add(center, center, pos);
             }
-            const averagePosition = Vec3.zero();
-            averagePosition[0] = sumX / atomIndices.length;
-            averagePosition[1] = sumY / atomIndices.length;
-            averagePosition[2] = sumZ / atomIndices.length;
-            return averagePosition;
+            Vec3.scale(center, center, 1 / polymerElements.length);
+            return center;
         } else {
-            return Vec3.create(caPositions[0], caPositions[1], caPositions[2]);
+            return Vec3.create(polymerPositions[0], polymerPositions[1], polymerPositions[2]);
         }
     }
-
 }
 
-export function pcaFocus(plugin: PluginContext, options: Partial<CameraFocusOptions> & { principalAxes?: PrincipalAxes, positionToFlip?: Vec3 }) {
-    if (options?.principalAxes) {
-        const { origin, dirA, dirB, dirC } = options.principalAxes.boxAxes;
-        let toFlip: ('aroundX' | 'aroundY')[] = [];
-        if (options.positionToFlip) {
-            toFlip = getAxesToFlip(options.positionToFlip, origin, dirA, dirB);
+export function pcaFocus(plugin: PluginContext, radius: number, options: { principalAxes: PrincipalAxes, positionToFlip?: Vec3 }) {
+    const { origin, dirB } = options.principalAxes.boxAxes;
+    let { dirA: up, dirC: dir } = options.principalAxes.boxAxes;
+
+    if (options.positionToFlip) {
+        const { aroundX, aroundY } = getAxesToFlip(options.positionToFlip, origin, up, dirB);
+
+        // Clone the up and dir since we will be mutating them below
+        up = Vec3.clone(up);
+        dir = Vec3.clone(dir);
+
+        if (aroundX) {
+            Vec3.negate(dir, dir);
+            Vec3.negate(up, up);
         }
-        toFlip.forEach((axis)=>{
-            if (axis === 'aroundY') {
-                Vec3.negate(dirC, dirC);
-            } else if (axis === 'aroundX') {
-                Vec3.negate(dirA, dirA);
-                Vec3.negate(dirC, dirC);
-            }
-        });
-        if (plugin.canvas3d) {
-            const position = Vec3();
-            Vec3.scaleAndAdd(position, position, origin, 100);
-            plugin.canvas3d.camera.setState({ position }, 0);
-            const deltaDistance = Vec3();
-            Vec3.negate(deltaDistance, position);
-            if (Vec3.dot(deltaDistance, dirC) <= 0) {
-                Vec3.negate(plugin.canvas3d.camera.position, position);
-            }
-            const up = Vec3.create(0, 1, 0);
-            if (Vec3.dot(up, dirA) <= 0) {
-                Vec3.negate(plugin.canvas3d?.camera.up, plugin.canvas3d.camera.up);
-            }
+        if (aroundY) {
+            Vec3.negate(dir, dir);
         }
-        return { origin, dirA, dirB, dirC };
     }
-    return {
-        origin: Vec3.zero(),
-        dirA: Vec3.zero(),
-        dirB: Vec3.zero(),
-        dirC: Vec3.zero()
-    };
+
+    if (plugin.canvas3d) {
+        const position = Vec3();
+        // NOTE: the below Vec3.scale is simplification of
+        //   Vec3.scaleAndAdd(position, position, origin, 100);
+        //   plugin.canvas3d.camera.setState({ position }, 0);
+        //   const deltaDistance = Vec3();
+        //   Vec3.negate(deltaDistance, position);
+        // from the original code.
+        Vec3.scale(position, origin, -100);
+        if (Vec3.dot(position, up) <= 0) {
+            Vec3.negate(dir, dir);
+        }
+        const upY = Vec3.create(0, 1, 0);
+        if (Vec3.dot(upY, dir) <= 0) {
+            Vec3.negate(up, up);
+        }
+    }
+
+    return plugin.canvas3d?.camera.getFocus(origin, radius, up, dir, Camera.createDefaultSnapshot());
+}
+
+export interface PCAFocusInfo {
+    principalAxes: PrincipalAxes;
+    positionToFlip: Vec3;
 }
 
-export function getPcaTransform(group: StructureComponentRef[]): { principalAxes?: PrincipalAxes, positionToFlip?: Vec3 } | undefined {
-    const polymerStructure = group[0].cell.obj?.data;
-    if (!polymerStructure) {
+export function getPcaTransform(group: StructureComponentRef[]): PCAFocusInfo | undefined {
+    const structure = group[0].cell.obj?.data;
+    if (!structure) {
         return undefined;
     }
-    if ('_pcaTransformData' in polymerStructure.currentPropertyData) {
-        return deepClone(polymerStructure.currentPropertyData._pcaTransformData);
+    if ('_pcaTransformData' in structure.currentPropertyData) {
+        return structure.currentPropertyData._pcaTransformData;
     }
-    if (!polymerStructure.units[0]?.props.polymerElements?.length) {
-        polymerStructure.currentPropertyData._pcaTransformData = undefined;
+    const positions = getPolymerPositions(structure);
+    if (!positions) {
+        structure.currentPropertyData._pcaTransformData = undefined;
         return undefined;
     }
-    const positions = getPolymerPositions(polymerStructure);
-    const positionToFlip = getFirstResidueOrAveragePosition(polymerStructure, positions);
-    polymerStructure.currentPropertyData._pcaTransformData = { principalAxes: PrincipalAxes.ofPositions(positions), positionToFlip };
-    return deepClone(polymerStructure.currentPropertyData._pcaTransformData);
+    const positionToFlip = getFirstResidueOrAveragePosition(structure, positions);
+    structure.currentPropertyData._pcaTransformData = { principalAxes: PrincipalAxes.ofPositions(positions), positionToFlip } as PCAFocusInfo;
+    return structure.currentPropertyData._pcaTransformData;
 }