diff --git a/src/mol-gl/compute/util.ts b/src/mol-gl/compute/util.ts
index fb7f9947e7f493b1d268c72fd9af38605c333135..0508154cf2a6e5900bcdcd5202d372d5b92ca5ef 100644
--- a/src/mol-gl/compute/util.ts
+++ b/src/mol-gl/compute/util.ts
@@ -10,6 +10,7 @@ import { printTextureImage } from 'mol-gl/renderable/util';
 import { defaults, ValueCell } from 'mol-util';
 import { ValueSpec, AttributeSpec, UniformSpec, Values } from 'mol-gl/renderable/schema';
 import { Vec2 } from 'mol-math/linear-algebra';
+import { GLRenderingContext } from 'mol-gl/webgl/compat';
 
 export const QuadPositions = new Float32Array([
      1.0,  1.0,  -1.0,  1.0,  -1.0, -1.0, // First triangle
@@ -32,12 +33,21 @@ export const QuadValues: Values<typeof QuadSchema> = {
 
 //
 
+function getArrayForTexture(gl:GLRenderingContext, texture: Texture, size: number) {
+    switch (texture.type) {
+        case gl.UNSIGNED_BYTE: return new Uint8Array(size)
+        case gl.FLOAT: return new Float32Array(size)
+    }
+    throw new Error('unknown/unsupported texture type')
+}
+
 export function readTexture(ctx: WebGLContext, texture: Texture, width?: number, height?: number) {
     const { gl, framebufferCache } = ctx
     width = defaults(width, texture.width)
     height = defaults(height, texture.height)
+    const size = width * height * 4
     const framebuffer = framebufferCache.get('read-texture').value
-    const array = texture.type === gl.UNSIGNED_BYTE ? new Uint8Array(width * height * 4) : new Float32Array(width * height * 4)
+    const array = getArrayForTexture(gl, texture, size)
     framebuffer.bind()
     texture.attachFramebuffer(framebuffer, 0)
     ctx.readPixels(0, 0, width, height, array)
diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts
index 4c9a9e453dcd536a60efccbc3c7ac8a06be8411c..cdc083cdb4b2c78687f49e096411ed3b19935519 100644
--- a/src/mol-gl/renderable/schema.ts
+++ b/src/mol-gl/renderable/schema.ts
@@ -47,6 +47,7 @@ export type KindValue = {
 
     'image-uint8': TextureImage<Uint8Array>
     'image-float32': TextureImage<Float32Array>
+    'image-depth': TextureImage<Uint8Array> // TODO should be Uint32Array
     'volume-uint8': TextureVolume<Uint8Array>
     'volume-float32': TextureVolume<Float32Array>
     'texture': Texture
diff --git a/src/mol-gl/webgl/compat.ts b/src/mol-gl/webgl/compat.ts
index 9021af77e7f829228e8755fbc84d73463651c949..ed2da5c59020e868963163349595c8ef5e22098c 100644
--- a/src/mol-gl/webgl/compat.ts
+++ b/src/mol-gl/webgl/compat.ts
@@ -220,4 +220,22 @@ export interface COMPAT_shader_texture_lod {
 
 export function getShaderTextureLod(gl: GLRenderingContext): COMPAT_shader_texture_lod | null {
     return isWebGL2(gl) ? {} : gl.getExtension('EXT_shader_texture_lod')
+}
+
+export interface COMPAT_depth_texture {
+    readonly UNSIGNED_INT_24_8: number;
+}
+
+export function getDepthTexture(gl: GLRenderingContext): COMPAT_depth_texture | null {
+    if(isWebGL2(gl)) {
+        return {
+            UNSIGNED_INT_24_8: gl.UNSIGNED_INT_24_8
+        }
+    } else {
+        const ext = gl.getExtension('WEBGL_depth_texture')
+        if (ext === null) return null
+        return {
+            UNSIGNED_INT_24_8: ext.UNSIGNED_INT_24_8_WEBGL
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts
index aca8e579dcc80a93d21a5edc09af0362c5c6b3c6..d03a511bf62bc797f854d401c77d417143737552 100644
--- a/src/mol-gl/webgl/context.ts
+++ b/src/mol-gl/webgl/context.ts
@@ -6,7 +6,7 @@
 
 import { createProgramCache, ProgramCache } from './program'
 import { createShaderCache, ShaderCache } from './shader'
-import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, getVertexArrayObject, isWebGL2, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod } from './compat';
+import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, getVertexArrayObject, isWebGL2, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod, getDepthTexture, COMPAT_depth_texture } from './compat';
 import { createFramebufferCache, FramebufferCache, checkFramebufferStatus } from './framebuffer';
 import { Scheduler } from 'mol-task';
 import { isDebugMode } from 'mol-util/debug';
@@ -124,8 +124,10 @@ function readPixels(gl: GLRenderingContext, x: number, y: number, width: number,
     if (isDebugMode) checkFramebufferStatus(gl)
     if (buffer instanceof Uint8Array) {
         gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buffer)
-    } else {
+    } else if (buffer instanceof Float32Array) {
         gl.readPixels(x, y, width, height, gl.RGBA, gl.FLOAT, buffer)
+    } else {
+        throw new Error('unsupported readPixels buffer type')
     }
     if (isDebugMode) checkError(gl)
 }
@@ -153,7 +155,9 @@ export type WebGLExtensions = {
     blendMinMax: COMPAT_blend_minmax
     textureFloat: COMPAT_texture_float
     textureFloatLinear: COMPAT_texture_float_linear
-    elementIndexUint: COMPAT_element_index_uint | null
+    elementIndexUint: COMPAT_element_index_uint
+    depthTexture: COMPAT_depth_texture
+
     vertexArrayObject: COMPAT_vertex_array_object | null
     fragDepth: COMPAT_frag_depth | null
     colorBufferFloat: COMPAT_color_buffer_float | null
@@ -184,8 +188,13 @@ function createExtensions(gl: GLRenderingContext): WebGLExtensions {
     }
     const elementIndexUint = getElementIndexUint(gl)
     if (elementIndexUint === null) {
-        console.warn('Could not find support for "element_index_uint"')
+        throw new Error('Could not find support for "element_index_uint"')
+    }
+    const depthTexture = getDepthTexture(gl)
+    if (depthTexture === null) {
+        throw new Error('Could not find support for "depth_texture"')
     }
+
     const vertexArrayObject = getVertexArrayObject(gl)
     if (vertexArrayObject === null) {
         console.log('Could not find support for "vertex_array_object"')
@@ -207,7 +216,6 @@ function createExtensions(gl: GLRenderingContext): WebGLExtensions {
         console.log('Could not find support for "shader_texture_lod"')
     }
     
-
     return {
         instancedArrays,
         standardDerivatives,
@@ -215,11 +223,13 @@ function createExtensions(gl: GLRenderingContext): WebGLExtensions {
         textureFloat,
         textureFloatLinear,
         elementIndexUint,
+        depthTexture,
+
         vertexArrayObject,
         fragDepth,
         colorBufferFloat,
         drawBuffers,
-        shaderTextureLod
+        shaderTextureLod,
     }
 }
 
diff --git a/src/mol-gl/webgl/render-target.ts b/src/mol-gl/webgl/render-target.ts
index 01f623ecc8658f02fbf14b913a23a8332197929a..6dea8717017d85454f22cc4512bc9e4d289a3bd2 100644
--- a/src/mol-gl/webgl/render-target.ts
+++ b/src/mol-gl/webgl/render-target.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -7,7 +7,7 @@
 import { WebGLContext, createImageData } from './context'
 import { idFactory } from 'mol-util/id-factory';
 import { createTexture, Texture } from './texture';
-import { createFramebuffer } from './framebuffer';
+import { createFramebuffer, Framebuffer } from './framebuffer';
 import { createRenderbuffer } from './renderbuffer';
 import { TextureImage } from '../renderable/util';
 import { Mutable } from 'mol-util/type-helpers';
@@ -20,6 +20,7 @@ export interface RenderTarget {
     readonly height: number
     readonly image: TextureImage<any>
     readonly texture: Texture
+    readonly framebuffer: Framebuffer
 
     /** binds framebuffer and sets viewport to rendertarget's width and height */
     bind: () => void
@@ -30,7 +31,7 @@ export interface RenderTarget {
     destroy: () => void
 }
 
-export function createRenderTarget (ctx: WebGLContext, _width: number, _height: number): RenderTarget {
+export function createRenderTarget (ctx: WebGLContext, _width: number, _height: number, enableDepthTexture: boolean = false): RenderTarget {
     const { gl, stats } = ctx
 
     const image: Mutable<TextureImage<Uint8Array>> = {
@@ -68,6 +69,7 @@ export function createRenderTarget (ctx: WebGLContext, _width: number, _height:
         get height () { return _height },
         image,
         texture: targetTexture,
+        framebuffer,
 
         bind: () => {
             framebuffer.bind()
@@ -80,7 +82,6 @@ export function createRenderTarget (ctx: WebGLContext, _width: number, _height:
             image.width = _width
             image.height = _height
             targetTexture.load(image)
-
             depthRenderbuffer.setSize(_width, _height)
         },
         readBuffer,
diff --git a/src/mol-gl/webgl/texture.ts b/src/mol-gl/webgl/texture.ts
index 20cc12853ad6a7475e1359899da9d6757d7ad9a3..f5b7dec523ae81dfcef1ca12861228a964407d21 100644
--- a/src/mol-gl/webgl/texture.ts
+++ b/src/mol-gl/webgl/texture.ts
@@ -18,14 +18,15 @@ const getNextTextureId = idFactory()
 export type TextureKindValue = {
     'image-uint8': TextureImage<Uint8Array>
     'image-float32': TextureImage<Float32Array>
+    'image-depth': TextureImage<Uint8Array> // TODO should be Uint32Array
     'volume-uint8': TextureVolume<Uint8Array>
     'volume-float32': TextureVolume<Float32Array>
     'texture': Texture
 }
 export type TextureValueType = ValueOf<TextureKindValue>
 export type TextureKind = keyof TextureKindValue
-export type TextureType = 'ubyte' | 'float'
-export type TextureFormat = 'alpha' | 'rgb' | 'rgba'
+export type TextureType = 'ubyte' | 'ushort' | 'float'
+export type TextureFormat = 'alpha' | 'rgb' | 'rgba' | 'depth'
 /** Numbers are shortcuts for color attachment */
 export type TextureAttachment = 'depth' | 'stencil' | 'color0' | 'color1' | 'color2' | 'color3' | 'color4' | 'color5' | 'color6' | 'color7' | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
 export type TextureFilter = 'nearest' | 'linear'
@@ -35,6 +36,7 @@ export function getTarget(ctx: WebGLContext, kind: TextureKind): number {
     switch (kind) {
         case 'image-uint8': return gl.TEXTURE_2D
         case 'image-float32': return gl.TEXTURE_2D
+        case 'image-depth': return gl.TEXTURE_2D
     }
     if (isWebGL2(gl)) {
         switch (kind) {
@@ -49,10 +51,11 @@ export function getFormat(ctx: WebGLContext, format: TextureFormat, type: Textur
     const { gl } = ctx
     switch (format) {
         case 'alpha':
-            if (isWebGL2 && type === 'float') return (gl as WebGL2RenderingContext).RED
+            if (isWebGL2(gl) && type === 'float') return gl.RED
             else return gl.ALPHA
         case 'rgb': return gl.RGB
         case 'rgba': return gl.RGBA
+        case 'depth': return gl.DEPTH_COMPONENT
     }
 }
 
@@ -75,6 +78,8 @@ export function getInternalFormat(ctx: WebGLContext, format: TextureFormat, type
                     case 'ubyte': return gl.RGBA
                     case 'float': return gl.RGBA32F
                 }
+            case 'depth':
+                return gl.DEPTH_COMPONENT16
         }
     }
     return getFormat(ctx, format, type)
@@ -84,6 +89,7 @@ export function getType(ctx: WebGLContext, type: TextureType): number {
     const { gl } = ctx
     switch (type) {
         case 'ubyte': return gl.UNSIGNED_BYTE
+        case 'ushort': return gl.UNSIGNED_SHORT
         case 'float': return gl.FLOAT
     }
 }
@@ -152,7 +158,11 @@ export function createTexture(ctx: WebGLContext, kind: TextureKind, _format: Tex
     }
 
     // check texture kind and type compatability
-    if ((kind.endsWith('float32') && _type !== 'float') || kind.endsWith('uint8') && _type !== 'ubyte') {
+    if (
+        (kind.endsWith('float32') && _type !== 'float') || 
+        (kind.endsWith('uint8') && _type !== 'ubyte') || 
+        (kind.endsWith('depth') && _type !== 'ushort')
+    ) {
         throw new Error(`texture kind '${kind}' and type '${_type}' are incompatible`)
     }
 
@@ -226,19 +236,23 @@ export function createTexture(ctx: WebGLContext, kind: TextureKind, _format: Tex
         },
         attachFramebuffer: (framebuffer: Framebuffer, attachment: TextureAttachment, layer?: number) => {
             framebuffer.bind()
-            if (target === (gl as WebGL2RenderingContext).TEXTURE_3D) {
-                if (layer === undefined) throw new Error('need `layer` to attach 3D texture');
-                (gl as WebGL2RenderingContext).framebufferTextureLayer(gl.FRAMEBUFFER, getAttachment(ctx, attachment), texture, 0, layer)
-            } else {
+            if (target === gl.TEXTURE_2D) {
                 gl.framebufferTexture2D(gl.FRAMEBUFFER, getAttachment(ctx, attachment), gl.TEXTURE_2D, texture, 0)
+            } else if (isWebGL2(gl) && target === gl.TEXTURE_3D) {
+                if (layer === undefined) throw new Error('need `layer` to attach 3D texture')
+                gl.framebufferTextureLayer(gl.FRAMEBUFFER, getAttachment(ctx, attachment), texture, 0, layer)
+            } else {
+                throw new Error('unknown texture target')
             }
         },
         detachFramebuffer: (framebuffer: Framebuffer, attachment: TextureAttachment) => {
             framebuffer.bind()
-            if (target === (gl as WebGL2RenderingContext).TEXTURE_3D) {
-                (gl as WebGL2RenderingContext).framebufferTextureLayer(gl.FRAMEBUFFER, getAttachment(ctx, attachment), null, 0, 0)
-            } else {
+            if (target === gl.TEXTURE_2D) {
                 gl.framebufferTexture2D(gl.FRAMEBUFFER, getAttachment(ctx, attachment), gl.TEXTURE_2D, null, 0)
+            } else if (isWebGL2(gl) && target === gl.TEXTURE_3D) {
+                gl.framebufferTextureLayer(gl.FRAMEBUFFER, getAttachment(ctx, attachment), null, 0, 0)
+            } else {
+                throw new Error('unknown texture target')
             }
         },
         destroy: () => {