diff --git a/src/mol-canvas3d/util.ts b/src/mol-canvas3d/util.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6cae476a114ea1402357c74ed9000763c9b0b52d
--- /dev/null
+++ b/src/mol-canvas3d/util.ts
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+/** resize canvas to container element */
+export function resizeCanvas (canvas: HTMLCanvasElement, container: Element) {
+    let w = window.innerWidth
+    let h = window.innerHeight
+    if (container !== document.body) {
+        let bounds = container.getBoundingClientRect()
+        w = bounds.right - bounds.left
+        h = bounds.bottom - bounds.top
+    }
+    canvas.width = window.devicePixelRatio * w
+    canvas.height = window.devicePixelRatio * h
+    Object.assign(canvas.style, { width: `${w}px`, height: `${h}px` })
+}
\ No newline at end of file
diff --git a/src/mol-plugin/ui/viewport.tsx b/src/mol-plugin/ui/viewport.tsx
index 99263d9d012a04ffe07ddf5074049904119cdfa4..5d202a78be80008496a776e22e47345f5dfcb837 100644
--- a/src/mol-plugin/ui/viewport.tsx
+++ b/src/mol-plugin/ui/viewport.tsx
@@ -13,6 +13,7 @@ import { ParameterControls } from './controls/parameters';
 import { Canvas3DParams } from 'mol-canvas3d/canvas3d';
 import { PluginLayoutStateParams } from 'mol-plugin/layout';
 import { ControlGroup, IconButton } from './controls/common';
