diff --git a/examples/Processing/sequencer/data/glass.jpeg b/examples/Processing/sequencer/data/glass.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..d045dc95c89f296acc673799896cb771a9528f60
Binary files /dev/null and b/examples/Processing/sequencer/data/glass.jpeg differ
diff --git a/examples/Processing/sequencer/sequencer.pde b/examples/Processing/sequencer/sequencer.pde
index 38071ab88578a426a321f0324328939a339ec532..c7abc152370d54ab5ed58f7f332ac323f9c217cf 100644
--- a/examples/Processing/sequencer/sequencer.pde
+++ b/examples/Processing/sequencer/sequencer.pde
@@ -4,22 +4,22 @@
 
 float BPM = 120;
 int[][] pattern = {
+  {0, 0, 0, 0, 0, 1, 0, 0},
   {0, 0, 0, 0, 0, 0, 0, 0},
+  {0, 0, 0, 1, 0, 0, 0, 0},
+  {0, 1, 0, 0, 0, 0, 0, 0},
+  {0, 0, 1, 0, 0, 0, 0, 1},
+  {1, 0, 0, 0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0, 0, 0, 0},
+  {0, 0, 0, 0, 0, 0, 1, 0},
   {0, 0, 0, 0, 0, 0, 0, 0},
+  {0, 0, 0, 0, 1, 0, 0, 1},
   {0, 0, 0, 0, 0, 0, 0, 0},
-  {0, 0, 0, 0, 0, 0, 0, 1},
+  {0, 0, 0, 0, 1, 0, 0, 1},
   {0, 0, 0, 0, 0, 0, 0, 0},
+  {0, 0, 0, 0, 1, 0, 0, 1},
   {0, 0, 0, 0, 0, 0, 0, 0},
-  {0, 0, 0, 0, 0, 0, 0, 0},
-  {0, 0, 0, 0, 0, 0, 0, 0},
-  {0, 0, 0, 0, 0, 0, 0, 0},
-  {0, 0, 0, 0, 0, 0, 0, 0},
-  {0, 0, 0, 0, 0, 0, 0, 0},
-  {0, 0, 0, 0, 0, 0, 0, 0},
-  {0, 0, 0, 0, 0, 0, 0, 0},
-  {0, 0, 0, 0, 0, 0, 0, 0},
-  {0, 0, 0, 0, 0, 0, 0, 0}
+  {0, 0, 0, 0, 1, 0, 0, 1}
 };
 
 OPC opc;
@@ -39,7 +39,8 @@ float patternDuration = pattern.length / rowsPerSecond;
 int ledX = 400;
 int ledY = 360/2;
 int ledSpacing = 15;
-int ledBottom = int(ledY + 3.5 * ledSpacing);
+int ledWidth = ledSpacing * 23;
+int ledHeight = ledSpacing * 7;
 
 // Images
 PImage imgGreenDot;
@@ -47,7 +48,11 @@ PImage imgOrangeDot;
 PImage imgPinkDot;
 PImage imgPurpleDot;
 PImage imgCheckers;
+PImage imgGlass;
+PImage[] dots;
 
+// Timekeeping
+long startTime, pauseTime;
 
 void setup()
 {
@@ -58,6 +63,10 @@ void setup()
   imgPinkDot = loadImage("pinkDot.png");
   imgPurpleDot = loadImage("purpleDot.png");
   imgCheckers = loadImage("checkers.png");
+  imgGlass = loadImage("glass.jpeg");
+
+  // Keep our multicolored dots in an array for easy access later
+  dots = new PImage[] { imgOrangeDot, imgPurpleDot, imgPinkDot, imgGreenDot };
 
   // Connect to the local instance of fcserver. You can change this line to connect to another computer's fcserver
   opc = new OPC(this, "127.0.0.1", 7890);
@@ -82,17 +91,54 @@ void setup()
 
   // If the Fadecandy board's status LED is bothersome, it's easy to turn off or repurpose.
   opc.setStatusLed(false);
+  
+  // Init timekeeping, start the pattern from the beginning
+  startPattern();
 }
 
 void draw()
 {
   background(0);
 
-  float now = millis() * 1e-3;
+  long m = millis();
+  if (pauseTime != 0) {
+    // Advance startTime forward while paused, so we don't make any progress
+    long delta = m - pauseTime;
+    startTime += delta;
+    pauseTime += delta;
+  }
+
+  float now = (m - startTime) * 1e-3;
   drawEffects(now);
   drawGrid(now);
+  drawInstructions();
+}
+
+void clearPattern()
+{
+  for (int row = 0; row < pattern.length; row++) {
+    for (int col = 0; col < pattern[0].length; col++) {
+      pattern[row][col] = 0;
+    }
+  }
 }
 
+void startPattern()
+{
+  startTime = millis();
+  pauseTime = 0;
+}
+
+void pausePattern()
+{
+  if (pauseTime == 0) {
+    // Pause by stopping the clock and remembering when to unpause at
+    pauseTime = millis();
+  } else {
+    pauseTime = 0;
+  }
+}   
+
 void mousePressed()
 {
   int gx = (mouseX - gridX) / gridSquareSpacing;
@@ -100,7 +146,15 @@ void mousePressed()
   if (gx >= 0 && gx < pattern[0].length && gy >= 0 && gy < pattern.length) {
     pattern[gy][gx] ^= 1;
   }
-} 
+}
+
+void keyPressed()
+{
+  if (keyCode == DELETE) clearPattern();
+  if (keyCode == BACKSPACE) clearPattern();
+  if (keyCode == UP) startPattern();
+  if (key == ' ') pausePattern();
+}
 
 void drawGrid(float now)
 {
@@ -122,6 +176,18 @@ void drawGrid(float now)
   }
 }
 
