diff --git a/src/Drawable.js b/src/Drawable.js
index 2bab1ded..532af120 100644
--- a/src/Drawable.js
+++ b/src/Drawable.js
@@ -119,8 +119,20 @@ Drawable.EFFECTS = Object.keys(Drawable._effectConverter);
  * @enum {string}
  */
 Drawable.DRAW_MODE = {
+    /**
+     * Draw normally.
+     */
     default: 'default',
-    pick: 'pick'
+
+    /**
+     * Draw the Drawable's silhouette using a particular color.
+     */
+    silhouette: 'silhouette',
+
+    /**
+     * Draw only the parts of the drawable which match a particular color.
+     */
+    colorMask: 'colorMask'
 };
 
 /**
@@ -238,7 +250,7 @@ Drawable.prototype._useSkin = function(
 /**
  * Fetch the shader for this Drawable's set of active effects.
  * Build the shader if necessary.
- * @param {Drawable.DRAW_MODE} drawMode Draw normally or for picking, etc.
+ * @param {Drawable.DRAW_MODE} drawMode Draw normally, silhouette, etc.
  * @returns {module:twgl.ProgramInfo?} The shader's program info.
  */
 Drawable.prototype.getShader = function (drawMode) {
@@ -255,7 +267,7 @@ Drawable.prototype.getShader = function (drawMode) {
 
 /**
  * Build the shader for this Drawable's set of active effects.
- * @param {Drawable.DRAW_MODE} drawMode Draw normally or for picking, etc.
+ * @param {Drawable.DRAW_MODE} drawMode Draw normally, silhouette, etc.
  * @returns {module:twgl.ProgramInfo?} The new shader's program info.
  * @private
  */
diff --git a/src/RenderWebGL.js b/src/RenderWebGL.js
index 73753894..31753b6d 100644
--- a/src/RenderWebGL.js
+++ b/src/RenderWebGL.js
@@ -128,13 +128,14 @@ RenderWebGL.prototype.draw = function () {
 /**
  * Draw all Drawables, with the possible exception of
  * @param {int[]} drawables The Drawable IDs to draw, possibly this._drawables.
- * @param {Drawable.DRAW_MODE} drawMode Draw normally or for picking, etc.
+ * @param {Drawable.DRAW_MODE} drawMode Draw normally, silhouette, etc.
  * @param {module:twgl/m4.Mat4} projection The projection matrix to use.
  * @param {Drawable~idFilterFunc} [filter] An optional filter function.
+ * @param {Object.<string,*>} [extraUniforms] Extra uniforms for the shaders.
  * @private
  */
 RenderWebGL.prototype._drawThese = function(
-    drawables, drawMode, projection, filter) {
+    drawables, drawMode, projection, filter, extraUniforms) {
 
     var gl = this._gl;
     var currentShader = null;
@@ -156,14 +157,20 @@ RenderWebGL.prototype._drawThese = function(
             twgl.setBuffersAndAttributes(gl, currentShader, this._bufferInfo);
             twgl.setUniforms(currentShader, {u_projectionMatrix: projection});
             twgl.setUniforms(currentShader, {u_fudge: window.fudge || 0});
+
+            // TODO: should these be set after the Drawable's uniforms?
+            // That would allow Drawable-scope uniforms to be overridden...
+            if (extraUniforms) {
+                twgl.setUniforms(currentShader, extraUniforms);
+            }
         }
 
         twgl.setUniforms(currentShader, drawable.getUniforms());
 
-        // TODO: consider moving u_pickColor into Drawable's getUniforms()...
-        if (drawMode == Drawable.DRAW_MODE.pick) {
+        // TODO: move u_silhouetteColor into Drawable's getUniforms()
+        if (drawMode == Drawable.DRAW_MODE.silhouette) {
             twgl.setUniforms(currentShader,
-                {u_pickColor: Drawable.color4fFromID(drawableID)});
+                {u_silhouetteColor: Drawable.color4fFromID(drawableID)});
         }
 
         twgl.drawBufferInfo(gl, gl.TRIANGLES, this._bufferInfo);
@@ -329,7 +336,7 @@ RenderWebGL.prototype.pick = function (
     var projection = twgl.m4.ortho(
         pickLeft, pickRight, pickTop, pickBottom, -1, 1);
 
-    this._drawThese(candidateIDs, Drawable.DRAW_MODE.pick, projection);
+    this._drawThese(candidateIDs, Drawable.DRAW_MODE.silhouette, projection);
 
     var pixels = new Buffer(touchWidth * touchHeight * 4);
     gl.readPixels(
@@ -371,7 +378,15 @@ RenderWebGL.prototype.pick = function (
     return hit | 0;
 };
 
-RenderWebGL.prototype.isTouchingColor = function(drawableID, color3ub) {
+/**
+ * Check if a particular Drawable is touching a particular color.
+ * @param {int} drawableID The ID of the Drawable to check.
+ * @param {int[]} color3ub Test if the Drawable is touching this color.
+ * @param {float[]} [mask3f] Optionally mask the check to this part of Drawable.
+ * @returns {boolean} True iff the Drawable is touching the color.
+ */
+RenderWebGL.prototype.isTouchingColor = function(drawableID, color3ub, mask3f) {
+
     var gl = this._gl;
 
     twgl.bindFramebufferInfo(gl, this._queryBufferInfo);
@@ -385,13 +400,26 @@ RenderWebGL.prototype.isTouchingColor = function(drawableID, color3ub) {
     gl.clearColor.apply(gl, this._backgroundColor);
     gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
 
+    var extraUniforms;
+    if (mask3f) {
+        extraUniforms = {
+            u_colorMask: mask3f,
+            u_colorMaskTolerance: 1 / 255
+        };
+    }
+
     try {
         gl.enable(gl.STENCIL_TEST);
         gl.stencilFunc(gl.ALWAYS, 1, 1);
         gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
         gl.colorMask(false, false, false, false);
         this._drawThese(
-            [drawableID], Drawable.DRAW_MODE.pick, this._projection);
+            [drawableID],
+            mask3f ?
+                Drawable.DRAW_MODE.colorMask : Drawable.DRAW_MODE.silhouette,
+            this._projection,
+            undefined,
+            extraUniforms);
 
         gl.stencilFunc(gl.EQUAL, 1, 1);
         gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
@@ -432,6 +460,7 @@ RenderWebGL.prototype.isTouchingColor = function(drawableID, color3ub) {
 
     for (var pixelBase = 0; pixelBase < pixels.length; pixelBase += 4) {
         // TODO: tolerance?
+        // TODO: use u_colorMask to make this test something like "pixel != 0"
         if ((pixels[pixelBase] == color3ub[0]) &&
             (pixels[pixelBase + 1] == color3ub[1]) &&
             (pixels[pixelBase + 2] == color3ub[2])) {
diff --git a/src/shaders/sprite.frag b/src/shaders/sprite.frag
index f2ac62e7..4c901e2a 100644
--- a/src/shaders/sprite.frag
+++ b/src/shaders/sprite.frag
@@ -2,16 +2,21 @@ precision mediump float;
 
 uniform float u_fudge;
 
-#ifdef DRAW_MODE_pick
-uniform vec4 u_pickColor;
-#else // DRAW_MODE_pick
+#ifdef DRAW_MODE_silhouette
+uniform vec4 u_silhouetteColor;
+#else // DRAW_MODE_silhouette
 # ifdef ENABLE_color
 uniform float u_color;
 # endif // ENABLE_color
 # ifdef ENABLE_brightness
 uniform float u_brightness;
 # endif // ENABLE_brightness
-#endif // DRAW_MODE_pick
+#endif // DRAW_MODE_silhouette
+
+#ifdef DRAW_MODE_colorMask
+uniform vec3 u_colorMask;
+uniform float u_colorMaskTolerance;
+#endif // DRAW_MODE_colorMask
 
 #ifdef ENABLE_fisheye
 uniform float u_fisheye;
@@ -34,7 +39,7 @@ uniform sampler2D u_skin;
 
 varying vec2 v_texCoord;
 
-#if !defined(DRAW_MODE_pick) && (defined(ENABLE_color) || defined(ENABLE_brightness))
+#if !defined(DRAW_MODE_silhouette) && (defined(ENABLE_color) || defined(ENABLE_brightness))
 // Branchless color conversions based on code from:
 // http://www.chilliant.com/rgb2hsv.html by Ian Taylor
 // Based in part on work by Sam Hocevar and Emil Persson
@@ -72,7 +77,7 @@ vec3 convertHSL2RGB(vec3 hsl)
 	float c = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y;
 	return (rgb - 0.5) * c + hsl.z;
 }
-#endif // !defined(DRAW_MODE_pick) && (defined(ENABLE_color) || defined(ENABLE_brightness))
+#endif // !defined(DRAW_MODE_silhouette) && (defined(ENABLE_color) || defined(ENABLE_brightness))
 
 const vec2 kCenter = vec2(0.5, 0.5);
 
@@ -140,10 +145,10 @@ void main()
 		discard;
 	}
 
-	#ifdef DRAW_MODE_pick
-	// switch to u_pickColor only AFTER the alpha test
-	gl_FragColor = u_pickColor;
-	#else // DRAW_MODE_pick
+	#ifdef DRAW_MODE_silhouette
+	// switch to u_silhouetteColor only AFTER the alpha test
+	gl_FragColor = u_silhouetteColor;
+	#else // DRAW_MODE_silhouette
 
 	#if defined(ENABLE_color) || defined(ENABLE_brightness)
 	{
@@ -171,8 +176,17 @@ void main()
 	}
 	#endif // defined(ENABLE_color) || defined(ENABLE_brightness)
 
+	#ifdef DRAW_MODE_colorMask
+	vec3 maskDistance = abs(gl_FragColor.rgb - u_colorMask);
+	vec3 colorMaskTolerance = vec3(u_colorMaskTolerance, u_colorMaskTolerance, u_colorMaskTolerance);
+	if (any(greaterThan(maskDistance, colorMaskTolerance)))
+	{
+		discard;
+	}
+	#endif // DRAW_MODE_colorMask
+
 	// WebGL defaults to premultiplied alpha
 	gl_FragColor.rgb *= gl_FragColor.a;
 
-	#endif // DRAW_MODE_pick
+	#endif // DRAW_MODE_silhouette
 }