+import { resizeCanvas } from 'mol-canvas3d/util';
 
 interface ViewportState {
     noWebGl: boolean
@@ -91,20 +92,12 @@ export class Viewport extends PluginUIComponent<{ }, ViewportState> {
     };
 
     private handleResize = () => {
-        let w = window.innerWidth
-        let h = window.innerHeight
-        const container = this.container.current
-        const canvas = this.canvas.current
-        if (!container || !canvas) return
-        if (container !== document.body) {
-            let bounds = container.getBoundingClientRect()
-            w = bounds.right - bounds.left
-            h = bounds.bottom - bounds.top
+        const container = this.container.current;
+        const canvas = this.canvas.current;
+        if (container && canvas) {
+            resizeCanvas(canvas, container);
+            this.plugin.canvas3d.handleResize();
         }
-        canvas.width = window.devicePixelRatio * w
-        canvas.height = window.devicePixelRatio * h
-        Object.assign(canvas.style, { width: `${w}px`, height: `${h}px` })
-        this.plugin.canvas3d.handleResize();
     }
 
     componentDidMount() {
diff --git a/src/tests/browser/marching-cubes.ts b/src/tests/browser/marching-cubes.ts
index a0ab9af5be7c3cccda7fcad9bec0d2ffe4e347c7..f7009255b12658106689b4f48b6d533cc660dec6 100644
--- a/src/tests/browser/marching-cubes.ts
+++ b/src/tests/browser/marching-cubes.ts
@@ -22,15 +22,15 @@ import { createHistogramPyramid } from 'mol-gl/compute/histogram-pyramid/reducti
 import { createIsosurfaceBuffers } from 'mol-gl/compute/marching-cubes/isosurface';
 import { RendererParams } from 'mol-gl/renderer';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
+import { resizeCanvas } from 'mol-canvas3d/util';
 
 const parent = document.getElementById('app')!
 parent.style.width = '100%'
 parent.style.height = '100%'
 
 const canvas = document.createElement('canvas')
-canvas.style.width = '100%'
-canvas.style.height = '100%'
 parent.appendChild(canvas)
+resizeCanvas(canvas, parent)
 
 const canvas3d = Canvas3D.fromCanvas(canvas, {
     renderer: { ...PD.getDefaultValues(RendererParams), backgroundColor: ColorNames.white },
diff --git a/src/tests/browser/render-asa.ts b/src/tests/browser/render-asa.ts
index 0861375bddcc656aabf49aef187ea2c484b56a5d..1298dfd0615284bc940409aef5e4970e96b120ad 100644
--- a/src/tests/browser/render-asa.ts
+++ b/src/tests/browser/render-asa.ts
@@ -18,15 +18,15 @@ import { Location } from 'mol-model/location';
 import { ThemeDataContext } from 'mol-theme/theme';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { ColorListName, ColorListOptions } from 'mol-util/color/scale';
+import { resizeCanvas } from 'mol-canvas3d/util';
 
 const parent = document.getElementById('app')!
 parent.style.width = '100%'
 parent.style.height = '100%'
 
 const canvas = document.createElement('canvas')
-canvas.style.width = '100%'
-canvas.style.height = '100%'
 parent.appendChild(canvas)
+resizeCanvas(canvas, parent)
 
 const canvas3d = Canvas3D.fromCanvas(canvas)
 canvas3d.animate()
diff --git a/src/tests/browser/render-lines.ts b/src/tests/browser/render-lines.ts
index 88101aaf0e708c719ba1f67d0435ca23110627f8..64f3c64d3092e602c612c3f23c944bbc71c9f184 100644
--- a/src/tests/browser/render-lines.ts
+++ b/src/tests/browser/render-lines.ts
@@ -13,15 +13,15 @@ import { createRenderObject } from 'mol-gl/render-object';
 import { Lines } from 'mol-geo/geometry/lines/lines';
 import { LinesBuilder } from 'mol-geo/geometry/lines/lines-builder';
 import { DodecahedronCage } from 'mol-geo/primitive/dodecahedron';
+import { resizeCanvas } from 'mol-canvas3d/util';
 
 const parent = document.getElementById('app')!
 parent.style.width = '100%'
 parent.style.height = '100%'
 
 const canvas = document.createElement('canvas')
-canvas.style.width = '100%'
-canvas.style.height = '100%'
 parent.appendChild(canvas)
+resizeCanvas(canvas, parent)
 
 const canvas3d = Canvas3D.fromCanvas(canvas)
 canvas3d.animate()
diff --git a/src/tests/browser/render-mesh.ts b/src/tests/browser/render-mesh.ts
index e87e73ca2253eeb05c060e5a5c9e0482343db9ab..c3dd5cb7c4db892949f4ebe179080913c28c135b 100644
--- a/src/tests/browser/render-mesh.ts
+++ b/src/tests/browser/render-mesh.ts
@@ -14,15 +14,15 @@ import { Color } from 'mol-util/color';
 import { createRenderObject } from 'mol-gl/render-object';
 import { SpikedBall } from 'mol-geo/primitive/spiked-ball';
 import { HexagonalPrismCage } from 'mol-geo/primitive/prism';
+import { resizeCanvas } from 'mol-canvas3d/util';
 
 const parent = document.getElementById('app')!
 parent.style.width = '100%'
 parent.style.height = '100%'
 
 const canvas = document.createElement('canvas')
-canvas.style.width = '100%'
-canvas.style.height = '100%'
 parent.appendChild(canvas)
+resizeCanvas(canvas, parent)
 
 const canvas3d = Canvas3D.fromCanvas(canvas)
 canvas3d.animate()
diff --git a/src/tests/browser/render-shape.ts b/src/tests/browser/render-shape.ts
index 92d25ca7b776a39f384d572f4d0af2d3576ed1b5..ff35b9808af0da76b763e17bff50af9a24305fbb 100644
--- a/src/tests/browser/render-shape.ts
+++ b/src/tests/browser/render-shape.ts
@@ -18,15 +18,15 @@ import { RuntimeContext, Progress } from 'mol-task';
 import { Representation } from 'mol-repr/representation';
 import { MarkerAction } from 'mol-geo/geometry/marker-data';
 import { EveryLoci } from 'mol-model/loci';
+import { resizeCanvas } from 'mol-canvas3d/util';
 
 const parent = document.getElementById('app')!
 parent.style.width = '100%'
 parent.style.height = '100%'
 
 const canvas = document.createElement('canvas')
-canvas.style.width = '100%'
-canvas.style.height = '100%'
 parent.appendChild(canvas)
+resizeCanvas(canvas, parent)
 
 const info = document.createElement('div')
 info.style.position = 'absolute'
diff --git a/src/tests/browser/render-spheres.ts b/src/tests/browser/render-spheres.ts
index f4799885669a0837a7c88b9d3877d0db5265335f..7b6f723f5692e69a6914127d58d50f037c685da0 100644
--- a/src/tests/browser/render-spheres.ts
+++ b/src/tests/browser/render-spheres.ts
@@ -11,15 +11,15 @@ import { Representation } from 'mol-repr/representation';
 import { Spheres } from 'mol-geo/geometry/spheres/spheres';
 import { Color } from 'mol-util/color';
 import { createRenderObject } from 'mol-gl/render-object';
+import { resizeCanvas } from 'mol-canvas3d/util';
 
 const parent = document.getElementById('app')!
 parent.style.width = '100%'
 parent.style.height = '100%'
 
 const canvas = document.createElement('canvas')
-canvas.style.width = '100%'
-canvas.style.height = '100%'
 parent.appendChild(canvas)
+resizeCanvas(canvas, parent)
 
 const canvas3d = Canvas3D.fromCanvas(canvas)
 canvas3d.animate()
diff --git a/src/tests/browser/render-structure.ts b/src/tests/browser/render-structure.ts
index 468bd73d46a6cbf077b6ce54c2152a6c129599be..0ea0fffd15d8d22353bea0849e1f4c86bed29960 100644
--- a/src/tests/browser/render-structure.ts
+++ b/src/tests/browser/render-structure.ts
@@ -16,15 +16,15 @@ import { MolecularSurfaceRepresentationProvider } from 'mol-repr/structure/repre
 import { BallAndStickRepresentationProvider } from 'mol-repr/structure/representation/ball-and-stick';
 import { GaussianSurfaceRepresentationProvider } from 'mol-repr/structure/representation/gaussian-surface';
 import { ComputedSecondaryStructure } from 'mol-model-props/computed/secondary-structure';
+import { resizeCanvas } from 'mol-canvas3d/util';
 
 const parent = document.getElementById('app')!
 parent.style.width = '100%'
 parent.style.height = '100%'
 
 const canvas = document.createElement('canvas')
-canvas.style.width = '100%'
-canvas.style.height = '100%'
 parent.appendChild(canvas)
+resizeCanvas(canvas, parent)
 
 const canvas3d = Canvas3D.fromCanvas(canvas)
 canvas3d.animate()
diff --git a/src/tests/browser/render-text.ts b/src/tests/browser/render-text.ts
index 7e5ee328432ffaf2c41c5aa00868326c985672ee..8a158ce42e7f1a05ea9748242d4ea012a9fcbb5c 100644
--- a/src/tests/browser/render-text.ts
+++ b/src/tests/browser/render-text.ts
@@ -14,15 +14,15 @@ import { Representation } from 'mol-repr/representation';
 import { SpheresBuilder } from 'mol-geo/geometry/spheres/spheres-builder';
 import { createRenderObject } from 'mol-gl/render-object';
 import { Spheres } from 'mol-geo/geometry/spheres/spheres';
+import { resizeCanvas } from 'mol-canvas3d/util';
 
 const parent = document.getElementById('app')!
 parent.style.width = '100%'
 parent.style.height = '100%'
 
 const canvas = document.createElement('canvas')
-canvas.style.width = '100%'
-canvas.style.height = '100%'
 parent.appendChild(canvas)
+resizeCanvas(canvas, parent)
 
 const canvas3d = Canvas3D.fromCanvas(canvas)
 canvas3d.animate()