+void drawInstructions()
+{
+  int size = 12;
+  int x = gridX + gridSquareSpacing * pattern[0].length + 5;
+  int y = gridY + size;
+
+  fill(255);
+  textSize(size);
+
+  text("<- Click squares to create an effect pattern\n[Delete] to clear, [Space] to pause, [Up] to restart pattern.\n", x, y);
+}
+
 void drawEffects(float now)
 {
   // To keep this simple and flexible, we'll calculate every possible effect that
@@ -136,29 +202,49 @@ void drawEffects(float now)
     for (int row = 0; row < pattern.length; row++) {
       for (int col = 0; col < pattern[0].length; col++) {
         if (pattern[row][col] != 0) {
-          float firingTime = patternStartTime + patternDuration * whichPattern + rowDuration * row;
-          drawSingleEffect(col, now - firingTime);
+          float patternTime = patternStartTime + patternDuration * whichPattern;
+          float firingTime = patternTime + rowDuration * row;
+          drawSingleEffect(col, firingTime, now);
         }
       }
     }
   }
 }
 
-void drawSingleEffect(int column, float time)
+void drawSingleEffect(int column, float firingTime, float now)
 {
+  /*
+   * Map sequencer columns to effects. Edit this to add your own effects!
+   *
+   * Parameters:
+   *   column -- Number of the column in the sequencer that we're drawing an effect for.
+   *   firingTime -- Time at which the effect in question should fire. May be in the
+   *                 past or the future. This number also uniquely identifies a particular
+   *                 instance of an effect.
+   *   now -- The current time, in seconds.
+   */
+
+  float timeDelta = now - firingTime;
+ 
   switch (column) {
 
     // First four tracks: Colored dots rising from below
-    case 0: drawDotEffect(column, time, imgOrangeDot); break;
-    case 1: drawDotEffect(column, time, imgPinkDot); break;
-    case 2: drawDotEffect(column, time, imgPurpleDot); break;
-    case 3: drawDotEffect(column, time, imgGreenDot); break;
-
-    // Spinner overlay
-    case 6: drawSpinnerEffect(time, imgCheckers); break;
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+      drawDotEffect(column, timeDelta, dots[column]);
+      break;
+   
+    // Stripes moving from left to right. Each stripe particle is unique based on firingTime.
+    case 4: drawStripeEffect(firingTime, timeDelta); break;
+
+    // Image spinner overlays
+    case 5: drawSpinnerEffect(timeDelta, imgCheckers); break;
+    case 6: drawSpinnerEffect(timeDelta, imgGlass); break;
 
     // Full-frame flash effect
-    case 7: drawFlashEffect(time); break;
+    case 7: drawFlashEffect(timeDelta); break;
   }
 }
 
@@ -172,7 +258,7 @@ void drawDotEffect(int column, float time, PImage im)
   float shrinkSpeed = motionSpeed * 1.2;
   float size = 200 - max(0, time * shrinkSpeed);
   float centerX = ledX + (column - 1.5) * 75.0;
-  float topY = ledBottom - time * motionSpeed;
+  float topY = ledY + ledHeight/2 - time * motionSpeed;
   int brightness = int(255 - max(0, fadeSpeed * time));
 
   // Adjust the 'top' position so the dot seems to appear on-time
@@ -187,20 +273,22 @@ void drawDotEffect(int column, float time, PImage im)
 
 void drawSpinnerEffect(float time, PImage im)
 {
-  float t = time / (rowDuration * 8.0);
-  if (t < 0 || t > 1) return;
+  float t = time / (rowDuration * 1.5);
+  if (t < -1 || t > 1) return;
 
-  float angle = t * 2.5;
+  float angle = time * 5.0;
   float size = 400;
-  int alpha = int(100 * sin(t * PI));
+  int alpha = int(128 * (1.0 + cos(t * PI)));
 
-  pushMatrix();
-  translate(ledX, ledY);
-  rotate(angle);
-  blendMode(ADD);
-  tint(alpha);
-  image(im, -size/2, -size/2, size, size);
-  popMatrix();
+  if (alpha > 0) {
+    pushMatrix();
+    translate(ledX, ledY);
+    rotate(angle);
+    blendMode(ADD);
+    tint(alpha);
+    image(im, -size/2, -size/2, size, size);
+    popMatrix();
+  }
 }
 
 void drawFlashEffect(float time)
@@ -214,3 +302,21 @@ void drawFlashEffect(float time)
   rect(0, 0, width, height);
 }
 
+void drawStripeEffect(float identity, float time)
+{
+  // Pick a pseudorandom dot and Y position
+  randomSeed(int(identity * 1e3));
+  PImage im = dots[int(random(dots.length))];
+  float y = ledY - ledHeight/2 + random(ledHeight);
+
+  // Animation
+  float motionSpeed = rowsPerSecond * 400.0;
+  float x = ledX - ledWidth/2 + time * motionSpeed;
+  float sizeX = 300;
+  float sizeY = 30;
+  
+  blendMode(ADD);
+  tint(255);
+  image(im, x - sizeX/2, y - sizeY/2, sizeX, sizeY);   
+}
+