diff --git a/src/mol-gl/shader-code.ts b/src/mol-gl/shader-code.ts
index 3778ba8ff85859b8e29edc6842d3b1d04d4187c9..10307aa1f6d6ba1f9ddd143ce89d5887743e5e61 100644
--- a/src/mol-gl/shader-code.ts
+++ b/src/mol-gl/shader-code.ts
@@ -6,7 +6,7 @@
 
 import { ValueCell } from 'mol-util';
 import { idFactory } from 'mol-util/id-factory';
-import { WebGLExtensions } from './webgl/context';
+import { WebGLExtensions } from './webgl/extensions';
 import { isWebGL2, GLRenderingContext } from './webgl/compat';
 
 export type DefineKind = 'boolean' | 'string' | 'number'
diff --git a/src/mol-gl/webgl/compat.ts b/src/mol-gl/webgl/compat.ts
index ed2da5c59020e868963163349595c8ef5e22098c..60a7e1cad3bca5cf6e3231fd576a924629889cef 100644
--- a/src/mol-gl/webgl/compat.ts
+++ b/src/mol-gl/webgl/compat.ts
@@ -227,7 +227,7 @@ export interface COMPAT_depth_texture {
 }
 
 export function getDepthTexture(gl: GLRenderingContext): COMPAT_depth_texture | null {
-    if(isWebGL2(gl)) {
+    if (isWebGL2(gl)) {
         return {
             UNSIGNED_INT_24_8: gl.UNSIGNED_INT_24_8
         }
diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts
index 92b32ef54ac611799bf9c73f24c0b28abfe7ebae..fa3f2d19fb8c82b48c1406518731e59c1ae8e601 100644
--- a/src/mol-gl/webgl/context.ts
+++ b/src/mol-gl/webgl/context.ts
@@ -6,10 +6,12 @@
 
 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, getDepthTexture, COMPAT_depth_texture } from './compat';
+import { GLRenderingContext, isWebGL2 } from './compat';
 import { createFramebufferCache, FramebufferCache, checkFramebufferStatus } from './framebuffer';
 import { Scheduler } from 'mol-task';
 import { isDebugMode } from 'mol-util/debug';
+import { createExtensions, WebGLExtensions } from './extensions';
+import { WebGLState, createState } from './state';
 
 export function getGLContext(canvas: HTMLCanvasElement, contextAttributes?: WebGLContextAttributes): GLRenderingContext | null {
     function getContext(contextId: 'webgl' | 'experimental-webgl' | 'webgl2') {
@@ -149,90 +151,6 @@ export function createImageData(buffer: ArrayLike<number>, width: number, height
 
 //
 
-export type WebGLExtensions = {
-    instancedArrays: COMPAT_instanced_arrays
-    standardDerivatives: COMPAT_standard_derivatives
-    blendMinMax: COMPAT_blend_minmax
-    textureFloat: COMPAT_texture_float
-    textureFloatLinear: COMPAT_texture_float_linear
-    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
-    drawBuffers: COMPAT_draw_buffers | null
-    shaderTextureLod: COMPAT_shader_texture_lod | null
-}
-
-function createExtensions(gl: GLRenderingContext): WebGLExtensions {
-    const instancedArrays = getInstancedArrays(gl)
-    if (instancedArrays === null) {
-        throw new Error('Could not find support for "instanced_arrays"')
-    }
-    const standardDerivatives = getStandardDerivatives(gl)
-    if (standardDerivatives === null) {
-        throw new Error('Could not find support for "standard_derivatives"')
-    }
-    const blendMinMax = getBlendMinMax(gl)
-    if (blendMinMax === null) {
-        throw new Error('Could not find support for "blend_minmax"')
-    }
-    const textureFloat = getTextureFloat(gl)
-    if (textureFloat === null) {
-        throw new Error('Could not find support for "texture_float"')
-    }
-    const textureFloatLinear = getTextureFloatLinear(gl)
-    if (textureFloatLinear === null) {
-        throw new Error('Could not find support for "texture_float_linear"')
-    }
-    const elementIndexUint = getElementIndexUint(gl)
-    if (elementIndexUint === null) {
-        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"')
-    }
-    const fragDepth = getFragDepth(gl)
-    if (fragDepth === null) {
-        console.log('Could not find support for "frag_depth"')
-    }
-    const colorBufferFloat = getColorBufferFloat(gl)
-    if (colorBufferFloat === null) {
-        console.log('Could not find support for "color_buffer_float"')
-    }
-    const drawBuffers = getDrawBuffers(gl)
-    if (drawBuffers === null) {
-        console.log('Could not find support for "draw_buffers"')
-    }
-    const shaderTextureLod = getShaderTextureLod(gl)
-    if (shaderTextureLod === null) {
-        console.log('Could not find support for "shader_texture_lod"')
-    }
-    
-    return {
-        instancedArrays,
-        standardDerivatives,
-        blendMinMax,
-        textureFloat,
-        textureFloatLinear,
-        elementIndexUint,
-        depthTexture,
-
-        vertexArrayObject,
-        fragDepth,
-        colorBufferFloat,
-        drawBuffers,
-        shaderTextureLod,
-    }
-}
-
 export type WebGLStats = {
     bufferCount: number
     framebufferCount: number
@@ -259,165 +177,7 @@ function createStats(): WebGLStats {
     }
 }
 
-export type WebGLState = {
-    currentProgramId: number
-    currentMaterialId: number
-    currentRenderItemId: number
-
-    /**
-     * specifies which WebGL capability to enable
-     * - `gl.BLEND`: blending of the computed fragment color values
-     * - `gl.CULL_FACE`: culling of polygons
-     * - `gl.DEPTH_TEST`: depth comparisons and updates to the depth buffer
-     * - `gl.DITHER`: dithering of color components before they get written to the color buffer
-     * - `gl.POLYGON_OFFSET_FILL`: adding an offset to depth values of polygon's fragments
-     * - `gl.SAMPLE_ALPHA_TO_COVERAGE`: computation of a temporary coverage value determined by the alpha value
-     * - `gl.SAMPLE_COVERAGE`: ANDing the fragment's coverage with the temporary coverage value
-     * - `gl.SCISSOR_TEST`: scissor test that discards fragments that are outside of the scissor rectangle
-     * - `gl.STENCIL_TEST`: stencil testing and updates to the stencil buffer
-     */
-    enable: (cap: number) => void
-    /**
-     * specifies which WebGL capability to disable
-     * - `gl.BLEND`: blending of the computed fragment color values
-     * - `gl.CULL_FACE`: culling of polygons
-     * - `gl.DEPTH_TEST`: depth comparisons and updates to the depth buffer
-     * - `gl.DITHER`: dithering of color components before they get written to the color buffer
-     * - `gl.POLYGON_OFFSET_FILL`: adding an offset to depth values of polygon's fragments
-     * - `gl.SAMPLE_ALPHA_TO_COVERAGE`: computation of a temporary coverage value determined by the alpha value
-     * - `gl.SAMPLE_COVERAGE`: ANDing the fragment's coverage with the temporary coverage value
-     * - `gl.SCISSOR_TEST`: scissor test that discards fragments that are outside of the scissor rectangle
-     * - `gl.STENCIL_TEST`: stencil testing and updates to the stencil buffer
-     */
-    disable: (cap: number) => void
-
-    /** specifies whether polygons are front- or back-facing by setting a winding orientation */
-    frontFace: (mode: number) => void
-    /** specifies whether or not front- and/or back-facing polygons can be culled */
-    cullFace: (mode: number) => void
-    /** sets whether writing into the depth buffer is enabled or disabled */
-    depthMask: (flag: boolean) => void
-    /** sets which color components to enable or to disable */
-    colorMask: (red: boolean, green: boolean, blue: boolean, alpha: boolean) => void
-    /** specifies the color values used when clearing color buffers, used when calling `gl.clear`, clamped to [0, 1] */
-    clearColor: (red: number, green: number, blue: number, alpha: number) => void
-
-    /** defines which function is used for blending pixel arithmetic */
-    blendFunc: (src: number, dst: number) => void
-    /** defines which function is used for blending pixel arithmetic for RGB and alpha components separately */
-    blendFuncSeparate: (srcRGB: number, dstRGB: number, srcAlpha: number, dstAlpha: number) => void
-
-    /** set both the RGB blend equation and alpha blend equation to a single equation, determines how a new pixel is combined with an existing */
-    blendEquation: (mode: number) => void
-    /** set the RGB blend equation and alpha blend equation separately, determines how a new pixel is combined with an existing */
-    blendEquationSeparate: (modeRGB: number, modeAlpha: number) => void
-}
-
-function createState(gl: GLRenderingContext): WebGLState {
-    const enabledCapabilities: { [k: number]: boolean } = {}
-
-    let currentFrontFace = gl.getParameter(gl.FRONT_FACE)
-    let currentCullFace = gl.getParameter(gl.CULL_FACE_MODE)
-    let currentDepthMask = gl.getParameter(gl.DEPTH_WRITEMASK)
-    let currentColorMask = gl.getParameter(gl.COLOR_WRITEMASK)
-    let currentClearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE)
-
-    let currentBlendSrcRGB = gl.getParameter(gl.BLEND_SRC_RGB)
-    let currentBlendDstRGB = gl.getParameter(gl.BLEND_DST_RGB)
-    let currentBlendSrcAlpha = gl.getParameter(gl.BLEND_SRC_ALPHA)
-    let currentBlendDstAlpha = gl.getParameter(gl.BLEND_DST_ALPHA)
-
-    let currentBlendEqRGB = gl.getParameter(gl.BLEND_EQUATION_RGB)
-    let currentBlendEqAlpha = gl.getParameter(gl.BLEND_EQUATION_ALPHA)
-
-    return {
-        currentProgramId: -1,
-        currentMaterialId: -1,
-        currentRenderItemId: -1,
-
-        enable: (cap: number) => {
-            if (enabledCapabilities[cap] !== true ) {
-                gl.enable(cap)
-                enabledCapabilities[cap] = true
-            }
-        },
-        disable: (cap: number) => {
-            if (enabledCapabilities[cap] !== false) {
-                gl.disable(cap)
-                enabledCapabilities[cap] = false
-            }
-        },
 
-        frontFace: (mode: number) => {
-            if (mode !== currentFrontFace) {
-                gl.frontFace(mode)
-                currentFrontFace = mode
-            }
-        },
-        cullFace: (mode: number) => {
-            if (mode !== currentCullFace) {
-                gl.cullFace(mode)
-                currentCullFace = mode
-            }
-        },
-        depthMask: (flag: boolean) => {
-            if (flag !== currentDepthMask) {
-                gl.depthMask(flag)
-                currentDepthMask = flag
-            }
-        },
-        colorMask: (red: boolean, green: boolean, blue: boolean, alpha: boolean) => {
-            if (red !== currentColorMask[0] || green !== currentColorMask[1] || blue !== currentColorMask[2] || alpha !== currentColorMask[3])
-            gl.colorMask(red, green, blue, alpha)
-            currentColorMask[0] = red
-            currentColorMask[1] = green
-            currentColorMask[2] = blue
-            currentColorMask[3] = alpha
-        },
-        clearColor: (red: number, green: number, blue: number, alpha: number) => {
-            if (red !== currentClearColor[0] || green !== currentClearColor[1] || blue !== currentClearColor[2] || alpha !== currentClearColor[3])
-            gl.clearColor(red, green, blue, alpha)
-            currentClearColor[0] = red
-            currentClearColor[1] = green
-            currentClearColor[2] = blue
-            currentClearColor[3] = alpha
-        },
-
-        blendFunc: (src: number, dst: number) => {
-            if (src !== currentBlendSrcRGB || dst !== currentBlendDstRGB || src !== currentBlendSrcAlpha || dst !== currentBlendDstAlpha) {
-                gl.blendFunc(src, dst)
-                currentBlendSrcRGB = src
-                currentBlendDstRGB = dst
-                currentBlendSrcAlpha = src
-                currentBlendDstAlpha = dst
-            }
-        },
-        blendFuncSeparate: (srcRGB: number, dstRGB: number, srcAlpha: number, dstAlpha: number) => {
-            if (srcRGB !== currentBlendSrcRGB || dstRGB !== currentBlendDstRGB || srcAlpha !== currentBlendSrcAlpha || dstAlpha !== currentBlendDstAlpha) {
-                gl.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha)
-                currentBlendSrcRGB = srcRGB
-                currentBlendDstRGB = dstRGB
-                currentBlendSrcAlpha = srcAlpha
-                currentBlendDstAlpha = dstAlpha
-            }
-        },
-
-        blendEquation: (mode: number) => {
-            if (mode !== currentBlendEqRGB || mode !== currentBlendEqAlpha) {
-                gl.blendEquation(mode)
-                currentBlendEqRGB = mode
-                currentBlendEqAlpha = mode
-            }
-        },
-        blendEquationSeparate: (modeRGB: number, modeAlpha: number) => {
-            if (modeRGB !== currentBlendEqRGB || modeAlpha !== currentBlendEqAlpha) {
-                gl.blendEquationSeparate(modeRGB, modeAlpha)
-                currentBlendEqRGB = modeRGB
-                currentBlendEqAlpha = modeAlpha
-            }
-        }
-    }
-}
 
 /** A WebGL context object, including the rendering context, resource caches and counts */
 export interface WebGLContext {
diff --git a/src/mol-gl/webgl/extensions.ts b/src/mol-gl/webgl/extensions.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dbc00402875c50d25ad2157828aadc5cd81f994d
--- /dev/null
+++ b/src/mol-gl/webgl/extensions.ts
@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, getVertexArrayObject, 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';
+
+export type WebGLExtensions = {
+    instancedArrays: COMPAT_instanced_arrays
+    standardDerivatives: COMPAT_standard_derivatives
+    blendMinMax: COMPAT_blend_minmax
+    textureFloat: COMPAT_texture_float
+    textureFloatLinear: COMPAT_texture_float_linear
+    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
+    drawBuffers: COMPAT_draw_buffers | null
+    shaderTextureLod: COMPAT_shader_texture_lod | null
+}
+
+export function createExtensions(gl: GLRenderingContext): WebGLExtensions {
+    const instancedArrays = getInstancedArrays(gl)
+    if (instancedArrays === null) {
+        throw new Error('Could not find support for "instanced_arrays"')
+    }
+    const standardDerivatives = getStandardDerivatives(gl)
+    if (standardDerivatives === null) {
+        throw new Error('Could not find support for "standard_derivatives"')
+    }
+    const blendMinMax = getBlendMinMax(gl)
+    if (blendMinMax === null) {
+        throw new Error('Could not find support for "blend_minmax"')
+    }
+    const textureFloat = getTextureFloat(gl)
+    if (textureFloat === null) {
+        throw new Error('Could not find support for "texture_float"')
+    }
+    const textureFloatLinear = getTextureFloatLinear(gl)
+    if (textureFloatLinear === null) {
+        throw new Error('Could not find support for "texture_float_linear"')
+    }
+    const elementIndexUint = getElementIndexUint(gl)
+    if (elementIndexUint === null) {
+        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"')
+    }
+    const fragDepth = getFragDepth(gl)
+    if (fragDepth === null) {
+        console.log('Could not find support for "frag_depth"')
+    }
+    const colorBufferFloat = getColorBufferFloat(gl)
+    if (colorBufferFloat === null) {
+        console.log('Could not find support for "color_buffer_float"')
+    }
+    const drawBuffers = getDrawBuffers(gl)
+    if (drawBuffers === null) {
+        console.log('Could not find support for "draw_buffers"')
+    }
+    const shaderTextureLod = getShaderTextureLod(gl)
+    if (shaderTextureLod === null) {
+        console.log('Could not find support for "shader_texture_lod"')
+    }
+
+    return {
+        instancedArrays,
+        standardDerivatives,
+        blendMinMax,
+        textureFloat,
+        textureFloatLinear,
+        elementIndexUint,
+        depthTexture,
+
+        vertexArrayObject,
+        fragDepth,
+        colorBufferFloat,
+        drawBuffers,
+        shaderTextureLod,
+    }
+}
\ No newline at end of file
diff --git a/src/mol-gl/webgl/program.ts b/src/mol-gl/webgl/program.ts
index 5997cc71165cb322693132650ee8412add4fe475..8d393ac7c3207c34e9082ea0084be7950f41b87c 100644
--- a/src/mol-gl/webgl/program.ts
+++ b/src/mol-gl/webgl/program.ts
@@ -5,7 +5,8 @@
  */
 
 import { ShaderCode, DefineValues, addShaderDefines } from '../shader-code'
-import { WebGLExtensions, WebGLState } from './context';
+import { WebGLState } from './state';
+import { WebGLExtensions } from './extensions';
 import { getUniformSetters, UniformsList, getUniformType } from './uniform';
 import { AttributeBuffers, getAttribType } from './buffer';
 import { TextureId, Textures } from './texture';
diff --git a/src/mol-gl/webgl/state.ts b/src/mol-gl/webgl/state.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f7a2ea4c7b518a06677170057043d1bccf4f37bf
--- /dev/null
+++ b/src/mol-gl/webgl/state.ts
@@ -0,0 +1,167 @@
+/**
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { GLRenderingContext } from './compat';
+
+export type WebGLState = {
+    currentProgramId: number
+    currentMaterialId: number
+    currentRenderItemId: number
+
+    /**
+     * specifies which WebGL capability to enable
+     * - `gl.BLEND`: blending of the computed fragment color values
+     * - `gl.CULL_FACE`: culling of polygons
+     * - `gl.DEPTH_TEST`: depth comparisons and updates to the depth buffer
+     * - `gl.DITHER`: dithering of color components before they get written to the color buffer
+     * - `gl.POLYGON_OFFSET_FILL`: adding an offset to depth values of polygon's fragments
+     * - `gl.SAMPLE_ALPHA_TO_COVERAGE`: computation of a temporary coverage value determined by the alpha value
+     * - `gl.SAMPLE_COVERAGE`: ANDing the fragment's coverage with the temporary coverage value
+     * - `gl.SCISSOR_TEST`: scissor test that discards fragments that are outside of the scissor rectangle
+     * - `gl.STENCIL_TEST`: stencil testing and updates to the stencil buffer
+     */
+    enable: (cap: number) => void
+    /**
+     * specifies which WebGL capability to disable
+     * - `gl.BLEND`: blending of the computed fragment color values
+     * - `gl.CULL_FACE`: culling of polygons
+     * - `gl.DEPTH_TEST`: depth comparisons and updates to the depth buffer
+     * - `gl.DITHER`: dithering of color components before they get written to the color buffer
+     * - `gl.POLYGON_OFFSET_FILL`: adding an offset to depth values of polygon's fragments
+     * - `gl.SAMPLE_ALPHA_TO_COVERAGE`: computation of a temporary coverage value determined by the alpha value
+     * - `gl.SAMPLE_COVERAGE`: ANDing the fragment's coverage with the temporary coverage value
+     * - `gl.SCISSOR_TEST`: scissor test that discards fragments that are outside of the scissor rectangle
+     * - `gl.STENCIL_TEST`: stencil testing and updates to the stencil buffer
+     */
+    disable: (cap: number) => void
+
+    /** specifies whether polygons are front- or back-facing by setting a winding orientation */
+    frontFace: (mode: number) => void
+    /** specifies whether or not front- and/or back-facing polygons can be culled */
+    cullFace: (mode: number) => void
+    /** sets whether writing into the depth buffer is enabled or disabled */
+    depthMask: (flag: boolean) => void
+    /** sets which color components to enable or to disable */
+    colorMask: (red: boolean, green: boolean, blue: boolean, alpha: boolean) => void
+    /** specifies the color values used when clearing color buffers, used when calling `gl.clear`, clamped to [0, 1] */
+    clearColor: (red: number, green: number, blue: number, alpha: number) => void
+
+    /** defines which function is used for blending pixel arithmetic */
+    blendFunc: (src: number, dst: number) => void
+    /** defines which function is used for blending pixel arithmetic for RGB and alpha components separately */
+    blendFuncSeparate: (srcRGB: number, dstRGB: number, srcAlpha: number, dstAlpha: number) => void
+
+    /** set both the RGB blend equation and alpha blend equation to a single equation, determines how a new pixel is combined with an existing */
+    blendEquation: (mode: number) => void
+    /** set the RGB blend equation and alpha blend equation separately, determines how a new pixel is combined with an existing */
+    blendEquationSeparate: (modeRGB: number, modeAlpha: number) => void
+}
+
+export function createState(gl: GLRenderingContext): WebGLState {
+    const enabledCapabilities: { [k: number]: boolean } = {}
+
+    let currentFrontFace = gl.getParameter(gl.FRONT_FACE)
+    let currentCullFace = gl.getParameter(gl.CULL_FACE_MODE)
+    let currentDepthMask = gl.getParameter(gl.DEPTH_WRITEMASK)
+    let currentColorMask = gl.getParameter(gl.COLOR_WRITEMASK)
+    let currentClearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE)
+
+    let currentBlendSrcRGB = gl.getParameter(gl.BLEND_SRC_RGB)
+    let currentBlendDstRGB = gl.getParameter(gl.BLEND_DST_RGB)
+    let currentBlendSrcAlpha = gl.getParameter(gl.BLEND_SRC_ALPHA)
+    let currentBlendDstAlpha = gl.getParameter(gl.BLEND_DST_ALPHA)
+
+    let currentBlendEqRGB = gl.getParameter(gl.BLEND_EQUATION_RGB)
+    let currentBlendEqAlpha = gl.getParameter(gl.BLEND_EQUATION_ALPHA)
+
+    return {
+        currentProgramId: -1,
+        currentMaterialId: -1,
+        currentRenderItemId: -1,
+
+        enable: (cap: number) => {
+            if (enabledCapabilities[cap] !== true ) {
+                gl.enable(cap)
+                enabledCapabilities[cap] = true
+            }
+        },
+        disable: (cap: number) => {
+            if (enabledCapabilities[cap] !== false) {
+                gl.disable(cap)
+                enabledCapabilities[cap] = false
+            }
+        },
+
+        frontFace: (mode: number) => {
+            if (mode !== currentFrontFace) {
+                gl.frontFace(mode)
+                currentFrontFace = mode
+            }
+        },
+        cullFace: (mode: number) => {
+            if (mode !== currentCullFace) {
+                gl.cullFace(mode)
+                currentCullFace = mode
+            }
+        },
+        depthMask: (flag: boolean) => {
+            if (flag !== currentDepthMask) {
+                gl.depthMask(flag)
+                currentDepthMask = flag
+            }
+        },
+        colorMask: (red: boolean, green: boolean, blue: boolean, alpha: boolean) => {
+            if (red !== currentColorMask[0] || green !== currentColorMask[1] || blue !== currentColorMask[2] || alpha !== currentColorMask[3])
+            gl.colorMask(red, green, blue, alpha)
+            currentColorMask[0] = red
+            currentColorMask[1] = green
+            currentColorMask[2] = blue
+            currentColorMask[3] = alpha
+        },
+        clearColor: (red: number, green: number, blue: number, alpha: number) => {
+            if (red !== currentClearColor[0] || green !== currentClearColor[1] || blue !== currentClearColor[2] || alpha !== currentClearColor[3])
+            gl.clearColor(red, green, blue, alpha)
+            currentClearColor[0] = red
+            currentClearColor[1] = green
+            currentClearColor[2] = blue
+            currentClearColor[3] = alpha
+        },
+
+        blendFunc: (src: number, dst: number) => {
+            if (src !== currentBlendSrcRGB || dst !== currentBlendDstRGB || src !== currentBlendSrcAlpha || dst !== currentBlendDstAlpha) {
+                gl.blendFunc(src, dst)
+                currentBlendSrcRGB = src
+                currentBlendDstRGB = dst
+                currentBlendSrcAlpha = src
+                currentBlendDstAlpha = dst
+            }
+        },
+        blendFuncSeparate: (srcRGB: number, dstRGB: number, srcAlpha: number, dstAlpha: number) => {
+            if (srcRGB !== currentBlendSrcRGB || dstRGB !== currentBlendDstRGB || srcAlpha !== currentBlendSrcAlpha || dstAlpha !== currentBlendDstAlpha) {
+                gl.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha)
+                currentBlendSrcRGB = srcRGB
+                currentBlendDstRGB = dstRGB
+                currentBlendSrcAlpha = srcAlpha
+                currentBlendDstAlpha = dstAlpha
+            }
+        },
+
+        blendEquation: (mode: number) => {
+            if (mode !== currentBlendEqRGB || mode !== currentBlendEqAlpha) {
+                gl.blendEquation(mode)
+                currentBlendEqRGB = mode
+                currentBlendEqAlpha = mode
+            }
+        },
+        blendEquationSeparate: (modeRGB: number, modeAlpha: number) => {
+            if (modeRGB !== currentBlendEqRGB || modeAlpha !== currentBlendEqAlpha) {
+                gl.blendEquationSeparate(modeRGB, modeAlpha)
+                currentBlendEqRGB = modeRGB
+                currentBlendEqAlpha = modeAlpha
+            }
+        }
+    }
+}
\ No newline at end of file