diff --git a/CHANGELOG.md b/CHANGELOG.md
index a4fa1d6befef858aa55743dbf6bff1b13005f3a6..40f8dc3e20a9ee6ead1a6af1949f13e91cf5ec14 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,8 @@ Note that since we don't clearly distinguish between a public and private interf
     - pLDDT & qmean score: coloring, repr presets, molql symbol, loci labels (including avg for mutli-residue selections)
     - pLDDT: selection query
 - Warn about erroneous symmetry operator matrix (instead of throwing an error)
+- Reduce number of created programs/shaders
+    - Support specifying variants when creating graphics render-items
 
 ## [v3.0.0-dev.5] - 2021-12-16
 
diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts
index 9f37822a7eca06deec1584d3e73b47442013105f..7ac00cc96b1a8ec89bab5ce2018e05b923e3d157 100644
--- a/src/mol-canvas3d/canvas3d.ts
+++ b/src/mol-canvas3d/canvas3d.ts
@@ -39,6 +39,7 @@ import { Helper } from './helper/helper';
 import { Passes } from './passes/passes';
 import { shallowEqual } from '../mol-util';
 import { MarkingParams } from './passes/marking';
+import { GraphicsRenderVariantsBlended, GraphicsRenderVariantsWboit } from '../mol-gl/webgl/render-item';
 
 export const Canvas3DParams = {
     camera: PD.Group({
@@ -296,7 +297,7 @@ namespace Canvas3D {
         let height = 128;
         updateViewport();
 
-        const scene = Scene.create(webgl);
+        const scene = Scene.create(webgl, passes.draw.wboitEnabled ? GraphicsRenderVariantsWboit : GraphicsRenderVariantsBlended);
 
         const camera = new Camera({
             position: Vec3.create(0, 0, 100),
diff --git a/src/mol-canvas3d/helper/bounding-sphere-helper.ts b/src/mol-canvas3d/helper/bounding-sphere-helper.ts
index aa673adef7365ce52d4f3ed8558d326136e081c5..7ccba7b621861c0f2b32afba9d1ff0bd7abfce30 100644
--- a/src/mol-canvas3d/helper/bounding-sphere-helper.ts
+++ b/src/mol-canvas3d/helper/bounding-sphere-helper.ts
@@ -18,6 +18,7 @@ import { TransformData } from '../../mol-geo/geometry/transform-data';
 import { sphereVertexCount } from '../../mol-geo/primitive/sphere';
 import { ValueCell } from '../../mol-util';
 import { Geometry } from '../../mol-geo/geometry/geometry';
+import { GraphicsRenderVariantsBlended } from '../../mol-gl/webgl/render-item';
 
 export const DebugHelperParams = {
     sceneBoundingSpheres: PD.Boolean(false, { description: 'Show full scene bounding spheres.' }),
@@ -41,7 +42,7 @@ export class BoundingSphereHelper {
     private visibleSceneData: BoundingSphereData | undefined;
 
     constructor(ctx: WebGLContext, parent: Scene, props: Partial<DebugHelperProps>) {
-        this.scene = Scene.create(ctx);
+        this.scene = Scene.create(ctx, GraphicsRenderVariantsBlended);
         this.parent = parent;
         this._props = { ...PD.getDefaultValues(DebugHelperParams), ...props };
     }
diff --git a/src/mol-canvas3d/helper/camera-helper.ts b/src/mol-canvas3d/helper/camera-helper.ts
index 6beb962a76d048f15d522d131872958b7bcba7fa..f03123903ad0afd745853437a3d571657a0bfc03 100644
--- a/src/mol-canvas3d/helper/camera-helper.ts
+++ b/src/mol-canvas3d/helper/camera-helper.ts
@@ -14,6 +14,7 @@ import { PickingId } from '../../mol-geo/geometry/picking';
 import { GraphicsRenderObject } from '../../mol-gl/render-object';
 import { Scene } from '../../mol-gl/scene';
 import { WebGLContext } from '../../mol-gl/webgl/context';
+import { GraphicsRenderVariantsBlended } from '../../mol-gl/webgl/render-item';
 import { Sphere3D } from '../../mol-math/geometry';
 import { Mat4, Vec3 } from '../../mol-math/linear-algebra';
 import { DataLoci, EmptyLoci, Loci } from '../../mol-model/loci';
@@ -58,7 +59,7 @@ export class CameraHelper {
     private renderObject: GraphicsRenderObject | undefined;
 
     constructor(private webgl: WebGLContext, props: Partial<CameraHelperProps> = {}) {
-        this.scene = Scene.create(webgl);
+        this.scene = Scene.create(webgl, GraphicsRenderVariantsBlended);
 
         this.camera = new Camera();
         Vec3.set(this.camera.up, 0, 1, 0);
@@ -201,7 +202,7 @@ function createAxesMesh(scale: number, mesh?: Mesh) {
     const x = Vec3.scale(Vec3(), Vec3.unitX, scale);
     const y = Vec3.scale(Vec3(), Vec3.unitY, scale);
     const z = Vec3.scale(Vec3(), Vec3.unitZ, scale);
-    const cylinderProps = { radiusTop: radius, radiusBottom: radius, radialSegments: 32 };
+    const cylinderProps = { radiusTop: radius, radiusBottom: radius, radialSegments: 32 };
 
     state.currentGroup = CameraHelperAxis.None;
     addSphere(state, Vec3.origin, radius, 2);
diff --git a/src/mol-canvas3d/helper/handle-helper.ts b/src/mol-canvas3d/helper/handle-helper.ts
index 303b67a1256c53af3344a1cd533b7a09836d0b52..ba8e74ae95f057c12161445bdb1499ed5db67415 100644
--- a/src/mol-canvas3d/helper/handle-helper.ts
+++ b/src/mol-canvas3d/helper/handle-helper.ts
@@ -24,6 +24,7 @@ import { DataLoci, EmptyLoci, Loci } from '../../mol-model/loci';
 import { MarkerAction, MarkerActions } from '../../mol-util/marker-action';
 import { Visual } from '../../mol-repr/visual';
 import { Interval } from '../../mol-data/int';
+import { GraphicsRenderVariantsBlended } from '../../mol-gl/webgl/render-item';
 
 const HandleParams = {
     ...Mesh.Params,
@@ -127,7 +128,7 @@ export class HandleHelper {
     }
 
     constructor(private webgl: WebGLContext, props: Partial<HandleHelperProps> = {}) {
-        this.scene = Scene.create(webgl);
+        this.scene = Scene.create(webgl, GraphicsRenderVariantsBlended);
         this.setProps(props);
     }
 }
diff --git a/src/mol-gl/render-object.ts b/src/mol-gl/render-object.ts
index 058ccb63febe472619e8dfbe9c26aefc6ad94004..730d4dfe1f203e01625593e72e28b77e62aea48b 100644
--- a/src/mol-gl/render-object.ts
+++ b/src/mol-gl/render-object.ts
@@ -16,6 +16,7 @@ import { TextValues, TextRenderable } from './renderable/text';
 import { TextureMeshValues, TextureMeshRenderable } from './renderable/texture-mesh';
 import { ImageValues, ImageRenderable } from './renderable/image';
 import { CylindersRenderable, CylindersValues } from './renderable/cylinders';
+import { GraphicsRenderVariant } from './webgl/render-item';
 
 const getNextId = idFactory(0, 0x7FFFFFFF);
 
@@ -48,17 +49,17 @@ export function createRenderObject<T extends RenderObjectType>(type: T, values:
     return { id: getNextId(), type, values, state, materialId } as GraphicsRenderObject<T>;
 }
 
-export function createRenderable<T extends RenderObjectType>(ctx: WebGLContext, o: GraphicsRenderObject<T>): Renderable<any> {
+export function createRenderable<T extends RenderObjectType>(ctx: WebGLContext, o: GraphicsRenderObject<T>, variants: GraphicsRenderVariant[]): Renderable<any> {
     switch (o.type) {
-        case 'mesh': return MeshRenderable(ctx, o.id, o.values as MeshValues, o.state, o.materialId);
-        case 'points': return PointsRenderable(ctx, o.id, o.values as PointsValues, o.state, o.materialId);
-        case 'spheres': return SpheresRenderable(ctx, o.id, o.values as SpheresValues, o.state, o.materialId);
-        case 'cylinders': return CylindersRenderable(ctx, o.id, o.values as CylindersValues, o.state, o.materialId);
-        case 'text': return TextRenderable(ctx, o.id, o.values as TextValues, o.state, o.materialId);
-        case 'lines': return LinesRenderable(ctx, o.id, o.values as LinesValues, o.state, o.materialId);
-        case 'direct-volume': return DirectVolumeRenderable(ctx, o.id, o.values as DirectVolumeValues, o.state, o.materialId);
-        case 'image': return ImageRenderable(ctx, o.id, o.values as ImageValues, o.state, o.materialId);
-        case 'texture-mesh': return TextureMeshRenderable(ctx, o.id, o.values as TextureMeshValues, o.state, o.materialId);
+        case 'mesh': return MeshRenderable(ctx, o.id, o.values as MeshValues, o.state, o.materialId, variants);
+        case 'points': return PointsRenderable(ctx, o.id, o.values as PointsValues, o.state, o.materialId, variants);
+        case 'spheres': return SpheresRenderable(ctx, o.id, o.values as SpheresValues, o.state, o.materialId, variants);
+        case 'cylinders': return CylindersRenderable(ctx, o.id, o.values as CylindersValues, o.state, o.materialId, variants);
+        case 'text': return TextRenderable(ctx, o.id, o.values as TextValues, o.state, o.materialId, variants);
+        case 'lines': return LinesRenderable(ctx, o.id, o.values as LinesValues, o.state, o.materialId, variants);
+        case 'direct-volume': return DirectVolumeRenderable(ctx, o.id, o.values as DirectVolumeValues, o.state, o.materialId, variants);
+        case 'image': return ImageRenderable(ctx, o.id, o.values as ImageValues, o.state, o.materialId, variants);
+        case 'texture-mesh': return TextureMeshRenderable(ctx, o.id, o.values as TextureMeshValues, o.state, o.materialId, variants);
     }
     throw new Error('unsupported type');
 }
diff --git a/src/mol-gl/renderable/cylinders.ts b/src/mol-gl/renderable/cylinders.ts
index 4cb175dd95a0042cb4b5a61d8941b4c0e5da2387..20c97c022520a1d4afdc2192de1dcfa5ed8faf89 100644
--- a/src/mol-gl/renderable/cylinders.ts
+++ b/src/mol-gl/renderable/cylinders.ts
@@ -6,7 +6,7 @@
 
 import { Renderable, RenderableState, createRenderable } from '../renderable';
 import { WebGLContext } from '../webgl/context';
-import { createGraphicsRenderItem } from '../webgl/render-item';
+import { createGraphicsRenderItem, GraphicsRenderVariant } from '../webgl/render-item';
 import { GlobalUniformSchema, BaseSchema, AttributeSpec, Values, InternalSchema, SizeSchema, InternalValues, ElementsSpec, ValueSpec, DefineSpec, GlobalTextureSchema, UniformSpec } from './schema';
 import { CylindersShaderCode } from '../shader-code';
 import { ValueCell } from '../../mol-util';
@@ -32,12 +32,12 @@ export const CylindersSchema = {
 export type CylindersSchema = typeof CylindersSchema
 export type CylindersValues = Values<CylindersSchema>
 
-export function CylindersRenderable(ctx: WebGLContext, id: number, values: CylindersValues, state: RenderableState, materialId: number): Renderable<CylindersValues> {
+export function CylindersRenderable(ctx: WebGLContext, id: number, values: CylindersValues, state: RenderableState, materialId: number, variants: GraphicsRenderVariant[]): Renderable<CylindersValues> {
     const schema = { ...GlobalUniformSchema, ...GlobalTextureSchema, ...InternalSchema, ...CylindersSchema };
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
     };
     const shaderCode = CylindersShaderCode;
-    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId);
+    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId, variants);
     return createRenderable(renderItem, values, state);
 }
\ No newline at end of file
diff --git a/src/mol-gl/renderable/direct-volume.ts b/src/mol-gl/renderable/direct-volume.ts
index 1c0734384123d35b85f7f2d4ba66da5b091560e8..6c9d5f1c710330096ec13694751fd4542762d8e6 100644
--- a/src/mol-gl/renderable/direct-volume.ts
+++ b/src/mol-gl/renderable/direct-volume.ts
@@ -6,7 +6,7 @@
 
 import { Renderable, RenderableState, createRenderable } from '../renderable';
 import { WebGLContext } from '../webgl/context';
-import { createGraphicsRenderItem } from '../webgl/render-item';
+import { createGraphicsRenderItem, GraphicsRenderVariant } from '../webgl/render-item';
 import { AttributeSpec, Values, UniformSpec, GlobalUniformSchema, InternalSchema, TextureSpec, ElementsSpec, DefineSpec, InternalValues, GlobalTextureSchema, BaseSchema } from './schema';
 import { DirectVolumeShaderCode } from '../shader-code';
 import { ValueCell } from '../../mol-util';
@@ -55,7 +55,7 @@ export const DirectVolumeSchema = {
 export type DirectVolumeSchema = typeof DirectVolumeSchema
 export type DirectVolumeValues = Values<DirectVolumeSchema>
 
-export function DirectVolumeRenderable(ctx: WebGLContext, id: number, values: DirectVolumeValues, state: RenderableState, materialId: number): Renderable<DirectVolumeValues> {
+export function DirectVolumeRenderable(ctx: WebGLContext, id: number, values: DirectVolumeValues, state: RenderableState, materialId: number, variants: GraphicsRenderVariant[]): Renderable<DirectVolumeValues> {
     const schema = { ...GlobalUniformSchema, ...GlobalTextureSchema, ...InternalSchema, ...DirectVolumeSchema };
     if (!ctx.isWebGL2) {
         // workaround for webgl1 limitation that loop counters need to be `const`
@@ -65,6 +65,6 @@ export function DirectVolumeRenderable(ctx: WebGLContext, id: number, values: Di
         uObjectId: ValueCell.create(id),
     };
     const shaderCode = DirectVolumeShaderCode;
-    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId);
+    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId, variants);
     return createRenderable(renderItem, values, state);
 }
\ No newline at end of file
diff --git a/src/mol-gl/renderable/image.ts b/src/mol-gl/renderable/image.ts
index 0b789080095c2f79c114cdd2bbb3fa43262e228c..ad4ee231c76cb192ae0ab4bd7eb213a18a79ba7d 100644
--- a/src/mol-gl/renderable/image.ts
+++ b/src/mol-gl/renderable/image.ts
@@ -6,7 +6,7 @@
 
 import { Renderable, RenderableState, createRenderable } from '../renderable';
 import { WebGLContext } from '../webgl/context';
-import { createGraphicsRenderItem } from '../webgl/render-item';
+import { createGraphicsRenderItem, GraphicsRenderVariant } from '../webgl/render-item';
 import { AttributeSpec, Values, GlobalUniformSchema, InternalSchema, TextureSpec, ElementsSpec, DefineSpec, InternalValues, BaseSchema, UniformSpec, GlobalTextureSchema } from './schema';
 import { ImageShaderCode } from '../shader-code';
 import { ValueCell } from '../../mol-util';
@@ -29,12 +29,12 @@ export const ImageSchema = {
 export type ImageSchema = typeof ImageSchema
 export type ImageValues = Values<ImageSchema>
 
-export function ImageRenderable(ctx: WebGLContext, id: number, values: ImageValues, state: RenderableState, materialId: number): Renderable<ImageValues> {
+export function ImageRenderable(ctx: WebGLContext, id: number, values: ImageValues, state: RenderableState, materialId: number, variants: GraphicsRenderVariant[]): Renderable<ImageValues> {
     const schema = { ...GlobalUniformSchema, ...GlobalTextureSchema, ...InternalSchema, ...ImageSchema };
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
     };
     const shaderCode = ImageShaderCode;
-    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId);
+    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId, variants);
     return createRenderable(renderItem, values, state);
 }
\ No newline at end of file
diff --git a/src/mol-gl/renderable/lines.ts b/src/mol-gl/renderable/lines.ts
index 539a9caaf590ca1f17193266ede60908dc2c0e44..ecbf96413fa0f1c7859cd68978d88f4ebeec0752 100644
--- a/src/mol-gl/renderable/lines.ts
+++ b/src/mol-gl/renderable/lines.ts
@@ -6,8 +6,7 @@
 
 import { Renderable, RenderableState, createRenderable } from '../renderable';
 import { WebGLContext } from '../webgl/context';
-import { createGraphicsRenderItem } from '../webgl/render-item';
-import { GlobalUniformSchema, BaseSchema, AttributeSpec, DefineSpec, Values, InternalSchema, SizeSchema, ElementsSpec, InternalValues, GlobalTextureSchema } from './schema';
+import { createGraphicsRenderItem, GraphicsRenderVariant } from '../webgl/render-item';
 import { ValueCell } from '../../mol-util';
 import { LinesShaderCode } from '../shader-code';
 
@@ -26,13 +25,13 @@ export const LinesSchema = {
 export type LinesSchema = typeof LinesSchema
 export type LinesValues = Values<LinesSchema>
 
-export function LinesRenderable(ctx: WebGLContext, id: number, values: LinesValues, state: RenderableState, materialId: number): Renderable<LinesValues> {
+export function LinesRenderable(ctx: WebGLContext, id: number, values: LinesValues, state: RenderableState, materialId: number, variants: GraphicsRenderVariant[]): Renderable<LinesValues> {
     const schema = { ...GlobalUniformSchema, ...GlobalTextureSchema, ...InternalSchema, ...LinesSchema };
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
     };
     const shaderCode = LinesShaderCode;
-    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId);
+    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId, variants);
 
     return createRenderable(renderItem, values, state);
 }
\ No newline at end of file
diff --git a/src/mol-gl/renderable/mesh.ts b/src/mol-gl/renderable/mesh.ts
index 4ee3a39ccdd35b8d86be16ecfb3f498ce99ebd76..83a41a40d2cfc7e8a2bdfb38047c80a666d93856 100644
--- a/src/mol-gl/renderable/mesh.ts
+++ b/src/mol-gl/renderable/mesh.ts
@@ -6,7 +6,7 @@
 
 import { Renderable, RenderableState, createRenderable } from '../renderable';
 import { WebGLContext } from '../webgl/context';
-import { createGraphicsRenderItem } from '../webgl/render-item';
+import { createGraphicsRenderItem, GraphicsRenderVariant } from '../webgl/render-item';
 import { GlobalUniformSchema, BaseSchema, AttributeSpec, ElementsSpec, DefineSpec, Values, InternalSchema, InternalValues, GlobalTextureSchema, ValueSpec, UniformSpec } from './schema';
 import { MeshShaderCode } from '../shader-code';
 import { ValueCell } from '../../mol-util';
@@ -29,13 +29,13 @@ export const MeshSchema = {
 export type MeshSchema = typeof MeshSchema
 export type MeshValues = Values<MeshSchema>
 
-export function MeshRenderable(ctx: WebGLContext, id: number, values: MeshValues, state: RenderableState, materialId: number): Renderable<MeshValues> {
+export function MeshRenderable(ctx: WebGLContext, id: number, values: MeshValues, state: RenderableState, materialId: number, variants: GraphicsRenderVariant[]): Renderable<MeshValues> {
     const schema = { ...GlobalUniformSchema, ...GlobalTextureSchema, ...InternalSchema, ...MeshSchema };
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
     };
     const shaderCode = MeshShaderCode;
-    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId);
+    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId, variants);
 
     return createRenderable(renderItem, values, state);
 }
\ No newline at end of file
diff --git a/src/mol-gl/renderable/points.ts b/src/mol-gl/renderable/points.ts
index df357394584acb67aefca1f4d0181d086bef7354..919527bfe5671702a75dc99a1abfe5c88d3a6831 100644
--- a/src/mol-gl/renderable/points.ts
+++ b/src/mol-gl/renderable/points.ts
@@ -6,7 +6,7 @@
 
 import { Renderable, RenderableState, createRenderable } from '../renderable';
 import { WebGLContext } from '../webgl/context';
-import { createGraphicsRenderItem } from '../webgl/render-item';
+import { createGraphicsRenderItem, GraphicsRenderVariant } from '../webgl/render-item';
 import { GlobalUniformSchema, BaseSchema, AttributeSpec, DefineSpec, Values, InternalSchema, SizeSchema, InternalValues, GlobalTextureSchema } from './schema';
 import { PointsShaderCode } from '../shader-code';
 import { ValueCell } from '../../mol-util';
@@ -22,12 +22,12 @@ export const PointsSchema = {
 export type PointsSchema = typeof PointsSchema
 export type PointsValues = Values<PointsSchema>
 
-export function PointsRenderable(ctx: WebGLContext, id: number, values: PointsValues, state: RenderableState, materialId: number): Renderable<PointsValues> {
+export function PointsRenderable(ctx: WebGLContext, id: number, values: PointsValues, state: RenderableState, materialId: number, variants: GraphicsRenderVariant[]): Renderable<PointsValues> {
     const schema = { ...GlobalUniformSchema, ...GlobalTextureSchema, ...InternalSchema, ...PointsSchema };
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
     };
     const shaderCode = PointsShaderCode;
-    const renderItem = createGraphicsRenderItem(ctx, 'points', shaderCode, schema, { ...values, ...internalValues }, materialId);
+    const renderItem = createGraphicsRenderItem(ctx, 'points', shaderCode, schema, { ...values, ...internalValues }, materialId, variants);
     return createRenderable(renderItem, values, state);
 }
\ No newline at end of file
diff --git a/src/mol-gl/renderable/spheres.ts b/src/mol-gl/renderable/spheres.ts
index a57943e44299d9764e45ac7a16d0276f1f4b7958..dae206ff1eab87ec32d22a2ed21feb29c5dc921b 100644
--- a/src/mol-gl/renderable/spheres.ts
+++ b/src/mol-gl/renderable/spheres.ts
@@ -6,7 +6,7 @@
 
 import { Renderable, RenderableState, createRenderable } from '../renderable';
 import { WebGLContext } from '../webgl/context';
-import { createGraphicsRenderItem } from '../webgl/render-item';
+import { createGraphicsRenderItem, GraphicsRenderVariant } from '../webgl/render-item';
 import { GlobalUniformSchema, BaseSchema, AttributeSpec, Values, InternalSchema, SizeSchema, InternalValues, ElementsSpec, ValueSpec, DefineSpec, GlobalTextureSchema, UniformSpec } from './schema';
 import { SpheresShaderCode } from '../shader-code';
 import { ValueCell } from '../../mol-util';
@@ -29,12 +29,12 @@ export const SpheresSchema = {
 export type SpheresSchema = typeof SpheresSchema
 export type SpheresValues = Values<SpheresSchema>
 
-export function SpheresRenderable(ctx: WebGLContext, id: number, values: SpheresValues, state: RenderableState, materialId: number): Renderable<SpheresValues> {
+export function SpheresRenderable(ctx: WebGLContext, id: number, values: SpheresValues, state: RenderableState, materialId: number, variants: GraphicsRenderVariant[]): Renderable<SpheresValues> {
     const schema = { ...GlobalUniformSchema, ...GlobalTextureSchema, ...InternalSchema, ...SpheresSchema };
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
     };
     const shaderCode = SpheresShaderCode;
-    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId);
+    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId, variants);
     return createRenderable(renderItem, values, state);
 }
\ No newline at end of file
diff --git a/src/mol-gl/renderable/text.ts b/src/mol-gl/renderable/text.ts
index c75fb374ef92fc58ee9c72321ece2a5a7058f7a9..8f6e145e659b8197c8e2ae17069546afb4b0e6c9 100644
--- a/src/mol-gl/renderable/text.ts
+++ b/src/mol-gl/renderable/text.ts
@@ -6,7 +6,7 @@
 
 import { Renderable, RenderableState, createRenderable } from '../renderable';
 import { WebGLContext } from '../webgl/context';
-import { createGraphicsRenderItem } from '../webgl/render-item';
+import { createGraphicsRenderItem, GraphicsRenderVariant } from '../webgl/render-item';
 import { GlobalUniformSchema, BaseSchema, AttributeSpec, UniformSpec, Values, InternalSchema, SizeSchema, InternalValues, TextureSpec, ElementsSpec, ValueSpec, GlobalTextureSchema } from './schema';
 import { TextShaderCode } from '../shader-code';
 import { ValueCell } from '../../mol-util';
@@ -35,12 +35,12 @@ export const TextSchema = {
 export type TextSchema = typeof TextSchema
 export type TextValues = Values<TextSchema>
 
-export function TextRenderable(ctx: WebGLContext, id: number, values: TextValues, state: RenderableState, materialId: number): Renderable<TextValues> {
+export function TextRenderable(ctx: WebGLContext, id: number, values: TextValues, state: RenderableState, materialId: number, variants: GraphicsRenderVariant[]): Renderable<TextValues> {
     const schema = { ...GlobalUniformSchema, ...GlobalTextureSchema, ...InternalSchema, ...TextSchema };
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
     };
     const shaderCode = TextShaderCode;
-    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId);
+    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId, variants);
     return createRenderable(renderItem, values, state);
 }
\ No newline at end of file
diff --git a/src/mol-gl/renderable/texture-mesh.ts b/src/mol-gl/renderable/texture-mesh.ts
index f4edf674b5fff12f25974ee7ba0f5ef5a5e5b459..f15bba5648762fa0206988f8835a88f26bf417f2 100644
--- a/src/mol-gl/renderable/texture-mesh.ts
+++ b/src/mol-gl/renderable/texture-mesh.ts
@@ -6,7 +6,7 @@
 
 import { Renderable, RenderableState, createRenderable } from '../renderable';
 import { WebGLContext } from '../webgl/context';
-import { createGraphicsRenderItem } from '../webgl/render-item';
+import { createGraphicsRenderItem, GraphicsRenderVariant } from '../webgl/render-item';
 import { GlobalUniformSchema, BaseSchema, DefineSpec, Values, InternalSchema, InternalValues, UniformSpec, TextureSpec, GlobalTextureSchema, ValueSpec } from './schema';
 import { MeshShaderCode } from '../shader-code';
 import { ValueCell } from '../../mol-util';
@@ -31,13 +31,13 @@ export const TextureMeshSchema = {
 export type TextureMeshSchema = typeof TextureMeshSchema
 export type TextureMeshValues = Values<TextureMeshSchema>
 
-export function TextureMeshRenderable(ctx: WebGLContext, id: number, values: TextureMeshValues, state: RenderableState, materialId: number): Renderable<TextureMeshValues> {
+export function TextureMeshRenderable(ctx: WebGLContext, id: number, values: TextureMeshValues, state: RenderableState, materialId: number, variants: GraphicsRenderVariant[]): Renderable<TextureMeshValues> {
     const schema = { ...GlobalUniformSchema, ...GlobalTextureSchema, ...InternalSchema, ...TextureMeshSchema };
     const internalValues: InternalValues = {
         uObjectId: ValueCell.create(id),
     };
     const shaderCode = MeshShaderCode;
-    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId);
+    const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId, variants);
 
     return createRenderable(renderItem, values, state);
 }
\ No newline at end of file
diff --git a/src/mol-gl/scene.ts b/src/mol-gl/scene.ts
index 94da5acefec077317bcaa212d2e41bb5572b2729..f41c9ac35e3046f565fd4053064b499f78632b41 100644
--- a/src/mol-gl/scene.ts
+++ b/src/mol-gl/scene.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 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>
@@ -15,6 +15,7 @@ import { arraySetRemove } from '../mol-util/array';
 import { BoundaryHelper } from '../mol-math/geometry/boundary-helper';
 import { hash1 } from '../mol-data/util';
 import { GraphicsRenderable } from './renderable';
+import { GraphicsRenderVariants } from './webgl/render-item';
 
 const boundaryHelper = new BoundaryHelper('98');
 
@@ -43,8 +44,8 @@ function calculateBoundingSphere(renderables: GraphicsRenderable[], boundingSphe
 }
 
 function renderableSort(a: GraphicsRenderable, b: GraphicsRenderable) {
-    const drawProgramIdA = a.getProgram('colorBlended').id;
-    const drawProgramIdB = b.getProgram('colorBlended').id;
+    const drawProgramIdA = (a.getProgram('colorBlended') || a.getProgram('colorWboit')).id;
+    const drawProgramIdB = (b.getProgram('colorBlended') || a.getProgram('colorWboit')).id;
     const materialIdA = a.materialId;
     const materialIdB = b.materialId;
 
@@ -85,7 +86,7 @@ namespace Scene {
         readonly renderables: ReadonlyArray<GraphicsRenderable>
     }
 
-    export function create(ctx: WebGLContext): Scene {
+    export function create(ctx: WebGLContext, variants = GraphicsRenderVariants): Scene {
         const renderableMap = new Map<GraphicsRenderObject, GraphicsRenderable>();
         const renderables: GraphicsRenderable[] = [];
         const boundingSphere = Sphere3D();
@@ -102,7 +103,7 @@ namespace Scene {
 
         function add(o: GraphicsRenderObject) {
             if (!renderableMap.has(o)) {
-                const renderable = createRenderable(ctx, o);
+                const renderable = createRenderable(ctx, o, variants);
                 renderables.push(renderable);
                 if (o.type === 'direct-volume') {
                     volumes.push(renderable);
diff --git a/src/mol-gl/webgl/render-item.ts b/src/mol-gl/webgl/render-item.ts
index 8a4c7660954afc1a9b2ccc89619c7cdfa081467d..3999129437d91a0716103cdaec8642b8745ed339 100644
--- a/src/mol-gl/webgl/render-item.ts
+++ b/src/mol-gl/webgl/render-item.ts
@@ -49,13 +49,15 @@ export interface RenderItem<T extends string> {
 
 //
 
-const GraphicsRenderVariant = { 'colorBlended': '', 'colorWboit': '', 'pickObject': '', 'pickInstance': '', 'pickGroup': '', 'depth': '', 'markingDepth': '', 'markingMask': '' };
+const GraphicsRenderVariant = { colorBlended: '', colorWboit: '', pickObject: '', pickInstance: '', pickGroup: '', depth: '', markingDepth: '', markingMask: '' };
 export type GraphicsRenderVariant = keyof typeof GraphicsRenderVariant
-const GraphicsRenderVariants = Object.keys(GraphicsRenderVariant) as GraphicsRenderVariant[];
+export const GraphicsRenderVariants = Object.keys(GraphicsRenderVariant) as GraphicsRenderVariant[];
+export const GraphicsRenderVariantsBlended = GraphicsRenderVariants.filter(v => v !== 'colorWboit');
+export const GraphicsRenderVariantsWboit = GraphicsRenderVariants.filter(v => v !== 'colorBlended');
 
-const ComputeRenderVariant = { 'compute': '' };
+const ComputeRenderVariant = { compute: '' };
 export type ComputeRenderVariant = keyof typeof ComputeRenderVariant
-const ComputeRenderVariants = Object.keys(ComputeRenderVariant) as ComputeRenderVariant[];
+export const ComputeRenderVariants = Object.keys(ComputeRenderVariant) as ComputeRenderVariant[];
 
 function createProgramVariant(ctx: WebGLContext, variant: string, defineValues: DefineValues, shaderCode: ShaderCode, schema: RenderableSchema) {
     defineValues = { ...defineValues, dRenderVariant: ValueCell.create(variant) };
@@ -90,8 +92,8 @@ function resetValueChanges(valueChanges: ValueChanges) {
 //
 
 export type GraphicsRenderItem = RenderItem<GraphicsRenderVariant>
-export function createGraphicsRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number) {
-    return createRenderItem(ctx, drawMode, shaderCode, schema, values, materialId, GraphicsRenderVariants);
+export function createGraphicsRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number, variants: GraphicsRenderVariant[]) {
+    return createRenderItem(ctx, drawMode, shaderCode, schema, values, materialId, variants);
 }
 
 export type ComputeRenderItem = RenderItem<ComputeRenderVariant>