diff --git a/src/mol-canvas3d/camera.ts b/src/mol-canvas3d/camera.ts
index bde9504bc6f39ddfe795d53e54b097aa6ae19fa4..5e3cbbabbf3b0402659fac398ed9723a37d56083 100644
--- a/src/mol-canvas3d/camera.ts
+++ b/src/mol-canvas3d/camera.ts
@@ -233,25 +233,36 @@ namespace Camera {
 
 const _center = Vec3.zero();
 function updateOrtho(camera: Camera) {
-    const { viewport, state: { zoom, near, far } } = camera;
+    const { viewport, state: { zoom, near, far }, viewOffset } = camera
 
-    const fullLeft = (viewport.width - viewport.x) / -2
+    const fullLeft = -(viewport.width - viewport.x) / 2
     const fullRight = (viewport.width - viewport.x) / 2
     const fullTop = (viewport.height - viewport.y) / 2
-    const fullBottom = (viewport.height - viewport.y) / -2
+    const fullBottom = -(viewport.height - viewport.y) / 2
 
     const dx = (fullRight - fullLeft) / (2 * zoom)
     const dy = (fullTop - fullBottom) / (2 * zoom)
     const cx = (fullRight + fullLeft) / 2
     const cy = (fullTop + fullBottom) / 2
 
-    const left = cx - dx
-    const right = cx + dx
-    const top = cy + dy
-    const bottom = cy - dy
+    let left = cx - dx
+    let right = cx + dx
+    let top = cy + dy
+    let bottom = cy - dy
+
+    if (viewOffset && viewOffset.enabled) {
+        const zoomW = zoom / (viewOffset.width / viewOffset.fullWidth)
+        const zoomH = zoom / (viewOffset.height / viewOffset.fullHeight)
+        const scaleW = (fullRight - fullLeft) / viewOffset.width
+        const scaleH = (fullTop - fullBottom) / viewOffset.height
+        left += scaleW * (viewOffset.offsetX / zoomW)
+        right = left + scaleW * (viewOffset.width / zoomW)
+        top -= scaleH * (viewOffset.offsetY / zoomH)
+        bottom = top - scaleH * (viewOffset.height / zoomH)
+    }
 
     // build projection matrix
-    Mat4.ortho(camera.projection, left, right, bottom, top, Math.abs(near), Math.abs(far))
+    Mat4.ortho(camera.projection, left, right, top, bottom, near, far)
 
     // build view matrix
     Vec3.add(_center, camera.position, camera.direction)
@@ -261,7 +272,7 @@ function updateOrtho(camera: Camera) {
 function updatePers(camera: Camera) {
     const aspect = camera.viewport.width / camera.viewport.height
 
-    const { state: { fov, near, far }, viewOffset } = camera;
+    const { state: { fov, near, far }, viewOffset } = camera
 
     let top = near * Math.tan(0.5 * fov)
     let height = 2 * top
diff --git a/src/mol-math/linear-algebra/3d/mat4.ts b/src/mol-math/linear-algebra/3d/mat4.ts
index ff0167e3f255fe1d1465e6991cf468aff1fa6d02..313de7f7b336a2bd2fd3787f79bdeae51583eb86 100644
--- a/src/mol-math/linear-algebra/3d/mat4.ts
+++ b/src/mol-math/linear-algebra/3d/mat4.ts
@@ -778,33 +778,7 @@ namespace Mat4 {
     }
 
     /**
-     * Generates a frustum matrix with the given bounds
-     */
-    export function frustum(out: Mat4, left: number, right: number, bottom: number, top: number, near: number, far: number) {
-        const rl = 1 / (right - left);
-        const tb = 1 / (top - bottom);
-        const nf = 1 / (near - far);
-        out[0] = (near * 2) * rl;
-        out[1] = 0;
-        out[2] = 0;
-        out[3] = 0;
-        out[4] = 0;
-        out[5] = (near * 2) * tb;
-        out[6] = 0;
-        out[7] = 0;
-        out[8] = (right + left) * rl;
-        out[9] = (top + bottom) * tb;
-        out[10] = (far + near) * nf;
-        out[11] = -1;
-        out[12] = 0;
-        out[13] = 0;
-        out[14] = (far * near * 2) * nf;
-        out[15] = 0;
-        return out;
-    }
-
-    /**
-     * Generates a perspective projection matrix with the given bounds
+     * Generates a perspective projection (frustum) matrix with the given bounds
      */
     export function perspective(out: Mat4, left: number, right: number, top: number, bottom: number, near: number, far: number) {
         const x = 2 * near / (right - left);
@@ -812,8 +786,8 @@ namespace Mat4 {
 
         const a = (right + left) / (right - left);
         const b = (top + bottom) / (top - bottom);
-        const c = - (far + near) / (far - near);
-        const d = - 2 * far * near / (far - near);
+        const c = -(far + near) / (far - near);
+        const d = -2 * far * near / (far - near);
 
         out[0] = x;
         out[1] = 0;
@@ -827,17 +801,17 @@ namespace Mat4 {
         out[9] = b;
         out[10] = c;
         out[11] = -1;
-        out[ 12 ] = 0;
-        out[ 13 ] = 0;
-        out[ 14 ] = d;
-        out[ 15 ] = 0;
+        out[12] = 0;
+        out[13] = 0;
+        out[14] = d;
+        out[15] = 0;
         return out;
     }
 
     /**
      * Generates a orthogonal projection matrix with the given bounds
      */
-    export function ortho(out: Mat4, left: number, right: number, bottom: number, top: number, near: number, far: number) {
+    export function ortho(out: Mat4, left: number, right: number, top: number, bottom: number, near: number, far: number) {
         const w = 1.0 / (right - left);
         const h = 1.0 / (top - bottom);
         const p = 1.0 / (far - near);
@@ -846,22 +820,22 @@ namespace Mat4 {
         const y = (top + bottom) * h;
         const z = (far + near) * p;
 
-        out[ 0 ] = 2 * w;
-        out[ 1 ] = 0;
-        out[ 2 ] = 0;
-        out[ 3 ] = 0;
-        out[ 4 ] = 0;
-        out[ 5 ] = 2 * h;
-        out[ 6 ] = 0;
-        out[ 7 ] = 0;
-        out[ 8 ] = 0;
-        out[ 9 ] = 0;
-        out[ 10 ] = - 2 * p;
-        out[ 11 ] = 0;
-        out[ 12 ] = - x;
-        out[ 13 ] = - y;
-        out[ 14 ] = - z;
-        out[ 15 ] = 1;
+        out[0] = 2 * w;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 0;
+        out[4] = 0;
+        out[5] = 2 * h;
+        out[6] = 0;
+        out[7] = 0;
+        out[8] = 0;
+        out[9] = 0;
+        out[10] = -2 * p;
+        out[11] = 0;
+        out[12] = -x;
+        out[13] = -y;
+        out[14] = -z;
+        out[15] = 1;
         return out;
     }