diff --git a/src/apps/canvas/component/viewport.tsx b/src/apps/canvas/component/viewport.tsx
index e0a5fdb780824b08e43b5a9947d97f335eda3fea..c6c6f547b6480d432581e53e215eb59351913690 100644
--- a/src/apps/canvas/component/viewport.tsx
+++ b/src/apps/canvas/component/viewport.tsx
@@ -11,7 +11,7 @@ import { EmptyLoci, Loci, areLociEqual } from 'mol-model/loci';
 import { labelFirst } from 'mol-theme/label';
 import { ButtonsType } from 'mol-util/input/input-observer';
 import { throttleTime } from 'rxjs/operators'
-import { CombinedCameraMode } from 'mol-canvas3d/camera/combined';
+import { Camera } from 'mol-canvas3d/camera';
 import { ColorParamComponent } from 'mol-app/component/parameter/color';
 import { Color } from 'mol-util/color';
 import { ParamDefinition as PD } from 'mol-util/param-definition'
@@ -24,7 +24,7 @@ interface ViewportState {
     noWebGl: boolean
     pickingInfo: string
     taskInfo: string
-    cameraMode: CombinedCameraMode
+    cameraMode: Camera.Mode
     backgroundColor: Color
 }
 
@@ -148,7 +148,7 @@ export class Viewport extends React.Component<ViewportProps, ViewportState> {
                         value={this.state.cameraMode}
                         style={{width: '150'}}
                         onChange={e => {
-                            const p = { cameraMode: e.target.value as CombinedCameraMode }
+                            const p = { cameraMode: e.target.value as Camera.Mode }
                             this.props.app.canvas3d.setProps(p)
                             this.setState(p)
                         }}
diff --git a/src/mol-canvas3d/camera.ts b/src/mol-canvas3d/camera.ts
new file mode 100644
index 0000000000000000000000000000000000000000..88027f1e5ae4d612e35125b78a2e7581aa71203b
--- /dev/null
+++ b/src/mol-canvas3d/camera.ts
@@ -0,0 +1,181 @@
+/**
+ * Copyright (c) 2018 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>
+ */
+
+import { Mat4, Vec3, Vec4 } from 'mol-math/linear-algebra'
+import { Viewport, cameraLookAt, cameraProject, cameraUnproject } from './camera/util';
+import { Object3D } from 'mol-gl/object3d';
+
+export { Camera }
+
+class Camera implements Object3D {
+    readonly view: Mat4 = Mat4.identity();
+    readonly projection: Mat4 = Mat4.identity();
+    readonly projectionView: Mat4 = Mat4.identity();
+    readonly inverseProjectionView: Mat4 = Mat4.identity();
+
+    readonly viewport: Viewport;
+    readonly state: Readonly<Camera.Snapshot> = Camera.createDefaultSnapshot();
+
+    get position() { return this.state.position; }
+    set position(v: Vec3) { Vec3.copy(this.state.position, v); }
+
+    get direction() { return this.state.direction; }
+    set direction(v: Vec3) { Vec3.copy(this.state.direction, v); }
+
+    get up() { return this.state.up; }
+    set up(v: Vec3) { Vec3.copy(this.state.up, v); }
+
+    get target() { return this.state.target; }
+    set target(v: Vec3) { Vec3.copy(this.state.target, v); }
+
+    updateMatrices() {
+        const snapshot = this.state as Camera.Snapshot;
+        const height = 2 * Math.tan(snapshot.fov / 2) * Vec3.distance(snapshot.position, snapshot.target);
+        snapshot.zoom = this.viewport.height / height;
+
+        switch (this.state.mode) {
+            case 'orthographic': updateOrtho(this); break;
+            case 'perspective': updatePers(this); break;
+            default: throw new Error('unknown camera mode');
+        }
+
+        Mat4.mul(this.projectionView, this.projection, this.view)
+        Mat4.invert(this.inverseProjectionView, this.projectionView)
+    }
+
+    setState(snapshot?: Partial<Camera.Snapshot>) {
+        Camera.copySnapshot(this.state, snapshot);
+    }
+
+    getSnapshot() {
+        const ret = Camera.createDefaultSnapshot();
+        Camera.copySnapshot(ret, this.state);
+        return ret;
+    }
+
+    lookAt(target: Vec3) {
+        cameraLookAt(this.direction, this.up, this.position, target);
+    }
+
+    translate(v: Vec3) {
+        Vec3.add(this.position, this.position, v)
+    }
+
+    project(out: Vec4, point: Vec3) {
+        return cameraProject(out, point, this.viewport, this.projectionView)
+    }
+
+    unproject(out: Vec3, point: Vec3) {
+        return cameraUnproject(out, point, this.viewport, this.inverseProjectionView)
+    }
+
+    constructor(state?: Partial<Camera.Snapshot>, viewport = Viewport.create(-1, -1, 1, 1)) {
+        this.viewport = viewport;
+        Camera.copySnapshot(this.state, state);
+    }
+
+}
+
+namespace Camera {
+    export type Mode = 'perspective' | 'orthographic'
+
+    export function createDefaultSnapshot(): Snapshot {
+        return {
+            mode: 'perspective',
+
+            position: Vec3.zero(),
+            direction: Vec3.create(0, 0, -1),
+            up: Vec3.create(0, 1, 0),
+
+            target: Vec3.create(0, 0, 0),
+
+            near: 0.1,
+            far: 10000,
+            fogNear: 0.1,
+            fogFar: 10000,
+
+            fov: Math.PI / 4,
+            zoom: 1
+        };
+    }
+
+    export interface Snapshot {
+        mode: Mode,
+
+        position: Vec3,
+        direction: Vec3,
+        up: Vec3,
+        target: Vec3,
+
+        near: number,
+        far: number,
+        fogNear: number,
+        fogFar: number,
+
+        fov: number,
+        zoom: number
+    }
+
+    export function copySnapshot(out: Snapshot, source?: Partial<Snapshot>) {
+        if (!source) return;
+
+        if (typeof source.mode !== 'undefined') out.mode = source.mode;
+
+        if (typeof source.position !== 'undefined') Vec3.copy(out.position, source.position);
+        if (typeof source.direction !== 'undefined') Vec3.copy(out.direction, source.direction);
+        if (typeof source.up !== 'undefined') Vec3.copy(out.up, source.up);
+        if (typeof source.target !== 'undefined') Vec3.copy(out.target, source.target);
+
+        if (typeof source.near !== 'undefined') out.near = source.near;
+        if (typeof source.far !== 'undefined') out.far = source.far;
+        if (typeof source.fogNear !== 'undefined') out.fogNear = source.fogNear;
+        if (typeof source.fogFar !== 'undefined') out.fogFar = source.fogFar;
+
+        if (typeof source.fov !== 'undefined') out.fov = source.fov;
+        if (typeof source.zoom !== 'undefined') out.zoom = source.zoom;
+    }
+}
+
+const _center = Vec3.zero();
+function updateOrtho(camera: Camera) {
+    const { viewport, state: { zoom, near, far } } = camera;
+
+    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 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
+
+    // build projection matrix
+    Mat4.ortho(camera.projection, left, right, bottom, top, Math.abs(near), Math.abs(far))
+
+    // build view matrix
+    Vec3.add(_center, camera.position, camera.direction)
+    Mat4.lookAt(camera.view, camera.position, _center, camera.up)
+}
+
+function updatePers(camera: Camera) {
+    const aspect = camera.viewport.width / camera.viewport.height
+
+    const { fov, near, far } = camera.state;
+
+    // build projection matrix
+    Mat4.perspective(camera.projection, fov, aspect, Math.abs(near), Math.abs(far))
+
+    // build view matrix
+    Vec3.add(_center, camera.position, camera.direction)
+    Mat4.lookAt(camera.view, camera.position, _center, camera.up)
+}
\ No newline at end of file
diff --git a/src/mol-canvas3d/camera/base.ts b/src/mol-canvas3d/camera/base.ts
deleted file mode 100644
index 3350d411fc58364279b9f644ae5a4cdf1be60092..0000000000000000000000000000000000000000
--- a/src/mol-canvas3d/camera/base.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
-
-import { Mat4, Vec3, Vec4 } from 'mol-math/linear-algebra'
-import { cameraProject, cameraUnproject, cameraLookAt, Viewport } from './util';
-import { Object3D } from 'mol-gl/object3d';
-
-export interface Camera extends Object3D {
-    readonly projection: Mat4,
-    readonly projectionView: Mat4,
-    readonly inverseProjectionView: Mat4,
-    readonly viewport: Viewport,
-
-    near: number,
-    far: number,
-    fogNear: number,
-    fogFar: number,
-}
-
-export const DefaultCameraProps = {
-    position: Vec3.zero(),
-    direction: Vec3.create(0, 0, -1),
-    up: Vec3.create(0, 1, 0),
-    viewport: Viewport.create(-1, -1, 1, 1),
-    target: Vec3.create(0, 0, 0),
-
-    near: 0.1,
-    far: 10000,
-    fogNear: 0.1,
-    fogFar: 10000,
-}
-export type CameraProps = typeof DefaultCameraProps
-
-export namespace Camera {
-    export function create(props?: Partial<CameraProps>): Camera {
-        const p = { ...DefaultCameraProps, ...props };
-
-        const { view, position, direction, up } = Object3D.create()
-        Vec3.copy(position, p.position)
-        Vec3.copy(direction, p.direction)
-        Vec3.copy(up, p.up)
-
-        const projection = Mat4.identity()
-        const viewport = Viewport.clone(p.viewport)
-        const projectionView = Mat4.identity()
-        const inverseProjectionView = Mat4.identity()
-
-        return {
-            projection,
-            projectionView,
-            inverseProjectionView,
-            viewport,
-
-            view,
-            position,
-            direction,
-            up,
-
-            near: p.near,
-            far: p.far,
-            fogNear: p.fogNear,
-            fogFar: p.fogFar,
-        }
-    }
-
-    export function update (camera: Camera) {
-        Mat4.mul(camera.projectionView, camera.projection, camera.view)
-        Mat4.invert(camera.inverseProjectionView, camera.projectionView)
-        return camera
-    }
-
-    export function lookAt (camera: Camera, target: Vec3) {
-        cameraLookAt(camera.direction, camera.up, camera.position, target)
-    }
-
-    export function reset (camera: Camera, props: CameraProps) {
-        Vec3.copy(camera.position, props.position)
-        Vec3.copy(camera.direction, props.direction)
-        Vec3.copy(camera.up, props.up)
-        Mat4.setIdentity(camera.view)
-        Mat4.setIdentity(camera.projection)
-        Mat4.setIdentity(camera.projectionView)
-        Mat4.setIdentity(camera.inverseProjectionView)
-    }
-
-    export function translate (camera: Camera, v: Vec3) {
-        Vec3.add(camera.position, camera.position, v)
-    }
-
-    export function project (camera: Camera, out: Vec4, point: Vec3) {
-        return cameraProject(out, point, camera.viewport, camera.projectionView)
-    }
-
-    export function unproject (camera: Camera, out: Vec3, point: Vec3) {
-        return cameraUnproject(out, point, camera.viewport, camera.inverseProjectionView)
-    }
-}
\ No newline at end of file
diff --git a/src/mol-canvas3d/camera/combined.ts b/src/mol-canvas3d/camera/combined.ts
deleted file mode 100644
index e0b1ed41c934f312cf2e9373c1d1ccd72f701f68..0000000000000000000000000000000000000000
--- a/src/mol-canvas3d/camera/combined.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
-
-import { PerspectiveCamera,  } from './perspective';
-import { OrthographicCamera } from './orthographic';
-import { Camera, DefaultCameraProps } from './base';
-import { Vec3 } from 'mol-math/linear-algebra';
-
-export type CombinedCameraMode = 'perspective' | 'orthographic'
-
-export interface CombinedCamera extends Camera {
-    target: Vec3
-    fov: number
-    zoom: number
-    mode: CombinedCameraMode
-}
-
-export const DefaultCombinedCameraProps = {
-    ...DefaultCameraProps,
-    target: Vec3.zero(),
-    fov: Math.PI / 4,
-    zoom: 1,
-    mode: 'perspective' as CombinedCameraMode
-}
-export type CombinedCameraProps = Partial<typeof DefaultCombinedCameraProps>
-
-export namespace CombinedCamera {
-    export function create(props: CombinedCameraProps = {}): CombinedCamera {
-        const { zoom, fov, mode, target: t } = { ...DefaultCombinedCameraProps, ...props };
-        const target = Vec3.create(t[0], t[1], t[2])
-        const camera = { ...Camera.create(props), zoom, fov, mode, target }
-        update(camera)
-
-        return camera
-    }
-
-    export function update(camera: CombinedCamera) {
-        const height = 2 * Math.tan(camera.fov / 2) * Vec3.distance(camera.position, camera.target)
-        camera.zoom = camera.viewport.height / height
-
-        switch (camera.mode) {
-            case 'orthographic': OrthographicCamera.update(camera); break
-            case 'perspective': PerspectiveCamera.update(camera); break
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/mol-canvas3d/camera/orthographic.ts b/src/mol-canvas3d/camera/orthographic.ts
deleted file mode 100644
index 26321535ff6021972f2cfda45c4004039aa3698b..0000000000000000000000000000000000000000
--- a/src/mol-canvas3d/camera/orthographic.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
-
-import { Mat4, Vec3 } from 'mol-math/linear-algebra'
-import { DefaultCameraProps, Camera } from './base'
-
-export interface OrthographicCamera extends Camera {
-    zoom: number
-}
-
-export const DefaultOrthographicCameraProps = {
-    ...DefaultCameraProps,
-    zoom: 1
-}
-export type OrthographicCameraProps = Partial<typeof DefaultOrthographicCameraProps>
-
-export namespace OrthographicCamera {
-    export function create(props: OrthographicCameraProps = {}): OrthographicCamera {
-        const { zoom } = { ...DefaultOrthographicCameraProps, ...props };
-        const camera = { ...Camera.create(props), zoom }
-        update(camera)
-
-        return camera
-    }
-
-    const center = Vec3.zero()
-    export function update(camera: OrthographicCamera) {
-        const { viewport, zoom } = camera
-
-        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 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
-
-        // build projection matrix
-        Mat4.ortho(camera.projection, left, right, bottom, top, Math.abs(camera.near), Math.abs(camera.far))
-
-        // build view matrix
-        Vec3.add(center, camera.position, camera.direction)
-        Mat4.lookAt(camera.view, camera.position, center, camera.up)
-
-        // update projection * view and invert
-        Camera.update(camera)
-    }
-}
\ No newline at end of file
diff --git a/src/mol-canvas3d/camera/perspective.ts b/src/mol-canvas3d/camera/perspective.ts
deleted file mode 100644
index b00f427aa776900974d2aec42ce4902a3dca7911..0000000000000000000000000000000000000000
--- a/src/mol-canvas3d/camera/perspective.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
-
-import { Mat4, Vec3 } from 'mol-math/linear-algebra'
-import { DefaultCameraProps, Camera } from './base'
-
-export interface PerspectiveCamera extends Camera {
-    fov: number
-}
-
-export const DefaultPerspectiveCameraProps = {
-    ...DefaultCameraProps,
-    fov: Math.PI / 4,
-}
-export type PerspectiveCameraProps = Partial<typeof DefaultPerspectiveCameraProps>
-
-export namespace PerspectiveCamera {
-    export function create(props: PerspectiveCameraProps = {}): PerspectiveCamera {
-        const { fov } = { ...DefaultPerspectiveCameraProps, ...props }
-        const camera = { ...Camera.create(props), fov }
-        update(camera)
-
-        return camera
-    }
-
-    const center = Vec3.zero()
-    export function update(camera: PerspectiveCamera) {
-        const aspect = camera.viewport.width / camera.viewport.height
-
-        // build projection matrix
-        Mat4.perspective(camera.projection, camera.fov, aspect, Math.abs(camera.near), Math.abs(camera.far))
-
-        // build view matrix
-        Vec3.add(center, camera.position, camera.direction)
-        Mat4.lookAt(camera.view, camera.position, center, camera.up)
-
-        // update projection * view and invert
-        Camera.update(camera)
-    }
-}
\ No newline at end of file
diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts
index 2f6bd0b460136e3c653cdbf485b70044475b8fbd..10e2ae36fca38cb2b92958c4ee743deef3e6cc24 100644
--- a/src/mol-canvas3d/canvas3d.ts
+++ b/src/mol-canvas3d/canvas3d.ts
@@ -24,11 +24,11 @@ import { PickingId, decodeIdRGB } from 'mol-geo/geometry/picking';
 import { MarkerAction } from 'mol-geo/geometry/marker-data';
 import { Loci, EmptyLoci, isEmptyLoci } from 'mol-model/loci';
 import { Color } from 'mol-util/color';
-import { CombinedCamera, CombinedCameraMode } from './camera/combined';
+import { Camera } from './camera';
 
 export const DefaultCanvas3DProps = {
     cameraPosition: Vec3.create(0, 0, 50),
-    cameraMode: 'perspective' as CombinedCameraMode,
+    cameraMode: 'perspective' as Camera.Mode,
     backgroundColor: Color(0x000000),
 }
 export type Canvas3DProps = typeof DefaultCanvas3DProps
@@ -60,7 +60,7 @@ interface Canvas3D {
 
     handleResize: () => void
     resetCamera: () => void
-    readonly camera: CombinedCamera
+    readonly camera: Camera
     downloadScreenshot: () => void
     getImageData: (variant: RenderVariant) => ImageData
     setProps: (props: Partial<Canvas3DProps>) => void
@@ -84,7 +84,7 @@ namespace Canvas3D {
         const didDraw = new BehaviorSubject(0)
         const input = InputObserver.create(canvas)
 
-        const camera = CombinedCamera.create({
+        const camera = new Camera({
             near: 0.1,
             far: 10000,
             position: Vec3.clone(p.cameraPosition),
@@ -188,7 +188,7 @@ namespace Canvas3D {
             }
             let didRender = false
             controls.update()
-            CombinedCamera.update(camera)
+            camera.updateMatrices();
             if (force || !Mat4.areEqual(camera.projectionView, prevProjectionView, EPSILON.Value) || !Mat4.areEqual(scene.view, prevSceneView, EPSILON.Value)) {
                 // console.log('foo', force, prevSceneView, scene.view)
                 Mat4.copy(prevProjectionView, camera.projectionView)
@@ -273,9 +273,9 @@ namespace Canvas3D {
         return {
             webgl,
 
-            center: (p: Vec3) => {
-                Vec3.set(controls.target, p[0], p[1], p[2])
-                Vec3.set(camera.target, p[0], p[1], p[2])
+            center: (target: Vec3) => {
+                // Vec3.set(controls.target, p[0], p[1], p[2])
+                camera.setState({ target })
             },
 
             hide: (repr: Representation<any>) => {
@@ -345,8 +345,8 @@ namespace Canvas3D {
             identified,
             didDraw,
             setProps: (props: Partial<Canvas3DProps>) => {
-                if (props.cameraMode !== undefined && props.cameraMode !== camera.mode) {
-                    camera.mode = props.cameraMode
+                if (props.cameraMode !== undefined && props.cameraMode !== camera.state.mode) {
+                    camera.setState({ mode: props.cameraMode })
                 }
                 if (props.backgroundColor !== undefined && props.backgroundColor !== renderer.props.clearColor) {
                     renderer.setClearColor(props.backgroundColor)
@@ -357,7 +357,7 @@ namespace Canvas3D {
             get props() {
                 return {
                     cameraPosition: Vec3.clone(camera.position),
-                    cameraMode: camera.mode,
+                    cameraMode: camera.state.mode,
                     backgroundColor: renderer.props.clearColor
                 }
             },
diff --git a/src/mol-canvas3d/controls/trackball.ts b/src/mol-canvas3d/controls/trackball.ts
index c88dda597536a9d091e70c38178f7f89fce0d80f..dc2f49ecb6280bf3570a5cd2abf0779720b27f19 100644
--- a/src/mol-canvas3d/controls/trackball.ts
+++ b/src/mol-canvas3d/controls/trackball.ts
@@ -2,6 +2,7 @@
  * Copyright (c) 2018 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>
  */
 
 /*
@@ -16,7 +17,6 @@ import { Object3D } from 'mol-gl/object3d';
 
 export const DefaultTrackballControlsProps = {
     noScroll: true,
-    target: [0, 0, 0] as Vec3,
 
     rotateSpeed: 3.0,
     zoomSpeed: 4.0,
@@ -32,7 +32,6 @@ export type TrackballControlsProps = Partial<typeof DefaultTrackballControlsProp
 
 interface TrackballControls {
     viewport: Viewport
-    target: Vec3
 
     dynamicDampingFactor: number
     rotateSpeed: number
@@ -45,11 +44,11 @@ interface TrackballControls {
 }
 
 namespace TrackballControls {
-    export function create (input: InputObserver, object: Object3D, props: TrackballControlsProps = {}): TrackballControls {
+    export function create (input: InputObserver, object: Object3D & { target: Vec3 }, props: TrackballControlsProps = {}): TrackballControls {
         const p = { ...DefaultTrackballControlsProps, ...props }
 
         const viewport: Viewport = { x: 0, y: 0, width: 0, height: 0 }
-        const target: Vec3 = Vec3.clone(p.target)
+        const target: Vec3 = object.target
 
         let { rotateSpeed, zoomSpeed, panSpeed } = p
         let { staticMoving, dynamicDampingFactor } = p
@@ -294,7 +293,7 @@ namespace TrackballControls {
 
         return {
             viewport,
-            target,
+            // target,
 
             get dynamicDampingFactor() { return dynamicDampingFactor },
             set dynamicDampingFactor(value: number ) { dynamicDampingFactor = value },
diff --git a/src/mol-gl/_spec/renderer.spec.ts b/src/mol-gl/_spec/renderer.spec.ts
index b564c9076680c2eadeb846ec3cf44a2f65e815ea..06cf3256925a27bc717b7529cb3529368bdec630 100644
--- a/src/mol-gl/_spec/renderer.spec.ts
+++ b/src/mol-gl/_spec/renderer.spec.ts
@@ -6,7 +6,7 @@
 
 import { createGl } from './gl.shim';
 
-import { PerspectiveCamera } from 'mol-canvas3d/camera/perspective';
+import { Camera } from 'mol-canvas3d/camera';
 import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { ValueCell } from 'mol-util';
 
@@ -36,7 +36,7 @@ import { Sphere3D } from 'mol-math/geometry';
 
 function createRenderer(gl: WebGLRenderingContext) {
     const ctx = createContext(gl)
-    const camera = PerspectiveCamera.create({
+    const camera = new Camera({
         near: 0.01,
         far: 10000,
         position: Vec3.create(0, 0, 50)
diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts
index 4234cc38fb50fc17c1b144e2750d4c2a28049e54..9050d0cf5e0669988e7eb6cd60dc74bd6ae21a8f 100644
--- a/src/mol-gl/renderer.ts
+++ b/src/mol-gl/renderer.ts
@@ -6,7 +6,7 @@
 
 // import { Vec3, Mat4 } from 'mol-math/linear-algebra'
 import { Viewport } from 'mol-canvas3d/camera/util';
-import { Camera } from 'mol-canvas3d/camera/base';
+import { Camera } from 'mol-canvas3d/camera';
 
 import Scene from './scene';
 import { WebGLContext, createImageData } from './webgl/context';
@@ -100,8 +100,8 @@ namespace Renderer {
             uHighlightColor: ValueCell.create(Vec3.clone(highlightColor)),
             uSelectColor: ValueCell.create(Vec3.clone(selectColor)),
 
-            uFogNear: ValueCell.create(camera.near),
-            uFogFar: ValueCell.create(camera.far / 50),
+            uFogNear: ValueCell.create(camera.state.near),
+            uFogFar: ValueCell.create(camera.state.far / 50),
             uFogColor: ValueCell.create(Vec3.clone(fogColor)),
         }
 
@@ -157,8 +157,8 @@ namespace Renderer {
             ValueCell.update(globalUniforms.uModelViewProjection, Mat4.mul(modelViewProjection, modelView, camera.projection))
             ValueCell.update(globalUniforms.uInvModelViewProjection, Mat4.invert(invModelViewProjection, modelViewProjection))
 
-            ValueCell.update(globalUniforms.uFogFar, camera.fogFar)
-            ValueCell.update(globalUniforms.uFogNear, camera.fogNear)
+            ValueCell.update(globalUniforms.uFogFar, camera.state.fogFar)
+            ValueCell.update(globalUniforms.uFogNear, camera.state.fogNear)
 
             currentProgramId = -1
 
diff --git a/src/mol-plugin/state.ts b/src/mol-plugin/state.ts
index a6892cba4e1ace0181b003bff2bad9faca577219..47981d07192234d17aa7bd13b69a23e739bd5037 100644
--- a/src/mol-plugin/state.ts
+++ b/src/mol-plugin/state.ts
@@ -6,7 +6,7 @@
 
 import { State, StateTree } from 'mol-state';
 import { PluginStateObjects as SO } from './state/objects';
-import { CombinedCamera } from 'mol-canvas3d/camera/combined';
+import { Camera } from 'mol-canvas3d/camera';
 
 export { PluginState }
 
@@ -19,7 +19,7 @@ class PluginState {
             data: this.data.getSnapshot(),
             behaviour: this.behavior.getSnapshot(),
             canvas3d: {
-                camera: { ...this.plugin.canvas3d.camera }
+                camera: this.plugin.canvas3d.camera.getSnapshot()
             }
         };
     }
@@ -27,6 +27,7 @@ class PluginState {
     async setSnapshot(snapshot: PluginState.Snapshot) {
         await this.behavior.setSnapshot(snapshot.behaviour);
         await this.data.setSnapshot(snapshot.data);
+        this.plugin.canvas3d.camera.setState(snapshot.canvas3d.camera);
 
         // TODO: handle camera
         // console.log({ old: { ...this.plugin.canvas3d.camera  }, new: snapshot.canvas3d.camera });
@@ -61,7 +62,7 @@ namespace PluginState {
         data: State.Snapshot,
         behaviour: State.Snapshot,
         canvas3d: {
-            camera: CombinedCamera
+            camera: Camera.Snapshot
         }
     }
 }