diff --git a/CHANGELOG.md b/CHANGELOG.md
index 00c3832802a6d3940ab047c27a305ff1c61bf228..13eced13ac23a0834e0ea19c5f3e6dd52f86be8b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@ Note that since we don't clearly distinguish between a public and private interf
 
 - Add ``bumpiness`` (per-object and per-group), ``bumpFrequency`` & ``bumpAmplitude`` (per-object) render parameters (#299)
 - Change ``label`` representation defaults: Use text border instead of rectangle background.
+- Add outline color option to renderer
 
 ## [v3.0.0-dev.3] - 2021-12-4
 
diff --git a/src/apps/docking-viewer/viewport.tsx b/src/apps/docking-viewer/viewport.tsx
index 082c59dd612c870c593636f3d8ab1b73cd7181ef..6be977980e1461ccd38a7335c6a7e1dc6083a65f 100644
--- a/src/apps/docking-viewer/viewport.tsx
+++ b/src/apps/docking-viewer/viewport.tsx
@@ -51,7 +51,8 @@ function occlusionStyle(plugin: PluginContext) {
             } },
             outline: { name: 'on', params: {
                 scale: 1.0,
-                threshold: 0.33
+                threshold: 0.33,
+                color: Color(0x0000),
             } }
         }
     } });
diff --git a/src/examples/lighting/index.ts b/src/examples/lighting/index.ts
index 6bc693ccc872c2b0dc0cdf05bcb0c45812909b2f..9537ba66750b19647b517652112d9e5902839200 100644
--- a/src/examples/lighting/index.ts
+++ b/src/examples/lighting/index.ts
@@ -11,6 +11,7 @@ import { PluginUIContext } from '../../mol-plugin-ui/context';
 import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
 import { PluginCommands } from '../../mol-plugin/commands';
 import { Asset } from '../../mol-util/assets';
+import { Color } from '../../mol-util/color';
 import './index.html';
 require('mol-plugin-ui/skin/light.scss');
 
@@ -26,7 +27,7 @@ const Canvas3DPresets = {
         },
         postprocessing: {
             occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
-            outline: { name: 'on', params: { scale: 1, threshold: 0.1 } }
+            outline: { name: 'on', params: { scale: 1, threshold: 0.1, color: Color(0x000000) } }
         },
         renderer: {
             style: { name: 'flat', params: {} }
diff --git a/src/mol-canvas3d/passes/postprocessing.ts b/src/mol-canvas3d/passes/postprocessing.ts
index 83697524173dc15bcfb4a76b27c0fd36a81ca747..5f013e24811d62a5956a463d8700ad252fec3413 100644
--- a/src/mol-canvas3d/passes/postprocessing.ts
+++ b/src/mol-canvas3d/passes/postprocessing.ts
@@ -193,6 +193,7 @@ const PostprocessingSchema = {
     uFogNear: UniformSpec('f'),
     uFogFar: UniformSpec('f'),
     uFogColor: UniformSpec('v3'),
+    uOutlineColor: UniformSpec('v3'),
     uTransparentBackground: UniformSpec('b'),
 
     uMaxPossibleViewZDiff: UniformSpec('f'),
@@ -220,6 +221,7 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
         uFogNear: ValueCell.create(10000),
         uFogFar: ValueCell.create(10000),
         uFogColor: ValueCell.create(Vec3.create(1, 1, 1)),
+        uOutlineColor: ValueCell.create(Vec3.create(0, 0, 0)),
         uTransparentBackground: ValueCell.create(false),
 
         uMaxPossibleViewZDiff: ValueCell.create(0.5),
@@ -252,6 +254,7 @@ export const PostprocessingParams = {
         on: PD.Group({
             scale: PD.Numeric(1, { min: 1, max: 5, step: 1 }),
             threshold: PD.Numeric(0.33, { min: 0.01, max: 1, step: 0.01 }),
+            color: PD.Color(Color(0x000000)),
         }),
         off: PD.Group({})
     }, { cycle: true, description: 'Draw outline around 3D objects' }),
@@ -446,6 +449,8 @@ export class PostprocessingPass {
             ValueCell.updateIfChanged(this.outlinesRenderable.values.uFar, camera.far);
             ValueCell.updateIfChanged(this.outlinesRenderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff);
 
+            ValueCell.update(this.renderable.values.uOutlineColor, Color.toVec3Normalized(this.renderable.values.uOutlineColor.ref.value, props.outline.params.color));
+
             ValueCell.updateIfChanged(this.renderable.values.uMaxPossibleViewZDiff, maxPossibleViewZDiff);
             if (this.renderable.values.dOutlineScale.ref.value !== outlineScale) { needsUpdateMain = true; }
             ValueCell.updateIfChanged(this.renderable.values.dOutlineScale, outlineScale);
diff --git a/src/mol-gl/shader/postprocessing.frag.ts b/src/mol-gl/shader/postprocessing.frag.ts
index 8bb6b78c11a9997babf47fdbb8cc0748cd3aabe1..9a50f414352179a0f5e3da916ea961020628f650 100644
--- a/src/mol-gl/shader/postprocessing.frag.ts
+++ b/src/mol-gl/shader/postprocessing.frag.ts
@@ -21,6 +21,7 @@ uniform float uFar;
 uniform float uFogNear;
 uniform float uFogFar;
 uniform vec3 uFogColor;
+uniform vec3 uOutlineColor;
 uniform bool uTransparentBackground;
 
 uniform float uOcclusionBias;
@@ -116,7 +117,7 @@ void main(void) {
         float outline = getOutline(coords, closestTexel);
 
         if (outline == 0.0) {
-            color.rgb *= outline;
+            color.rgb = mix(uOutlineColor, color.rgb, outline);
             viewDist = abs(getViewZ(closestTexel));
             fogFactor = smoothstep(uFogNear, uFogFar, viewDist);
             if (!uTransparentBackground) {