diff --git a/garnet/examples/escher/BUILD.gn b/garnet/examples/escher/BUILD.gn
index bbdb848fd14b7d6131d8953a487484fa53e144eb..2788bb4e3e216b7c6b9effd3013da3439fd6d498 100644
--- a/garnet/examples/escher/BUILD.gn
+++ b/garnet/examples/escher/BUILD.gn
@@ -6,16 +6,18 @@ import("//build/package.gni")
 import("//garnet/lib/vulkan/image_pipe_swapchain.gni")
 import("//third_party/vulkan_loader_and_validation_layers/layers/layers.gni")
 
+# NOTE: whenever a new example is added, also add it to
+# //garnet/public/lib/escher/test:force_waterfall_to_build_on_host
 group("escher") {
   deps = [
     ":escher_waterfall",
-    ":escher_waterfall2",
   ]
 }
 
 package("escher_waterfall") {
   deps = [
     "waterfall",
+    "//third_party/vulkan_loader_and_validation_layers/layers",
   ]
 
   binary = "waterfall"
@@ -27,29 +29,6 @@ package("escher_waterfall") {
     },
   ]
 
-  public_deps =
-      vulkan_validation_layers.public_deps + image_pipe_swapchain_fb.public_deps
-  loadable_modules = vulkan_validation_layers.loadable_modules +
-                     image_pipe_swapchain_fb.loadable_modules
-  resources =
-      vulkan_validation_layers.resources + image_pipe_swapchain_fb.resources
-}
-
-package("escher_waterfall2") {
-  deps = [
-    "waterfall2",
-    "//third_party/vulkan_loader_and_validation_layers/layers",
-  ]
-
-  binary = "waterfall2"
-
-  meta = [
-    {
-      path = rebase_path("meta/escher_examples.cmx")
-      dest = "escher_waterfall2.cmx"
-    },
-  ]
-
   public_deps =
       vulkan_validation_layers.public_deps + image_pipe_swapchain_fb.public_deps
   loadable_modules = vulkan_validation_layers.loadable_modules +
diff --git a/garnet/examples/escher/waterfall/BUILD.gn b/garnet/examples/escher/waterfall/BUILD.gn
index 7be4b1e616645e837ec6a2cf83cf09b7340d48ad..671759b54636fb7138586492adc59261ec060bf9 100644
--- a/garnet/examples/escher/waterfall/BUILD.gn
+++ b/garnet/examples/escher/waterfall/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2016 The Fuchsia Authors. All rights reserved.
+# Copyright 2018 The Fuchsia Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
@@ -8,6 +8,7 @@ executable("waterfall") {
     "waterfall_demo.h",
     "waterfall_main.cc",
   ]
+
   deps = [
     ":scenes",
     "//garnet/examples/escher/common",
@@ -19,6 +20,10 @@ executable("waterfall") {
     "//garnet/public/lib/escher",
     "//third_party/glm",
   ]
+
+  if (is_fuchsia) {
+    deps += [ "//zircon/public/lib/trace" ]
+  }
 }
 
 source_set("scenes") {
@@ -27,24 +32,8 @@ source_set("scenes") {
     "scenes/demo_scene.h",
     "scenes/paper_demo_scene1.cc",
     "scenes/paper_demo_scene1.h",
-    "scenes/ring_tricks1.cc",
-    "scenes/ring_tricks1.h",
-    "scenes/ring_tricks2.cc",
-    "scenes/ring_tricks2.h",
-    "scenes/ring_tricks3.cc",
-    "scenes/ring_tricks3.h",
     "scenes/scene.cc",
     "scenes/scene.h",
-    "scenes/uber_scene.cc",
-    "scenes/uber_scene.h",
-    "scenes/uber_scene2.cc",
-    "scenes/uber_scene2.h",
-    "scenes/uber_scene3.cc",
-    "scenes/uber_scene3.h",
-    "scenes/wobbly_ocean_scene.cc",
-    "scenes/wobbly_ocean_scene.h",
-    "scenes/wobbly_rings_scene.cc",
-    "scenes/wobbly_rings_scene.h",
   ]
 
   deps = [
diff --git a/garnet/examples/escher/waterfall/scenes/ring_tricks1.cc b/garnet/examples/escher/waterfall/scenes/ring_tricks1.cc
deleted file mode 100644
index 295059d1cf6bd6284f7c5f2c258e58613e13846b..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/ring_tricks1.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "garnet/examples/escher/waterfall/scenes/ring_tricks1.h"
-
-#include "lib/escher/geometry/tessellation.h"
-#include "lib/escher/geometry/transform.h"
-#include "lib/escher/geometry/types.h"
-#include "lib/escher/material/material.h"
-#include "lib/escher/scene/model.h"
-#include "lib/escher/scene/stage.h"
-#include "lib/escher/shape/modifier_wobble.h"
-#include "lib/escher/util/stopwatch.h"
-#include "lib/escher/vk/image.h"
-#include "lib/escher/vk/vulkan_context.h"
-
-using escher::MeshAttribute;
-using escher::MeshSpec;
-using escher::Object;
-using escher::ShapeModifier;
-using escher::Transform;
-using escher::vec2;
-using escher::vec3;
-
-RingTricks1::RingTricks1(Demo* demo) : Scene(demo) {}
-
-void RingTricks1::Init(escher::Stage* stage) {
-  bg_ = fxl::MakeRefCounted<escher::Material>();
-  color1_ = fxl::MakeRefCounted<escher::Material>();
-  color2_ = fxl::MakeRefCounted<escher::Material>();
-
-  bg_->set_color(vec3(0.8f, 0.8f, 0.8f));
-
-  color1_->set_color(vec3(157.f / 255.f, 183.f / 255.f, 189.f / 255.f));
-  color2_->set_color(vec3(63.f / 255.f, 138.f / 255.f, 153.f / 255.f));
-
-  // Create meshes for fancy wobble effect.
-  MeshSpec spec{MeshAttribute::kPosition2D | MeshAttribute::kPositionOffset |
-                MeshAttribute::kPerimeterPos | MeshAttribute::kUV};
-
-  ring_mesh1_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 300.f,
-                                    250.f, 18.f, -15.f);
-}
-
-RingTricks1::~RingTricks1() {}
-
-escher::Model* RingTricks1::Update(const escher::Stopwatch& stopwatch,
-                                   uint64_t frame_count, escher::Stage* stage,
-                                   escher::PaperRenderer2* renderer) {
-  float current_time_sec = stopwatch.GetElapsedSeconds();
-
-  float screen_width = stage->viewing_volume().width();
-  float screen_height = stage->viewing_volume().height();
-  float min_height = 5.f;
-  float max_height = 80.f;
-  float elevation_range = max_height - min_height;
-
-  std::vector<Object> objects;
-
-  float circle_elevation =
-      (sin(current_time_sec * 1.f) * 0.5f + 0.5f) * elevation_range +
-      min_height;
-
-  float outer_ring_scale =
-      (cos(current_time_sec * 1.f) * 0.5f + 0.5f) * 1.25 + .5;
-
-  // Create the ring that will do the fancy trick
-  vec3 inner_ring_pos(screen_width * 0.5f, screen_height * 0.5f, 15.f);
-  Object inner_ring(inner_ring_pos, ring_mesh1_, color1_);
-  inner_ring.set_shape_modifiers(ShapeModifier::kWobble);
-  objects.push_back(inner_ring);
-
-  // Create the ring that will do the fancy trick
-  vec3 outer_ring_pos(screen_width * 0.5f, screen_height * 0.5f,
-                      circle_elevation);
-  Object outer_ring(
-      Transform(outer_ring_pos,
-                vec3(outer_ring_scale, outer_ring_scale, outer_ring_scale)),
-      ring_mesh1_, color2_);
-  outer_ring.set_shape_modifiers(ShapeModifier::kWobble);
-  objects.push_back(outer_ring);
-
-  // Create our background plane
-  Object bg_plane(Object::NewRect(vec3(0.f, 0.f, 0.f),
-                                  vec2(screen_width, screen_height), bg_));
-
-  objects.push_back(bg_plane);
-
-  // Create the Model
-  model_ = std::unique_ptr<escher::Model>(new escher::Model(objects));
-  model_->set_time(current_time_sec);
-
-  return model_.get();
-}
diff --git a/garnet/examples/escher/waterfall/scenes/ring_tricks1.h b/garnet/examples/escher/waterfall/scenes/ring_tricks1.h
deleted file mode 100644
index 0a9d2f95295891927a8d38ba20f68624e9e2af8f..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/ring_tricks1.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_RING_TRICKS1_H_
-#define GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_RING_TRICKS1_H_
-
-#include "lib/escher/escher.h"
-
-#include "garnet/examples/escher/waterfall/scenes/scene.h"
-
-class RingTricks1 : public Scene {
- public:
-  RingTricks1(Demo* demo);
-  ~RingTricks1();
-
-  void Init(escher::Stage* stage) override;
-
-  escher::Model* Update(const escher::Stopwatch& stopwatch,
-                        uint64_t frame_count, escher::Stage* stage,
-                        escher::PaperRenderer2* renderer) override;
-
- private:
-  std::unique_ptr<escher::Model> model_;
-
-  escher::MaterialPtr bg_;
-  escher::MaterialPtr color1_;
-  escher::MaterialPtr color2_;
-
-  escher::MeshPtr ring_mesh1_;
-
-  FXL_DISALLOW_COPY_AND_ASSIGN(RingTricks1);
-};
-
-#endif  // GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_RING_TRICKS1_H_
diff --git a/garnet/examples/escher/waterfall/scenes/ring_tricks2.cc b/garnet/examples/escher/waterfall/scenes/ring_tricks2.cc
deleted file mode 100644
index ce9ff875d20623745d3655066fcb3f28f9e23612..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/ring_tricks2.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "garnet/examples/escher/waterfall/scenes/ring_tricks2.h"
-
-#include "lib/escher/geometry/clip_planes.h"
-#include "lib/escher/geometry/tessellation.h"
-#include "lib/escher/geometry/types.h"
-#include "lib/escher/material/material.h"
-#include "lib/escher/renderer/batch_gpu_uploader.h"
-#include "lib/escher/scene/model.h"
-#include "lib/escher/scene/stage.h"
-#include "lib/escher/shape/modifier_wobble.h"
-#include "lib/escher/util/stopwatch.h"
-#include "lib/escher/vk/image.h"
-#include "lib/escher/vk/texture.h"
-#include "lib/escher/vk/vulkan_context.h"
-
-using escher::MeshAttribute;
-using escher::MeshSpec;
-using escher::Object;
-using escher::RoundedRectSpec;
-using escher::ShapeModifier;
-using escher::vec2;
-using escher::vec3;
-
-RingTricks2::RingTricks2(Demo* demo)
-    : Scene(demo), factory_(demo->GetEscherWeakPtr()) {}
-
-void RingTricks2::Init(escher::Stage* stage) {
-  red_ = fxl::MakeRefCounted<escher::Material>();
-  bg_ = fxl::MakeRefCounted<escher::Material>();
-  color1_ = fxl::MakeRefCounted<escher::Material>();
-  color2_ = fxl::MakeRefCounted<escher::Material>();
-  red_->set_color(vec3(0.98f, 0.15f, 0.15f));
-  bg_->set_color(vec3(0.8f, 0.8f, 0.8f));
-  color1_->set_color(vec3(63.f / 255.f, 138.f / 255.f, 153.f / 255.f));
-  color2_->set_color(vec3(143.f / 255.f, 143.f / 255.f, 143.f / 255.f));
-
-  gradient_ = fxl::MakeRefCounted<escher::Material>();
-  gradient_->SetTexture(escher()->NewTexture(
-      escher()->NewGradientImage(128, 128), vk::Filter::eLinear));
-  gradient_->set_color(vec3(0.98f, 0.15f, 0.15f));
-
-  auto gpu_uploader = escher::BatchGpuUploader::New(escher()->GetWeakPtr());
-  // Create meshes for fancy wobble effect.
-  {
-    MeshSpec spec{MeshAttribute::kPosition2D | MeshAttribute::kPositionOffset |
-                  MeshAttribute::kPerimeterPos | MeshAttribute::kUV};
-    ring_mesh1_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 285.f,
-                                      265.f, 18.f, -15.f);
-  }
-
-  // Create rounded rectangles.
-  {
-    // Work in progress.  The "#if 1" variant works with both the Waterfall and
-    // Waterfall2 demos, but the "#if 0" variant works only with the Waterfall2
-    // demo.  This is because the way ModelRenderer VkPipelines are built is
-    // extremely fiddly and manual, and not worth fixing since they'll soon be
-    // deleted.
-#if 1
-    MeshSpec mesh_spec{MeshAttribute::kPosition2D | MeshAttribute::kUV};
-#else
-    MeshSpec mesh_spec{{MeshAttribute::kPosition2D, MeshAttribute::kUV}};
-#endif
-    rounded_rect1_ =
-        factory_.NewRoundedRect(RoundedRectSpec(200, 400, 90, 20, 20, 50),
-                                mesh_spec, gpu_uploader.get());
-  }
-
-  // Create sphere.
-  {
-    MeshSpec spec{MeshAttribute::kPosition3D | MeshAttribute::kUV};
-    sphere_ = escher::NewSphereMesh(escher(), spec, 3, vec3(0, 0, 0), 100);
-  }
-
-  // Upload mesh data to the GPU.
-  gpu_uploader->Submit();
-}
-
-RingTricks2::~RingTricks2() {}
-
-escher::Model* RingTricks2::Update(const escher::Stopwatch& stopwatch,
-                                   uint64_t frame_count, escher::Stage* stage,
-                                   escher::PaperRenderer2* renderer) {
-  float current_time_sec = stopwatch.GetElapsedSeconds();
-
-  float screen_width = stage->viewing_volume().width();
-  float screen_height = stage->viewing_volume().height();
-  float min_elevation = 5.f;
-  float max_elevation = 95.f;
-  float mid_elevation = 0.5f * (min_elevation + max_elevation);
-  float elevation_range = max_elevation - min_elevation;
-
-  std::vector<Object> objects;
-
-  // Orbiting circle1.
-  float circle1_orbit_radius = 275.f;
-  vec3 circle1_pos(sin(current_time_sec * 1.f) * circle1_orbit_radius +
-                       (screen_width * 0.5f),
-                   cos(current_time_sec * 1.f) * circle1_orbit_radius +
-                       (screen_height * 0.5f),
-                   mid_elevation + 10.f);
-  Object circle1(Object::NewCircle(circle1_pos, 60.f, red_));
-  objects.push_back(circle1);
-
-  // Orbiting circle2.
-  float circle2_orbit_radius = 120.f;
-  vec2 circle2_offset(sin(current_time_sec * 2.f) * circle2_orbit_radius,
-                      cos(current_time_sec * 2.f) * circle2_orbit_radius);
-
-  float circle2_elevation =
-      (cos(current_time_sec * 1.5f) * 0.5 + 0.5) * elevation_range +
-      min_elevation;
-  vec3 circle2_pos(vec2(circle1_pos) + circle2_offset, circle2_elevation);
-  Object circle2(Object::NewCircle(circle2_pos, 30.f, color1_));
-  objects.push_back(circle2);
-
-  // Create the ring that will do the fancy trick.
-  vec3 inner_ring_pos(screen_width * 0.5f, screen_height * 0.5f, mid_elevation);
-  Object inner_ring(inner_ring_pos, ring_mesh1_, color2_);
-  objects.push_back(inner_ring);
-
-  // Create our background plane.
-  Object bg_plane(
-      Object::NewRect(vec3(0, 0, 0), vec2(screen_width, screen_height), bg_));
-  objects.push_back(bg_plane);
-
-  // Stack of circles.
-  Object circle4(Object::NewCircle(vec2(100, 100), 90.f, 35.f, red_));
-  objects.push_back(circle4);
-
-  Object circle5(Object::NewCircle(vec2(100, 100), 80.f, 45.f, color2_));
-  objects.push_back(circle5);
-
-  Object circle6(Object::NewCircle(vec2(100, 100), 70.f, 55.f, color1_));
-  objects.push_back(circle6);
-
-  Object circle7(Object::NewCircle(vec2(100, 100), 60.f, 65.f, red_));
-  objects.push_back(circle7);
-
-  Object circle8(Object::NewCircle(vec2(100, 100), 50.f, 75.f, color2_));
-  objects.push_back(circle8);
-
-  Object circle9(Object::NewCircle(vec2(100, 100), 40.f, 85.f, color1_));
-  objects.push_back(circle9);
-
-  // Rounded rect.
-  Object round_rect1(vec3(300, 700, 30.f), rounded_rect1_, gradient_);
-  objects.push_back(round_rect1);
-
-  // Sphere.
-  Object sphere(vec3(800, 300, 0.f), sphere_, color1_);
-  objects.push_back(sphere);
-
-  // Create the Model
-  model_ = std::unique_ptr<escher::Model>(new escher::Model(objects));
-  model_->set_time(current_time_sec);
-
-  // The following code allows the scene to be rendered in both the Waterfall
-  // and Waterfall2 demos.  In the near-ish future, only Waterfall2 will remain,
-  // and this method signature will be changed to no longer return a Model.
-  // Therefore it will no longer be necessary to collect these objects in a
-  // vector.
-  if (renderer) {
-    renderer->DrawLegacyObject(circle1);
-    renderer->DrawLegacyObject(circle2);
-    renderer->DrawLegacyObject(inner_ring);
-    renderer->DrawLegacyObject(bg_plane);
-    renderer->DrawLegacyObject(round_rect1);
-    renderer->DrawLegacyObject(sphere);
-    renderer->DrawLegacyObject(circle4);
-    renderer->DrawLegacyObject(circle5);
-    renderer->DrawLegacyObject(circle6);
-    renderer->DrawLegacyObject(circle7);
-    renderer->DrawLegacyObject(circle8);
-    renderer->DrawLegacyObject(circle9);
-  }
-
-  return model_.get();
-}
diff --git a/garnet/examples/escher/waterfall/scenes/ring_tricks2.h b/garnet/examples/escher/waterfall/scenes/ring_tricks2.h
deleted file mode 100644
index 821e13bffd87d084488f1dbf6840d9fef75909de..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/ring_tricks2.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_RING_TRICKS2_H_
-#define GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_RING_TRICKS2_H_
-
-#include "lib/escher/escher.h"
-#include "lib/escher/shape/rounded_rect_factory.h"
-
-#include "garnet/examples/escher/waterfall/scenes/scene.h"
-
-class RingTricks2 : public Scene {
- public:
-  RingTricks2(Demo* demo);
-  ~RingTricks2();
-
-  void Init(escher::Stage* stage) override;
-
-  escher::Model* Update(const escher::Stopwatch& stopwatch,
-                        uint64_t frame_count, escher::Stage* stage,
-                        escher::PaperRenderer2* renderer) override;
-
- private:
-  escher::RoundedRectFactory factory_;
-
-  std::unique_ptr<escher::Model> model_;
-
-  escher::MaterialPtr red_;
-  escher::MaterialPtr bg_;
-
-  escher::MaterialPtr color1_;
-  escher::MaterialPtr color2_;
-
-  escher::MaterialPtr gradient_;
-
-  escher::MeshPtr ring_mesh1_;
-
-  escher::MeshPtr rounded_rect1_;
-  escher::MeshPtr rounded_rect2_;
-  escher::MeshPtr rounded_rect3_;
-  escher::MeshPtr sphere_;
-
-  FXL_DISALLOW_COPY_AND_ASSIGN(RingTricks2);
-};
-
-#endif  // GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_RING_TRICKS2_H_
diff --git a/garnet/examples/escher/waterfall/scenes/ring_tricks3.cc b/garnet/examples/escher/waterfall/scenes/ring_tricks3.cc
deleted file mode 100644
index 58ad8e5a7dc129a43b1f08d0069ebcebab1c9a4d..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/ring_tricks3.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "garnet/examples/escher/waterfall/scenes/ring_tricks3.h"
-
-#include "lib/escher/geometry/tessellation.h"
-#include "lib/escher/geometry/types.h"
-#include "lib/escher/material/material.h"
-#include "lib/escher/scene/model.h"
-#include "lib/escher/scene/stage.h"
-#include "lib/escher/shape/modifier_wobble.h"
-#include "lib/escher/util/stopwatch.h"
-#include "lib/escher/vk/image.h"
-#include "lib/escher/vk/vulkan_context.h"
-
-using escher::MeshAttribute;
-using escher::MeshSpec;
-using escher::Object;
-using escher::ShapeModifier;
-using escher::vec2;
-using escher::vec3;
-
-RingTricks3::RingTricks3(Demo* demo) : Scene(demo) {}
-
-void RingTricks3::Init(escher::Stage* stage) {
-  bg_ = fxl::MakeRefCounted<escher::Material>();
-  color1_ = fxl::MakeRefCounted<escher::Material>();
-  color2_ = fxl::MakeRefCounted<escher::Material>();
-  bg_->set_color(vec3(0.8f, 0.8f, 0.8f));
-  color1_->set_color(vec3(63.f / 255.f, 138.f / 255.f, 153.f / 255.f));
-  color2_->set_color(vec3(143.f / 255.f, 143.f / 255.f, 143.f / 255.f));
-
-  // Create meshes for fancy wobble effect.
-  MeshSpec spec{MeshAttribute::kPosition2D | MeshAttribute::kPositionOffset |
-                MeshAttribute::kPerimeterPos | MeshAttribute::kUV};
-  ring_mesh1_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 285.f,
-                                    265.f, 18.f, -15.f);
-}
-
-RingTricks3::~RingTricks3() {}
-
-escher::Model* RingTricks3::Update(const escher::Stopwatch& stopwatch,
-                                   uint64_t frame_count, escher::Stage* stage,
-                                   escher::PaperRenderer2* renderer) {
-  float current_time_sec = stopwatch.GetElapsedSeconds();
-
-  float screen_width = stage->viewing_volume().width();
-  float screen_height = stage->viewing_volume().height();
-  float min_height = 5.f;
-  float max_height = 80.f;
-  float elevation_range = max_height - min_height;
-
-  std::vector<Object> objects;
-
-  // animate the position along a figure-eight
-  float figure_eight_size = 600.f;
-  float circle1_path_scale =
-      2. / (3. - cos(2. * current_time_sec)) * figure_eight_size;
-  float circle1_x_pos =
-      circle1_path_scale * cos(current_time_sec) + (screen_width * 0.5);
-  float circle1_y_pos = circle1_path_scale * sin(2. * current_time_sec) / 2. +
-                        (screen_height * 0.5);
-  float circle1_elevation =
-      (sin(2. * current_time_sec) * 0.5 + 0.5) * elevation_range + min_height;
-
-  Object circle1(Object::NewCircle(
-      vec3(circle1_x_pos, circle1_y_pos, circle1_elevation), 120.f, color1_));
-  objects.push_back(circle1);
-
-  // Create the ring that will do the fancy trick
-  // vec3 inner_ring_pos(screen_width * 0.5f, screen_height * 0.5f,
-  //                     (elevation_range * 0.75 + min_height));
-  vec3 inner_ring_pos(screen_width * 0.5f, screen_height * 0.5f, 30.f);
-  Object inner_ring(inner_ring_pos, ring_mesh1_, color2_);
-  inner_ring.set_shape_modifiers(ShapeModifier::kWobble);
-  objects.push_back(inner_ring);
-
-  // Create our background plane
-  Object bg_plane(Object::NewRect(vec2(0.f, 0.f),
-                                  vec2(screen_width, screen_height), 0.f, bg_));
-
-  objects.push_back(bg_plane);
-
-  // Create the Model
-  model_ = std::unique_ptr<escher::Model>(new escher::Model(objects));
-  model_->set_time(current_time_sec);
-
-  return model_.get();
-}
diff --git a/garnet/examples/escher/waterfall/scenes/ring_tricks3.h b/garnet/examples/escher/waterfall/scenes/ring_tricks3.h
deleted file mode 100644
index bfb8903ee10240dcf31d1277db34ace15e8c7fa1..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/ring_tricks3.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_RING_TRICKS3_H_
-#define GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_RING_TRICKS3_H_
-
-#include "lib/escher/escher.h"
-
-#include "garnet/examples/escher/waterfall/scenes/scene.h"
-
-class RingTricks3 : public Scene {
- public:
-  RingTricks3(Demo* demo);
-  ~RingTricks3();
-
-  void Init(escher::Stage* stage) override;
-
-  escher::Model* Update(const escher::Stopwatch& stopwatch,
-                        uint64_t frame_count, escher::Stage* stage,
-                        escher::PaperRenderer2* renderer) override;
-
- private:
-  std::unique_ptr<escher::Model> model_;
-
-  escher::MaterialPtr bg_;
-
-  escher::MaterialPtr color1_;
-  escher::MaterialPtr color2_;
-
-  escher::MeshPtr ring_mesh1_;
-
-  FXL_DISALLOW_COPY_AND_ASSIGN(RingTricks3);
-};
-
-#endif  // GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_RING_TRICKS3_H_
diff --git a/garnet/examples/escher/waterfall/scenes/uber_scene.cc b/garnet/examples/escher/waterfall/scenes/uber_scene.cc
deleted file mode 100644
index a56b210d9f927ef0c2441cca99d08a6487f375ac..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/uber_scene.cc
+++ /dev/null
@@ -1,242 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "garnet/examples/escher/waterfall/scenes/uber_scene.h"
-
-#include "lib/escher/geometry/tessellation.h"
-#include "lib/escher/geometry/types.h"
-#include "lib/escher/material/material.h"
-#include "lib/escher/scene/model.h"
-#include "lib/escher/scene/stage.h"
-#include "lib/escher/shape/modifier_wobble.h"
-#include "lib/escher/util/stopwatch.h"
-#include "lib/escher/vk/image.h"
-#include "lib/escher/vk/vulkan_context.h"
-
-using escher::MeshAttribute;
-using escher::MeshSpec;
-using escher::Object;
-using escher::ShapeModifier;
-using escher::vec2;
-using escher::vec3;
-
-UberScene::UberScene(Demo* demo) : Scene(demo) {}
-
-void UberScene::Init(escher::Stage* stage) {
-  blue_ = fxl::MakeRefCounted<escher::Material>();
-  red_ = fxl::MakeRefCounted<escher::Material>();
-  bg_ = fxl::MakeRefCounted<escher::Material>();
-  purple_->set_color(vec3(0.588f, 0.239f, 0.729f));
-  bg_->set_color(vec3(0.8f, 0.8f, 0.8f));
-
-  // Create meshes for fancy wobble effect.
-  MeshSpec spec{MeshAttribute::kPosition2D | MeshAttribute::kPositionOffset |
-                MeshAttribute::kPerimeterPos | MeshAttribute::kUV};
-  ring_mesh1_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 300.f,
-                                    250.f, 18.f, -15.f);
-
-  ring_mesh2_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 500.f,
-                                    400.f, 18.f, -15.f);
-
-  ring_mesh3_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 500.f,
-                                    350.f, 18.f, -15.f);
-
-  ring_mesh4_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 150.f,
-                                    100.f, 18.f, -15.f);
-}
-
-UberScene::~UberScene() {}
-
-escher::Model* UberScene::Update(const escher::Stopwatch& stopwatch,
-                                 uint64_t frame_count, escher::Stage* stage,
-                                 escher::PaperRenderer2* renderer) {
-  float current_time_sec = stopwatch.GetElapsedSeconds();
-
-  float screen_width = stage->viewing_volume().width();
-  float screen_height = stage->viewing_volume().height();
-  float min_height = 2.f;
-  float max_height = 20.f;
-
-  // animate the position along a figure-eight
-  float circle1_time_offset = 0.f;
-  float circle1_time = current_time_sec + circle1_time_offset;
-  float circle1_path_scale = 2. / (3. - cos(2. * circle1_time)) * 800.;
-  float circle1_x_pos =
-      circle1_path_scale * cos(circle1_time) + (screen_width * 0.5);
-  float circle1_y_pos =
-      circle1_path_scale * sin(2. * circle1_time) / 2. + (screen_height * 0.5);
-  float circle1_z_pos =
-      circle1_path_scale / 800. * max_height * sin(2. * circle1_time) / 2. +
-      min_height + (max_height * 0.5);
-
-  Object circle1(Object::NewCircle(vec2(circle1_x_pos, circle1_y_pos), 120.f,
-                                   circle1_z_pos, blue_));
-
-  float circle1o_y_pos = circle1_y_pos + (sin(circle1_time * 2) * 200.);
-  float circle1o_z_pos = circle1_z_pos + (cos(circle1_time * 2) * 3.);
-  Object circle1o(Object::NewCircle(vec2(circle1_x_pos, circle1o_y_pos), 40.f,
-                                    circle1o_z_pos, red_));
-
-  // animate the position along a figure-eight
-  float circle2_time_offset = 0.75f;
-  float circle2_time = current_time_sec + circle2_time_offset;
-  float circle2_path_scale = 2. / (3. - cos(2. * circle2_time)) * 800.;
-  float circle2_x_pos =
-      circle2_path_scale * cos(circle2_time) + (screen_width * 0.5);
-  float circle2_y_pos =
-      circle2_path_scale * sin(2. * circle2_time) / 2. + (screen_height * 0.5);
-  float circle2_z_pos =
-      circle2_path_scale / 800. * max_height * sin(2. * circle2_time) / 2. +
-      min_height + (max_height * 0.5);
-
-  Object circle2(Object::NewCircle(vec2(circle2_x_pos, circle2_y_pos), 120.f,
-                                   circle2_z_pos, blue_));
-
-  float circle2o_y_pos = circle2_y_pos + (sin(circle2_time * 2) * 200.);
-  float circle2o_z_pos = circle2_z_pos + (cos(circle2_time * 2) * 3.);
-  Object circle2o(Object::NewCircle(vec2(circle2_x_pos, circle2o_y_pos), 40.f,
-                                    circle2o_z_pos, red_));
-
-  // animate the position along a figure-eight
-  float circle3_time_offset = 1.5f;
-  float circle3_time = current_time_sec + circle3_time_offset;
-  float circle3_path_scale = 2. / (3. - cos(2. * circle3_time)) * 800.;
-  float circle3_x_pos =
-      circle3_path_scale * cos(circle3_time) + (screen_width * 0.5);
-  float circle3_y_pos =
-      circle3_path_scale * sin(2. * circle3_time) / 2. + (screen_height * 0.5);
-  float circle3_z_pos =
-      circle3_path_scale / 800. * max_height * sin(2. * circle3_time) / 2. +
-      min_height + (max_height * 0.5);
-
-  Object circle3(Object::NewCircle(vec2(circle3_x_pos, circle3_y_pos), 120.f,
-                                   circle3_z_pos, blue_));
-
-  float circle3o_y_pos = circle3_y_pos + (sin(circle3_time * 2) * 200.);
-  float circle3o_z_pos = circle3_z_pos + (cos(circle3_time * 2) * 3.);
-  Object circle3o(Object::NewCircle(vec2(circle3_x_pos, circle3o_y_pos), 40.f,
-                                    circle3o_z_pos, red_));
-
-  // animate the position along a figure-eight
-  float circle4_time_offset = 2.25f;
-  float circle4_time = current_time_sec + circle4_time_offset;
-  float circle4_path_scale = 2. / (3. - cos(2. * circle4_time)) * 800.;
-  float circle4_x_pos =
-      circle4_path_scale * cos(circle4_time) + (screen_width * 0.5);
-  float circle4_y_pos =
-      circle4_path_scale * sin(2. * circle4_time) / 2. + (screen_height * 0.5);
-  float circle4_z_pos =
-      circle4_path_scale / 800. * max_height * sin(2. * circle4_time) / 2. +
-      min_height + (max_height * 0.5);
-
-  Object circle4(Object::NewCircle(vec2(circle4_x_pos, circle4_y_pos), 120.f,
-                                   circle4_z_pos, blue_));
-
-  float circle4o_y_pos = circle4_y_pos + (sin(circle4_time * 2) * 200.);
-  float circle4o_z_pos = circle4_z_pos + (cos(circle4_time * 2) * 3.);
-  Object circle4o(Object::NewCircle(vec2(circle4_x_pos, circle4o_y_pos), 40.f,
-                                    circle4o_z_pos, red_));
-
-  // animate the position along a figure-eight
-  float circle5_time_offset = 3.f;
-  float circle5_time = current_time_sec + circle5_time_offset;
-  float circle5_path_scale = 2. / (3. - cos(2. * circle5_time)) * 800.;
-  float circle5_x_pos =
-      circle5_path_scale * cos(circle5_time) + (screen_width * 0.5);
-  float circle5_y_pos =
-      circle5_path_scale * sin(2. * circle5_time) / 2. + (screen_height * 0.5);
-  float circle5_z_pos =
-      circle5_path_scale / 800. * max_height * sin(2. * circle5_time) / 2. +
-      min_height + (max_height * 0.5);
-
-  Object circle5(Object::NewCircle(vec2(circle5_x_pos, circle5_y_pos), 120.f,
-                                   circle5_z_pos, blue_));
-
-  float circle5o_y_pos = circle5_y_pos + (sin(circle5_time * 2) * 200.);
-  float circle5o_z_pos = circle5_z_pos + (cos(circle5_time * 2) * 3.);
-  Object circle5o(Object::NewCircle(vec2(circle5_x_pos, circle5o_y_pos), 40.f,
-                                    circle5o_z_pos, red_));
-
-  // animate the position along a figure-eight
-  float circle6_time_offset = 3.75f;
-  float circle6_time = current_time_sec + circle6_time_offset;
-  float circle6_path_scale = 2. / (3. - cos(2. * circle6_time)) * 800.;
-  float circle6_x_pos =
-      circle6_path_scale * cos(circle6_time) + (screen_width * 0.5);
-  float circle6_y_pos =
-      circle6_path_scale * sin(2. * circle6_time) / 2. + (screen_height * 0.5);
-  float circle6_z_pos =
-      circle6_path_scale / 800. * max_height * sin(2. * circle6_time) / 2. +
-      min_height + (max_height * 0.5);
-
-  Object circle6(Object::NewCircle(vec2(circle6_x_pos, circle6_y_pos), 120.f,
-                                   circle6_z_pos, blue_));
-
-  float circle6o_y_pos = circle6_y_pos + (sin(circle6_time * 2) * 200.);
-  float circle6o_z_pos = circle6_z_pos + (cos(circle6_time * 2) * 3.);
-  Object circle6o(Object::NewCircle(vec2(circle6_x_pos, circle6o_y_pos), 40.f,
-                                    circle6o_z_pos, red_));
-
-  Object rectangle(Object::NewRect(
-      vec2(0.f, 0.f), vec2(screen_width, screen_height), 1.f, bg_));
-
-  vec3 ring1_pos(250., screen_height * 0.5, 10.f);
-  Object ring1(ring1_pos, ring_mesh1_, purple_);
-  ring1.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring2_pos(screen_width - 250., screen_height * 0.5, 10.f);
-  Object ring2(ring2_pos, ring_mesh1_, purple_);
-  ring2.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring1a_pos(250., screen_height * 0.5, 22.f);
-  Object ring1a(ring1a_pos, ring_mesh4_, purple_);
-  ring1a.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring2a_pos(screen_width - 250., screen_height * 0.5, 22.f);
-  Object ring2a(ring2a_pos, ring_mesh4_, purple_);
-  ring2a.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring3_pos(250., screen_height * 0.5, 1.f);
-  Object ring3(ring3_pos, ring_mesh2_, purple_);
-  ring3.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring4_pos(screen_width - 250., screen_height * 0.5, 1.f);
-  Object ring4(ring4_pos, ring_mesh2_, purple_);
-  ring4.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring5_pos(screen_width * 0.5, 0.0, 2.f);
-  Object ring5(ring5_pos, ring_mesh3_, purple_);
-  ring5.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring6_pos(screen_width * 0.5, screen_height, 2.f);
-  Object ring6(ring6_pos, ring_mesh3_, purple_);
-  ring6.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring7_pos(screen_width * 0.5, 0.0, 15.f);
-  Object ring7(ring7_pos, ring_mesh1_, purple_);
-  ring7.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring8_pos(screen_width * 0.5, screen_height, 15.f);
-  Object ring8(ring8_pos, ring_mesh1_, purple_);
-  ring8.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring7a_pos(screen_width * 0.5, 0.0, 22.f);
-  Object ring7a(ring7a_pos, ring_mesh4_, purple_);
-  ring7a.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring8a_pos(screen_width * 0.5, screen_height, 22.f);
-  Object ring8a(ring8a_pos, ring_mesh4_, purple_);
-  ring8a.set_shape_modifiers(ShapeModifier::kWobble);
-
-  std::vector<Object> objects{
-      rectangle, circle1,  circle1o, circle2, circle2o, circle3, circle3o,
-      circle4,   circle4o, ring1,    ring2,   ring3,    ring4,   ring5,
-      ring6,     ring7,    ring8,    ring1a,  ring2a,   ring7a,  ring8a};
-
-  // Create the Model
-  model_ = std::unique_ptr<escher::Model>(new escher::Model(objects));
-  model_->set_time(current_time_sec);
-
-  return model_.get();
-}
diff --git a/garnet/examples/escher/waterfall/scenes/uber_scene.h b/garnet/examples/escher/waterfall/scenes/uber_scene.h
deleted file mode 100644
index baf1935558b4f469801403c5c08ea1643b22b4d0..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/uber_scene.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_UBER_SCENE_H_
-#define GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_UBER_SCENE_H_
-
-#include "lib/escher/escher.h"
-
-#include "garnet/examples/escher/waterfall/scenes/scene.h"
-
-class UberScene : public Scene {
- public:
-  UberScene(Demo* demo);
-  ~UberScene();
-
-  void Init(escher::Stage* stage) override;
-
-  escher::Model* Update(const escher::Stopwatch& stopwatch,
-                        uint64_t frame_count, escher::Stage* stage,
-                        escher::PaperRenderer2* renderer) override;
-
- private:
-  std::unique_ptr<escher::Model> model_;
-
-  escher::MaterialPtr blue_;
-  escher::MaterialPtr red_;
-  escher::MaterialPtr purple_;
-  escher::MaterialPtr bg_;
-
-  escher::MeshPtr ring_mesh1_;
-  escher::MeshPtr ring_mesh2_;
-  escher::MeshPtr ring_mesh3_;
-  escher::MeshPtr ring_mesh4_;
-
-  FXL_DISALLOW_COPY_AND_ASSIGN(UberScene);
-};
-
-#endif  // GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_UBER_SCENE_H_
diff --git a/garnet/examples/escher/waterfall/scenes/uber_scene2.cc b/garnet/examples/escher/waterfall/scenes/uber_scene2.cc
deleted file mode 100644
index 5c9cf64c62d3f689893bd7ae118d0a77b39db565..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/uber_scene2.cc
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "garnet/examples/escher/waterfall/scenes/uber_scene2.h"
-
-#include "lib/escher/geometry/tessellation.h"
-#include "lib/escher/geometry/types.h"
-#include "lib/escher/material/material.h"
-#include "lib/escher/scene/model.h"
-#include "lib/escher/scene/stage.h"
-#include "lib/escher/shape/modifier_wobble.h"
-#include "lib/escher/util/stopwatch.h"
-#include "lib/escher/vk/image.h"
-#include "lib/escher/vk/vulkan_context.h"
-
-using escher::MeshAttribute;
-using escher::MeshSpec;
-using escher::Object;
-using escher::ShapeModifier;
-using escher::vec2;
-using escher::vec3;
-using escher::vec4;
-
-UberScene2::UberScene2(Demo* demo) : Scene(demo) {}
-
-void UberScene2::Init(escher::Stage* stage) {
-  blue_ = fxl::MakeRefCounted<escher::Material>();
-  red_ = fxl::MakeRefCounted<escher::Material>();
-  purple_ = fxl::MakeRefCounted<escher::Material>();
-  bg_ = fxl::MakeRefCounted<escher::Material>();
-  gray1_ = fxl::MakeRefCounted<escher::Material>();
-  gray2_ = fxl::MakeRefCounted<escher::Material>();
-  blue_->set_color(vec3(0.188f, 0.188f, 0.788f));
-  red_->set_color(vec3(0.98f, 0.15f, 0.15f));
-  purple_->set_color(vec3(0.588f, 0.239f, 0.729f));
-  bg_->set_color(vec3(0.8f, 0.8f, 0.8f));
-  gray1_->set_color(vec4(0.7f, 0.7f, 0.7f, 0.9f));
-  gray1_->set_opaque(false);
-  gray2_->set_color(vec4(0.4f, 0.4f, 0.4f, 0.4f));
-  gray2_->set_opaque(false);
-
-  // Create meshes for fancy wobble effect.
-  MeshSpec spec{MeshAttribute::kPosition2D | MeshAttribute::kPositionOffset |
-                MeshAttribute::kPerimeterPos | MeshAttribute::kUV};
-  ring_mesh1_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 150.f,
-                                    100.f, 18.f, -15.f);
-
-  ring_mesh2_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 300.f,
-                                    250.f, 18.f, -15.f);
-
-  ring_mesh3_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 500.f,
-                                    350.f, 18.f, -15.f);
-
-  ring_mesh4_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 700.f,
-                                    600.f, 18.f, -15.f);
-
-  ring_mesh5_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 1300.f,
-                                    1150.f, 18.f, -15.f);
-}
-
-UberScene2::~UberScene2() {}
-
-escher::Model* UberScene2::Update(const escher::Stopwatch& stopwatch,
-                                  uint64_t frame_count, escher::Stage* stage,
-                                  escher::PaperRenderer2* renderer) {
-  float current_time_sec = stopwatch.GetElapsedSeconds();
-
-  float screen_width = stage->viewing_volume().width();
-  float screen_height = stage->viewing_volume().height();
-  float min_height = 2.f;
-  float max_height = 20.f;
-
-  // animate the position along a figure-eight
-  float circle1_time_offset = 0.f;
-  float circle1_time = current_time_sec + circle1_time_offset;
-  float circle1_path_scale = 2. / (3. - cos(2. * circle1_time)) * 800.;
-  float circle1_x_pos =
-      circle1_path_scale * cos(circle1_time) + (screen_width * 0.5);
-  float circle1_y_pos =
-      circle1_path_scale * sin(2. * circle1_time) / 2. + (screen_height * 0.5);
-  float circle1_z_pos =
-      circle1_path_scale / 800. * max_height * sin(2. * circle1_time) / 2. +
-      min_height + (max_height * 0.5);
-  vec3 circle1_pos(circle1_x_pos, circle1_y_pos, circle1_z_pos);
-  Object circle1(Object::NewCircle(circle1_pos, 120.f, blue_));
-
-  float circle1o_y_pos = circle1_y_pos + (sin(circle1_time * 2) * 200.);
-  float circle1o_z_pos = circle1_z_pos + (cos(circle1_time * 2) * 3.);
-  vec3 circle1o_pos(circle1_x_pos, circle1o_y_pos, circle1o_z_pos);
-  Object circle1o(Object::NewCircle(circle1o_pos, 40.f, red_));
-
-  // animate the position along a figure-eight
-  float circle3_time_offset = 2.f;
-  float circle3_time = current_time_sec + circle3_time_offset;
-  float circle3_path_scale = 2. / (3. - cos(2. * circle3_time)) * 800.;
-  float circle3_x_pos =
-      circle3_path_scale * cos(circle3_time) + (screen_width * 0.5);
-  float circle3_y_pos =
-      circle3_path_scale * sin(2. * circle3_time) / 2. + (screen_height * 0.5);
-  float circle3_z_pos =
-      circle3_path_scale / 800. * max_height * sin(2. * circle3_time) / 2. +
-      min_height + (max_height * 0.5);
-  vec3 circle3_pos(circle3_x_pos, circle3_y_pos, circle3_z_pos);
-  Object circle3(Object::NewCircle(circle3_pos, 120.f, blue_));
-
-  float circle3o_y_pos = circle3_y_pos + (cos(circle3_time * 2) * 200.);
-  float circle3o_z_pos = circle3_z_pos + (sin(circle3_time * 2) * 3.);
-  vec3 circle3o_pos(circle3_x_pos, circle3o_y_pos, circle3o_z_pos);
-  Object circle3o(Object::NewCircle(circle3o_pos, 40.f, red_));
-
-  // animate the position along a figure-eight
-  float circle2_time_offset = 1.f;
-  float circle2_time = current_time_sec + circle2_time_offset;
-  float circle2_path_scale = 2. / (3. - cos(2. * circle2_time)) * 800.;
-  float circle2_x_pos =
-      circle2_path_scale * -sin(2. * circle2_time) / 2. + (screen_width * 0.5);
-  float circle2_y_pos =
-      circle2_path_scale * -cos(circle2_time) + (screen_height * 0.5);
-  float circle2_z_pos =
-      circle2_path_scale / 800. * max_height * sin(2. * circle2_time) / 2. +
-      min_height + (max_height * 0.5);
-  vec3 circle2_pos(circle2_x_pos, circle2_y_pos, circle2_z_pos);
-  Object circle2(Object::NewCircle(circle2_pos, 120.f, blue_));
-
-  float circle2o_x_pos = circle2_x_pos + (cos(circle2_time * 2) * 200.);
-  float circle2o_z_pos = circle2_z_pos + (sin(circle2_time * 2) * 3.);
-  vec3 circle2o_pos(circle2o_x_pos, circle2_y_pos, circle2o_z_pos);
-  Object circle2o(Object::NewCircle(circle2o_pos, 40.f, red_));
-
-  // animate the position along a figure-eight
-  float circle4_time_offset = 4.f;
-  float circle4_time = current_time_sec + circle4_time_offset;
-  float circle4_path_scale = 2. / (3. - cos(2. * circle4_time)) * 800.;
-  float circle4_x_pos =
-      circle4_path_scale * -sin(2. * circle4_time) / 2. + (screen_width * 0.5);
-  float circle4_y_pos =
-      circle4_path_scale * -cos(circle4_time) + (screen_height * 0.5);
-  float circle4_z_pos =
-      circle4_path_scale / 800. * max_height * sin(2. * circle4_time) / 2. +
-      min_height + (max_height * 0.5);
-  vec3 circle4_pos(circle4_x_pos, circle4_y_pos, circle4_z_pos);
-  Object circle4(Object::NewCircle(circle4_pos, 120.f, blue_));
-
-  float circle4o_x_pos = circle4_x_pos + (sin(circle4_time * 2) * 200.);
-  float circle4o_z_pos = circle4_z_pos + (cos(circle4_time * 2) * 3.);
-  vec3 circle4o_pos(circle4o_x_pos, circle4_y_pos, circle4o_z_pos);
-  Object circle4o(Object::NewCircle(circle4o_pos, 40.f, red_));
-
-  Object rectangle(Object::NewRect(vec3(0.f, 0.f, 1.f),
-                                   vec2(screen_width, screen_height), bg_));
-
-  vec3 ring1_pos(screen_width * 0.5, screen_height * 0.5, 10.f);
-  Object ring1(ring1_pos, ring_mesh2_, purple_);
-  ring1.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring1b_pos(screen_width * 0.5, screen_height * 0.5, 5.f);
-  Object ring1b(ring1b_pos, ring_mesh1_, purple_);
-  ring1b.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring2_pos(screen_width * 0.15, screen_height * 0.5, 10.f);
-  Object ring2(ring2_pos, ring_mesh2_, purple_);
-  ring2.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring2b_pos(screen_width * 0.15, screen_height * 0.5, 5.f);
-  Object ring2b(ring2b_pos, ring_mesh1_, purple_);
-  ring2b.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring3_pos(screen_width * 0.85, screen_height * 0.5, 10.f);
-  Object ring3(ring3_pos, ring_mesh2_, purple_);
-  ring3.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring3b_pos(screen_width * 0.85, screen_height * 0.5, 5.f);
-  Object ring3b(ring3b_pos, ring_mesh1_, purple_);
-  ring3b.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring4_pos(screen_width * 0.325, screen_height * 0.15, 2.f);
-  Object ring4(ring4_pos, ring_mesh2_, purple_);
-  ring4.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring4b_pos(screen_width * 0.325, screen_height * 0.15, 22.f);
-  Object ring4b(ring4b_pos, ring_mesh1_, purple_);
-  ring4b.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring6_pos(screen_width * 0.325, screen_height * 0.15, 22.f);
-  Object ring6(ring6_pos, ring_mesh2_, purple_);
-  ring6.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring6b_pos(screen_width * 0.325, screen_height * 0.15, 2.f);
-  Object ring6b(ring6b_pos, ring_mesh1_, purple_);
-  ring6b.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring5_pos(screen_width * 0.675, screen_height * 0.15, 2.f);
-  Object ring5(ring5_pos, ring_mesh2_, purple_);
-  ring5.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring5b_pos(screen_width * 0.675, screen_height * 0.15, 22.f);
-  Object ring5b(ring5b_pos, ring_mesh1_, purple_);
-  ring5b.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring7_pos(screen_width * 0.675, screen_height * 0.15, 22.f);
-  Object ring7(ring7_pos, ring_mesh2_, purple_);
-  ring7.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring7b_pos(screen_width * 0.675, screen_height * 0.15, 2.f);
-  Object ring7b(ring7b_pos, ring_mesh1_, purple_);
-  ring7b.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring8_pos(screen_width * 0.325, screen_height * 0.85, 23.f);
-  Object ring8(ring8_pos, ring_mesh2_, purple_);
-  ring8.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring8b_pos(screen_width * 0.325, screen_height * 0.85, 2.f);
-  Object ring8b(ring8b_pos, ring_mesh1_, purple_);
-  ring8b.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring9_pos(screen_width * 0.675, screen_height * 0.85, 23.f);
-  Object ring9(ring9_pos, ring_mesh2_, purple_);
-  ring9.set_shape_modifiers(ShapeModifier::kWobble);
-
-  vec3 ring9b_pos(screen_width * 0.675, screen_height * 0.85, 2.f);
-  Object ring9b(ring9b_pos, ring_mesh1_, purple_);
-  ring9b.set_shape_modifiers(ShapeModifier::kWobble);
-
-  std::vector<Object> objects{
-      rectangle, circle1,  circle1o, circle2, circle3, circle3o, circle2o,
-      circle4,   circle4o, ring1,    ring1b,  ring2,   ring2b,   ring3,
-      ring3b,    ring4,    ring4b,   ring5,   ring5b,  ring6,    ring6b,
-      ring7,     ring7b,   ring8,    ring8b,  ring9,   ring9b};
-
-  // Create the Model
-  model_ = std::make_unique<escher::Model>(std::move(objects));
-  model_->set_time(current_time_sec);
-
-  return model_.get();
-}
-
-escher::Model* UberScene2::UpdateOverlay(const escher::Stopwatch& stopwatch,
-                                         uint64_t frame_count, uint32_t width,
-                                         uint32_t height) {
-  const float quarter_width = static_cast<float>(width) * 0.25f;
-  const float half_height = static_cast<float>(height) * 0.5f;
-  const float radius = quarter_width * 0.9f;
-  Object circle1(Object::NewCircle(vec3(quarter_width, half_height, 24.f),
-                                   radius, gray1_));
-  Object circle2(Object::NewCircle(vec3(3.f * quarter_width, half_height, 24.f),
-                                   radius, gray2_));
-  std::vector<Object> objects{circle1, circle2};
-  overlay_model_ = std::make_unique<escher::Model>(std::move(objects));
-
-  return overlay_model_.get();
-}
diff --git a/garnet/examples/escher/waterfall/scenes/uber_scene2.h b/garnet/examples/escher/waterfall/scenes/uber_scene2.h
deleted file mode 100644
index a6713481042a6fb30915c760783ecd3f0db8b173..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/uber_scene2.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_UBER_SCENE2_H_
-#define GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_UBER_SCENE2_H_
-
-#include "lib/escher/escher.h"
-
-#include "garnet/examples/escher/waterfall/scenes/scene.h"
-
-class UberScene2 : public Scene {
- public:
-  UberScene2(Demo* demo);
-  ~UberScene2();
-
-  void Init(escher::Stage* stage) override;
-
-  escher::Model* Update(const escher::Stopwatch& stopwatch,
-                        uint64_t frame_count, escher::Stage* stage,
-                        escher::PaperRenderer2* renderer) override;
-
-  escher::Model* UpdateOverlay(const escher::Stopwatch& stopwatch,
-                               uint64_t frame_count, uint32_t width,
-                               uint32_t height) override;
-
- private:
-  std::unique_ptr<escher::Model> model_;
-  std::unique_ptr<escher::Model> overlay_model_;
-
-  escher::MaterialPtr blue_;
-  escher::MaterialPtr red_;
-  escher::MaterialPtr purple_;
-  escher::MaterialPtr bg_;
-  escher::MaterialPtr gray1_;
-  escher::MaterialPtr gray2_;
-
-  escher::MeshPtr ring_mesh1_;
-  escher::MeshPtr ring_mesh2_;
-  escher::MeshPtr ring_mesh3_;
-  escher::MeshPtr ring_mesh4_;
-  escher::MeshPtr ring_mesh5_;
-
-  FXL_DISALLOW_COPY_AND_ASSIGN(UberScene2);
-};
-
-#endif  // GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_UBER_SCENE2_H_
diff --git a/garnet/examples/escher/waterfall/scenes/uber_scene3.cc b/garnet/examples/escher/waterfall/scenes/uber_scene3.cc
deleted file mode 100644
index 166fe3b5b236454e0b667a29c67617de6993fd72..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/uber_scene3.cc
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "garnet/examples/escher/waterfall/scenes/uber_scene3.h"
-
-#include "lib/escher/geometry/tessellation.h"
-#include "lib/escher/geometry/transform.h"
-#include "lib/escher/geometry/types.h"
-#include "lib/escher/material/material.h"
-#include "lib/escher/scene/model.h"
-#include "lib/escher/scene/stage.h"
-#include "lib/escher/shape/modifier_wobble.h"
-#include "lib/escher/util/stopwatch.h"
-#include "lib/escher/vk/image.h"
-#include "lib/escher/vk/vulkan_context.h"
-
-using escher::MeshAttribute;
-using escher::MeshSpec;
-using escher::Object;
-using escher::ShapeModifier;
-using escher::Transform;
-using escher::vec2;
-using escher::vec3;
-
-UberScene3::UberScene3(Demo* demo) : Scene(demo) {}
-
-void UberScene3::Init(escher::Stage* stage) {
-  bg_ = fxl::MakeRefCounted<escher::Material>();
-  color1_ = fxl::MakeRefCounted<escher::Material>();
-  color2_ = fxl::MakeRefCounted<escher::Material>();
-  bg_->set_color(vec3(0.8f, 0.8f, 0.8f));
-  color1_->set_color(vec3(157.f / 255.f, 183.f / 255.f, 189.f / 255.f));
-  color2_->set_color(vec3(63.f / 255.f, 138.f / 255.f, 153.f / 255.f));
-
-  MeshSpec spec{MeshAttribute::kPosition2D | MeshAttribute::kPositionOffset |
-                MeshAttribute::kPerimeterPos | MeshAttribute::kUV};
-  ring_mesh_ = escher::NewRingMesh(escher(), spec, 5, vec2(0.f, 0.f), 75.f,
-                                   55.f, 18.f, -15.f);
-}
-
-UberScene3::~UberScene3() {}
-
-escher::Model* UberScene3::Update(const escher::Stopwatch& stopwatch,
-                                  uint64_t frame_count, escher::Stage* stage,
-                                  escher::PaperRenderer2* renderer) {
-  float current_time_sec = stopwatch.GetElapsedSeconds();
-
-  float screen_width = stage->viewing_volume().width();
-  float screen_height = stage->viewing_volume().height();
-  float min_height = 5.f;
-  float max_height = 30.f;
-  float elevation_range = max_height - min_height;
-
-  std::vector<Object> objects;
-
-  constexpr float PI = 3.14159265359f;
-  constexpr float TWO_PI = PI * 2.f;
-  float hex_circle_diameter = 170.f;
-  float hex_circle_radius = hex_circle_diameter / 2.0f;
-  float col_width = hex_circle_radius / tan(30.f * 180.f / PI);
-
-  float num_rows_f = screen_height / hex_circle_radius;
-  float num_cols_f = screen_width / col_width;
-
-  int num_rows = num_rows_f;
-  int num_cols = num_cols_f;
-
-  float hex_current_x_pos = 0.f;
-  float hex_current_y_pos = 0.f;
-  float hex_x_offset = 0.f;
-
-  float time_mult = 2.f;
-
-  int circle_index = 0;
-  int is_even = 0;
-
-  for (int i = 0; i <= num_rows; i++) {
-    hex_current_y_pos = i * hex_circle_diameter;
-    if (fmod(i, 2) == 0) {
-      is_even = 1;
-      hex_x_offset = hex_circle_radius;
-    } else {
-      is_even = 0;
-      hex_x_offset = 0.f;
-    }
-
-    for (int ii = 0; ii <= num_cols; ii++) {
-      float time_offset = ii * 0.2f;
-      float circle_elevation = 2.f;
-      float circle_scale =
-          (sin((current_time_sec + time_offset) * 1.25f) * .5f + .5f) * .5f +
-          .5f;
-      float circle_scale_alt =
-          (cos((current_time_sec + (time_offset * 1.25f)) * 1.5f) * .5f + .5f) *
-              .6f +
-          .5f;
-
-      hex_current_x_pos = ii * col_width + hex_x_offset;
-
-      if (is_even == 1) {
-        circle_elevation =
-            sin(current_time_sec + time_offset * time_mult) * elevation_range +
-            min_height + (elevation_range / 1.f);
-      } else {
-        circle_elevation =
-            cos(current_time_sec + time_offset * time_mult) * elevation_range +
-            min_height + (elevation_range / 1.f);
-      }
-
-      Object circle(Object::NewCircle(
-          vec3(hex_current_x_pos, hex_current_y_pos, circle_elevation),
-          hex_circle_radius * circle_scale, color2_));
-      objects.push_back(circle);
-
-      Object circle_bg(Transform(vec3(hex_current_x_pos, hex_current_y_pos,
-                                      circle_elevation - 4.f),
-                                 vec3(circle_scale_alt, circle_scale_alt, 1.f)),
-                       ring_mesh_, color1_);
-      circle_bg.set_shape_modifiers(ShapeModifier::kWobble);
-      escher::ModifierWobble wobble_data{
-          {{-0.3f * TWO_PI, 0.1f, 7.f * TWO_PI},
-           {-0.2f * TWO_PI, 0.05f, 23.f * TWO_PI},
-           {1.f * TWO_PI, 0.25f, 5.f * TWO_PI}}};
-      circle_bg.set_shape_modifier_data(wobble_data);
-      objects.push_back(circle_bg);
-
-      circle_index++;
-    }
-  }
-
-  Object rectangle(Object::NewRect(
-      vec2(0.f, 0.f), vec2(screen_width, screen_height), 1.f, bg_));
-
-  objects.push_back(rectangle);
-
-  // Create the Model
-  model_ = std::unique_ptr<escher::Model>(new escher::Model(objects));
-  model_->set_time(current_time_sec);
-
-  return model_.get();
-}
diff --git a/garnet/examples/escher/waterfall/scenes/uber_scene3.h b/garnet/examples/escher/waterfall/scenes/uber_scene3.h
deleted file mode 100644
index 8b7781b0aef6fd935afa169b40d57abe30624d85..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/uber_scene3.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_UBER_SCENE3_H_
-#define GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_UBER_SCENE3_H_
-
-#include "lib/escher/escher.h"
-
-#include "garnet/examples/escher/waterfall/scenes/scene.h"
-
-class UberScene3 : public Scene {
- public:
-  UberScene3(Demo* demo);
-  ~UberScene3();
-
-  void Init(escher::Stage* stage) override;
-
-  escher::Model* Update(const escher::Stopwatch& stopwatch,
-                        uint64_t frame_count, escher::Stage* stage,
-                        escher::PaperRenderer2* renderer) override;
-
- private:
-  std::unique_ptr<escher::Model> model_;
-
-  escher::MeshPtr ring_mesh_;
-  escher::MaterialPtr bg_;
-
-  escher::MaterialPtr color1_;
-  escher::MaterialPtr color2_;
-
-  FXL_DISALLOW_COPY_AND_ASSIGN(UberScene3);
-};
-
-#endif  // GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_UBER_SCENE3_H_
diff --git a/garnet/examples/escher/waterfall/scenes/wobbly_ocean_scene.cc b/garnet/examples/escher/waterfall/scenes/wobbly_ocean_scene.cc
deleted file mode 100644
index 6ce612b122260dee632dc9a860dbd78e642e548d..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/wobbly_ocean_scene.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "garnet/examples/escher/waterfall/scenes/wobbly_ocean_scene.h"
-
-#include "lib/escher/geometry/tessellation.h"
-#include "lib/escher/geometry/types.h"
-#include "lib/escher/material/color_utils.h"
-#include "lib/escher/material/material.h"
-#include "lib/escher/scene/model.h"
-#include "lib/escher/scene/stage.h"
-#include "lib/escher/shape/modifier_wobble.h"
-#include "lib/escher/util/stopwatch.h"
-#include "lib/escher/vk/image.h"
-#include "lib/escher/vk/vulkan_context.h"
-
-using escher::MeshAttribute;
-using escher::MeshSpec;
-using escher::Object;
-using escher::ShapeModifier;
-using escher::TexturePtr;
-using escher::vec2;
-using escher::vec3;
-
-WobblyOceanScene::WobblyOceanScene(Demo* demo) : Scene(demo) {}
-
-void WobblyOceanScene::Init(escher::Stage* stage) {
-  bg_ = fxl::MakeRefCounted<escher::Material>();
-  color1_ = fxl::MakeRefCounted<escher::Material>();
-  color2_ = fxl::MakeRefCounted<escher::Material>();
-  color3_ = fxl::MakeRefCounted<escher::Material>();
-  color4_ = fxl::MakeRefCounted<escher::Material>();
-
-  bg_->set_color(vec3(0.8f, 0.8f, 0.8f));
-  color1_->set_color(vec3(63.f / 255.f, 138.f / 255.f, 153.f / 255.f));
-  color2_->set_color(vec3(143.f / 255.f, 143.f / 255.f, 143.f / 255.f));
-  color3_->set_color(escher::SrgbToLinear(vec3(0.913f, 0.384f, 0.352f)));
-  color4_->set_color(escher::SrgbToLinear(vec3(0.286f, 0.545f, 0.607f)));
-
-  TexturePtr checkerboard = escher()->NewTexture(
-      escher()->NewCheckerboardImage(14, 4), vk::Filter::eNearest);
-  checkerboard_material_ = fxl::MakeRefCounted<escher::Material>();
-  checkerboard_material_->SetTexture(checkerboard);
-
-  checkerboard_material_->set_color(
-      escher::SrgbToLinear(vec3(.164f, .254f, 0.278f)));
-
-  // Create meshes for fancy wobble effect.
-  MeshSpec spec{MeshAttribute::kPosition2D | MeshAttribute::kPositionOffset |
-                MeshAttribute::kPerimeterPos | MeshAttribute::kUV};
-  ring_mesh1_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 300.f,
-                                    250.f, 18.f, -15.f);
-  ring_mesh2_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 200.f,
-                                    150.f, 11.f, -8.f);
-  ring_mesh3_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 100.f,
-                                    50.f, 5.f, -2.f);
-
-  // Make this mesh the size of the stage
-  float screenWidth = stage->viewing_volume().width();
-  float screenHeight = stage->viewing_volume().height();
-
-  // Make this mesh the size of the stage
-  wobbly_ocean_mesh_ = escher::NewRectangleMesh(
-      escher(), spec, 8, vec2(screenWidth, screenHeight * 0.5f), vec2(0.f, 0.f),
-      18.f, 0.f);
-}
-
-WobblyOceanScene::~WobblyOceanScene() {}
-
-escher::Model* WobblyOceanScene::Update(
-    const escher::Stopwatch& stopwatch, uint64_t frame_count,
-    escher::Stage* stage, escher::PaperRenderer2* renderer) {
-  float current_time_sec = stopwatch.GetElapsedSeconds();
-
-  float screenWidth = stage->viewing_volume().width();
-  float screenHeight = stage->viewing_volume().height();
-  float minElevation = stage->viewing_volume().bottom();
-  float maxElevation = stage->viewing_volume().top();
-  float elevationRange = maxElevation - minElevation;
-
-  std::vector<Object> objects;
-
-  vec3 ring_pos(screenWidth * 0.5, screenHeight * 0.5, 10.f);
-  Object ring1(ring_pos + vec3(0, 0, 4.f), ring_mesh1_, color4_);
-  ring1.set_shape_modifiers(ShapeModifier::kWobble);
-  Object ring2(ring_pos + vec3(75., 0, 12.f), ring_mesh2_, color1_);
-  ring2.set_shape_modifiers(ShapeModifier::kWobble);
-  Object ring3(ring_pos + vec3(-125.0, 0, 24.f), ring_mesh3_, color3_);
-  ring3.set_shape_modifiers(ShapeModifier::kWobble);
-
-  constexpr float TWO_PI = 6.28318530718f;
-  escher::ModifierWobble wobble_data1{{{-0.3f * TWO_PI, 0.4f, 7.f * TWO_PI},
-                                       {-0.15 * TWO_PI, 0.2, 14.f * TWO_PI},
-                                       {0 * TWO_PI, 0, 0 * TWO_PI}}};
-  escher::ModifierWobble wobble_data2{{{0.3f * TWO_PI, 0.5f, 10.f * TWO_PI},
-                                       {0.15f * TWO_PI, 0.3f, 15.f * TWO_PI},
-                                       {0.2f * TWO_PI, 0.2f, 18.f * TWO_PI}}};
-  escher::ModifierWobble wobble_data3{{{-0.6f * TWO_PI, 1.2f, 12.f * TWO_PI},
-                                       {-.3f * TWO_PI, 0.8f, 8.f * TWO_PI},
-                                       {0.4 * TWO_PI, 0.5, 15.f * TWO_PI}}};
-  ring1.set_shape_modifier_data(wobble_data1);
-  ring2.set_shape_modifier_data(wobble_data2);
-  ring3.set_shape_modifier_data(wobble_data3);
-
-  objects.push_back(ring1);
-  objects.push_back(ring2);
-  objects.push_back(ring3);
-
-  escher::ModifierWobble ocean_wobble_data{
-      {{-0.1f * TWO_PI, 0.75f, 7.f * TWO_PI},
-       {-.2f * TWO_PI, .3f, 12.f * TWO_PI},
-       {-.5f * TWO_PI, .1f, 16.f * TWO_PI}}};
-
-  // Create a wobbly rectangle
-  Object ocean_rect1(vec3(0.f, screenHeight * 0.65f, 2.f), wobbly_ocean_mesh_,
-                     checkerboard_material_);
-  ocean_rect1.set_shape_modifiers(ShapeModifier::kWobble);
-  ocean_rect1.set_shape_modifier_data(ocean_wobble_data);
-  objects.push_back(ocean_rect1);
-
-  // Orbiting circle1
-  float circle1_orbit_radius = 275.f;
-  float circle1_x_pos = sin(current_time_sec * 0.85f) * circle1_orbit_radius +
-                        (screenWidth * 0.65f);
-  float circle1_y_pos = cos(current_time_sec * 0.85f) * circle1_orbit_radius +
-                        (screenHeight * 0.35f);
-  float circle1_elevation =
-      (sin(current_time_sec * 0.85f + 0.5f) * 0.5f + 0.5f) * elevationRange +
-      minElevation;
-  Object circle1(Object::NewCircle(
-      vec3(circle1_x_pos, circle1_y_pos, circle1_elevation), 60.f, color2_));
-  objects.push_back(circle1);
-
-  // Create our background plane
-  Object bg_plane(Object::NewRect(vec2(0.f, 0.f),
-                                  vec2(screenWidth, screenHeight), 0.f, bg_));
-
-  objects.push_back(bg_plane);
-
-  // Create the Model
-  model_ = std::unique_ptr<escher::Model>(new escher::Model(objects));
-  model_->set_time(current_time_sec);
-
-  return model_.get();
-}
diff --git a/garnet/examples/escher/waterfall/scenes/wobbly_ocean_scene.h b/garnet/examples/escher/waterfall/scenes/wobbly_ocean_scene.h
deleted file mode 100644
index 286db9e169ef9a50ddebc670a601b0f21326f8ca..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/wobbly_ocean_scene.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_WOBBLY_OCEAN_SCENE_H_
-#define GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_WOBBLY_OCEAN_SCENE_H_
-
-#include "lib/escher/escher.h"
-
-#include "garnet/examples/escher/waterfall/scenes/scene.h"
-
-class WobblyOceanScene : public Scene {
- public:
-  WobblyOceanScene(Demo* demo);
-  ~WobblyOceanScene();
-
-  void Init(escher::Stage* stage) override;
-
-  escher::Model* Update(const escher::Stopwatch& stopwatch,
-                        uint64_t frame_count, escher::Stage* stage,
-                        escher::PaperRenderer2* renderer) override;
-
- private:
-  std::unique_ptr<escher::Model> model_;
-
-  escher::MaterialPtr bg_;
-
-  escher::MaterialPtr color1_;
-  escher::MaterialPtr color2_;
-  escher::MaterialPtr color3_;
-  escher::MaterialPtr color4_;
-  escher::MaterialPtr checkerboard_material_;
-
-  escher::MeshPtr ring_mesh1_;
-  escher::MeshPtr ring_mesh2_;
-  escher::MeshPtr ring_mesh3_;
-  escher::MeshPtr wobbly_ocean_mesh_;
-
-  FXL_DISALLOW_COPY_AND_ASSIGN(WobblyOceanScene);
-};
-
-#endif  // GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_WOBBLY_OCEAN_SCENE_H_
diff --git a/garnet/examples/escher/waterfall/scenes/wobbly_rings_scene.cc b/garnet/examples/escher/waterfall/scenes/wobbly_rings_scene.cc
deleted file mode 100644
index c79d910563f272a9a2bc302db79f330f995ca9b1..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/wobbly_rings_scene.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "garnet/examples/escher/waterfall/scenes/wobbly_rings_scene.h"
-
-#include "lib/escher/geometry/tessellation.h"
-#include "lib/escher/geometry/types.h"
-#include "lib/escher/material/material.h"
-#include "lib/escher/scene/model.h"
-#include "lib/escher/scene/stage.h"
-#include "lib/escher/shape/modifier_wobble.h"
-#include "lib/escher/util/stopwatch.h"
-#include "lib/escher/vk/image.h"
-#include "lib/escher/vk/vulkan_context.h"
-
-using escher::MeshAttribute;
-using escher::MeshSpec;
-using escher::Object;
-using escher::ShapeModifier;
-using escher::TexturePtr;
-using escher::vec2;
-using escher::vec3;
-
-const float kRectYPos = 40.f;
-
-WobblyRingsScene::WobblyRingsScene(Demo* demo, vec3 clear_color,
-                                   vec3 ring1_color, vec3 ring2_color,
-                                   vec3 ring3_color, vec3 circle_color,
-                                   vec3 checkerboard_color)
-    : Scene(demo), clear_color_(clear_color) {
-  ring1_color_ = fxl::MakeRefCounted<escher::Material>();
-  ring2_color_ = fxl::MakeRefCounted<escher::Material>();
-  ring3_color_ = fxl::MakeRefCounted<escher::Material>();
-  circle_color_ = fxl::MakeRefCounted<escher::Material>();
-  clip_color_ = fxl::MakeRefCounted<escher::Material>();
-  checkerboard_material_ = fxl::MakeRefCounted<escher::Material>();
-
-  ring1_color_->set_color(ring1_color);
-  ring2_color_->set_color(ring2_color);
-  ring3_color_->set_color(ring3_color);
-  circle_color_->set_color(circle_color);
-  vec3 clip_color = circle_color * 0.8f;
-  clip_color_->set_color(clip_color);
-  checkerboard_material_->set_color(checkerboard_color);
-}
-
-void WobblyRingsScene::Init(escher::Stage* stage) {
-  // Create meshes for fancy wobble effect.
-  MeshSpec spec{MeshAttribute::kPosition2D | MeshAttribute::kPositionOffset |
-                MeshAttribute::kPerimeterPos | MeshAttribute::kUV};
-  ring_mesh1_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 300.f,
-                                    250.f, 18.f, -15.f);
-  ring_mesh2_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 200.f,
-                                    150.f, 11.f, -8.f);
-  ring_mesh3_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 100.f,
-                                    50.f, 5.f, -2.f);
-
-  // Make this mesh the size of the stage
-  float screenWidth = stage->viewing_volume().width();
-  float screenHeight = stage->viewing_volume().height();
-  wobbly_rect_mesh_ = escher::NewRectangleMesh(
-      escher(), spec, 2, vec2(screenWidth, screenHeight - kRectYPos),
-      vec2(0.f, 0.f), 18.f, 0.f);
-
-  // Create materials.
-  TexturePtr checkerboard = escher()->NewTexture(
-      escher()->NewCheckerboardImage(16, 16), vk::Filter::eNearest);
-  auto checkerboard_color = checkerboard_material_->color();
-  checkerboard_material_ = fxl::MakeRefCounted<escher::Material>();
-  checkerboard_material_->SetTexture(checkerboard);
-  checkerboard_material_->set_color(checkerboard_color);
-}
-
-WobblyRingsScene::~WobblyRingsScene() {}
-
-escher::Model* WobblyRingsScene::Update(
-    const escher::Stopwatch& stopwatch, uint64_t frame_count,
-    escher::Stage* stage, escher::PaperRenderer2* renderer) {
-  stage->set_clear_color(clear_color_);
-  float current_time_sec = stopwatch.GetElapsedSeconds();
-
-  vec2 center(stage->viewing_volume().width() / 2.f,
-              stage->viewing_volume().height() / 2.f);
-
-  Object circle1(Object::NewCircle(center + vec2(100.f, -300.f), 200.f, 8.f,
-                                   circle_color_));
-  Object circle2(Object::NewCircle(center + vec2(-100.f, 268.f), 200.f, 8.f,
-                                   circle_color_));
-  Object circle3(Object::NewCircle(center + vec2(-350.f, -100.f), 120.f, 15.f,
-                                   circle_color_));
-  Object circle4(Object::NewCircle(center + vec2(338.f, 88.f), 120.f, 15.f,
-                                   circle_color_));
-
-  // Animate the position of the rings, using a cos and sin function applied
-  // to time
-  float x_pos_offset = cos(current_time_sec * 0.4f) * 200.;
-  float y_pos_offset = sin(current_time_sec) * 100.;
-  vec3 ring_pos(center + vec2(x_pos_offset, y_pos_offset), 0);
-
-  Object ring1(ring_pos + vec3(0, 0, 4.f), ring_mesh1_, ring1_color_);
-  ring1.set_shape_modifiers(ShapeModifier::kWobble);
-  Object ring2(ring_pos + vec3(0, 0, 12.f), ring_mesh2_, ring2_color_);
-  ring2.set_shape_modifiers(ShapeModifier::kWobble);
-  Object ring3(ring_pos + vec3(0, 0, 24.f), ring_mesh3_, ring3_color_);
-  ring3.set_shape_modifiers(ShapeModifier::kWobble);
-
-  constexpr float TWO_PI = 6.28318530718f;
-  escher::ModifierWobble wobble_data{{{-0.3f * TWO_PI, 0.4f, 7.f * TWO_PI},
-                                      {-0.2f * TWO_PI, 0.2f, 23.f * TWO_PI},
-                                      {1.f * TWO_PI, 0.6f, 5.f * TWO_PI}}};
-  ring1.set_shape_modifier_data(wobble_data);
-  ring2.set_shape_modifier_data(wobble_data);
-  ring3.set_shape_modifier_data(wobble_data);
-
-  // Create two circles that will be part of a clip group.  One draws a
-  // background, and is orbited by a smaller circle that doesn't draw a
-  // background.
-  Object clip_circle1(Object::NewCircle(
-      center - vec2(x_pos_offset, y_pos_offset), 400.f, 2.f, clip_color_));
-  x_pos_offset += cos(current_time_sec * 2.f) * 420.f;
-  y_pos_offset += sin(current_time_sec * 2.f) * 420.f;
-  Object clip_circle2(Object::NewCircle(
-      center - vec2(x_pos_offset, y_pos_offset), 180.f, 2.f, nullptr));
-
-  // Create a clip group where the two clip-circles are used to clip some of
-  // the other objects defined above.
-  Object clip_group({clip_circle1, clip_circle2},
-                    {ring1, ring2, ring3, circle1, circle2});
-
-// Create a wobbly rectangle
-#if 0
-  Object rectangle(wobbly_rect_mesh_, vec3(0.f, kRectYPos, 0.f),
-                   checkerboard_material_);
-  rectangle.set_shape_modifiers(ShapeModifier::kWobble);
-  rectangle.set_shape_modifier_data(wobble_data);
-#else
-  Object rectangle(Object::NewRect(
-      vec2(0.f, 0.f),
-      vec2(stage->viewing_volume().width(), stage->viewing_volume().height()),
-      0.f, checkerboard_material_));
-#endif
-
-  std::vector<Object> objects{std::move(clip_group), circle3, circle4,
-                              rectangle};
-
-  // Create the Model
-  model_ = std::unique_ptr<escher::Model>(new escher::Model(objects));
-  model_->set_time(current_time_sec);
-
-  return model_.get();
-}
diff --git a/garnet/examples/escher/waterfall/scenes/wobbly_rings_scene.h b/garnet/examples/escher/waterfall/scenes/wobbly_rings_scene.h
deleted file mode 100644
index 2338f56539b30e9f93afbd6e3acacb53da32194b..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall/scenes/wobbly_rings_scene.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_WOBBLY_RINGS_SCENE_H_
-#define GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_WOBBLY_RINGS_SCENE_H_
-
-#include "lib/escher/escher.h"
-
-#include "garnet/examples/escher/waterfall/scenes/scene.h"
-#include "lib/escher/geometry/types.h"
-
-using escher::vec3;
-
-class WobblyRingsScene : public Scene {
- public:
-  WobblyRingsScene(Demo* demo, vec3 clear_color, vec3 ring1_color,
-                   vec3 ring2_color, vec3 ring3_color, vec3 circle_color,
-                   vec3 checkerboard_color);
-  ~WobblyRingsScene();
-
-  void Init(escher::Stage* stage) override;
-
-  escher::Model* Update(const escher::Stopwatch& stopwatch,
-                        uint64_t frame_count, escher::Stage* stage,
-                        escher::PaperRenderer2* renderer) override;
-
- private:
-  std::unique_ptr<escher::Model> model_;
-
-  vec3 clear_color_;
-  escher::MeshPtr ring_mesh1_;
-  escher::MeshPtr ring_mesh2_;
-  escher::MeshPtr ring_mesh3_;
-  escher::MeshPtr wobbly_rect_mesh_;
-  escher::MaterialPtr circle_color_;
-  escher::MaterialPtr clip_color_;
-  escher::MaterialPtr ring1_color_;
-  escher::MaterialPtr ring2_color_;
-  escher::MaterialPtr ring3_color_;
-  escher::MaterialPtr checkerboard_material_;
-
-  FXL_DISALLOW_COPY_AND_ASSIGN(WobblyRingsScene);
-};
-
-#endif  // GARNET_EXAMPLES_ESCHER_WATERFALL_SCENES_WOBBLY_RINGS_SCENE_H_
diff --git a/garnet/examples/escher/waterfall/waterfall_demo.cc b/garnet/examples/escher/waterfall/waterfall_demo.cc
index 91f37cec00cc84fc6cc2049918e716bd696cfab6..568a7621b09f65e523a46aa6b0dab1fbcfcaa8e0 100644
--- a/garnet/examples/escher/waterfall/waterfall_demo.cc
+++ b/garnet/examples/escher/waterfall/waterfall_demo.cc
@@ -1,74 +1,91 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "garnet/examples/escher/waterfall/waterfall_demo.h"
 
-#include "garnet/examples/escher/waterfall/scenes/demo_scene.h"
-#include "garnet/examples/escher/waterfall/scenes/ring_tricks1.h"
-#include "garnet/examples/escher/waterfall/scenes/ring_tricks2.h"
-#include "garnet/examples/escher/waterfall/scenes/ring_tricks3.h"
-#include "garnet/examples/escher/waterfall/scenes/uber_scene.h"
-#include "garnet/examples/escher/waterfall/scenes/uber_scene2.h"
-#include "garnet/examples/escher/waterfall/scenes/uber_scene3.h"
-#include "garnet/examples/escher/waterfall/scenes/wobbly_ocean_scene.h"
-#include "garnet/examples/escher/waterfall/scenes/wobbly_rings_scene.h"
-#include "lib/escher/renderer/shadow_map.h"
+#include "garnet/examples/escher/waterfall/scenes/paper_demo_scene1.h"
+#include "lib/escher/defaults/default_shader_program_factory.h"
+#include "lib/escher/geometry/tessellation.h"
+#include "lib/escher/paper/paper_scene.h"
+#include "lib/escher/paper/paper_shader_structs.h"
 #include "lib/escher/scene/camera.h"
+#include "lib/escher/scene/viewing_volume.h"
+#include "lib/escher/shape/mesh.h"
+#include "lib/escher/util/enum_utils.h"
+#include "lib/escher/util/trace_macros.h"
+#include "lib/escher/vk/shader_module_template.h"
+#include "lib/escher/vk/shader_program.h"
+#include "lib/escher/vk/texture.h"
 
-// Material design places objects from 0.0f to 24.0f.
-static constexpr float kNear = 100.f;
-static constexpr float kFar = -1.f;
+using namespace escher;
 
-// Directional light is 50% intensity; ambient light will adjust automatically.
-static constexpr float kLightIntensity = 0.5f;
-
-// Directional light parameters.
-static constexpr float kLightDispersion = M_PI * 0.15f;
-static constexpr float kLightElevationRadians = M_PI / 3.f;
+static constexpr float kNear = 1.f;
+static constexpr float kFar = -200.f;
 
 WaterfallDemo::WaterfallDemo(DemoHarness* harness, int argc, char** argv)
-    : Demo(harness, "Waterfall Demo"),
-      renderer_(escher::PaperRenderer::New(GetEscherWeakPtr())),
-      shadow_renderer_(escher::ShadowMapRenderer::New(
-          GetEscherWeakPtr(), renderer_->model_data(),
-          renderer_->model_renderer())),
-      moment_shadow_renderer_(escher::MomentShadowMapRenderer::New(
-          GetEscherWeakPtr(), renderer_->model_data(),
-          renderer_->model_renderer())) {
+    : Demo(harness, "Waterfall Demo") {
   ProcessCommandLineArgs(argc, argv);
-  InitializeEscherStage(harness->GetWindowParams());
+
+  // Initialize filesystem with files before creating renderer; it will use them
+  // to generate the necessary ShaderPrograms.
+  escher()->shader_program_factory()->filesystem()->InitializeWithRealFiles(
+      {"shaders/model_renderer/main.frag", "shaders/model_renderer/main.vert",
+       "shaders/model_renderer/default_position.vert",
+       "shaders/model_renderer/shadow_map_generation.frag",
+       "shaders/model_renderer/shadow_map_lighting.frag",
+       "shaders/model_renderer/wobble_position.vert",
+       "shaders/paper/common/use.glsl",
+       "shaders/paper/frag/main_ambient_light.frag",
+       "shaders/paper/frag/main_point_light.frag",
+       "shaders/paper/vert/compute_model_space_position.vert",
+       "shaders/paper/vert/compute_world_space_position.vert",
+       "shaders/paper/vert/main_shadow_volume_extrude.vert",
+       "shaders/paper/vert/vertex_attributes.vert"});
+
+  renderer_ = escher::PaperRenderer2::New(GetEscherWeakPtr());
+
+  renderer_config_.shadow_type = PaperRendererShadowType::kShadowVolume;
+  renderer_config_.msaa_sample_count = 2;
+  renderer_config_.num_depth_buffers =
+      harness->GetVulkanSwapchain().images.size();
+  renderer_->SetConfig(renderer_config_);
+
+  InitializePaperScene(harness->GetWindowParams());
   InitializeDemoScenes();
 }
 
 WaterfallDemo::~WaterfallDemo() {
-  // Print out FPS stats.  Omit the first frame when computing the average,
-  // because it is generating pipelines.
-  auto microseconds = stopwatch_.GetElapsedMicroseconds();
-  double fps = (frame_count() - 1) * 1000000.0 /
-               (microseconds - first_frame_microseconds_);
-  FXL_LOG(INFO) << "Average frame rate: " << fps;
+  FXL_LOG(INFO) << "Average frame rate: " << ComputeFps();
   FXL_LOG(INFO) << "First frame took: " << first_frame_microseconds_ / 1000.0
                 << " milliseconds";
 
   escher()->Cleanup();
 }
 
+void WaterfallDemo::InitializePaperScene(
+    const DemoHarness::WindowParams& window_params) {
+  paper_scene_ = fxl::MakeRefCounted<PaperScene>();
+
+  // Number of lights can be cycled via keyboard event.  Light positions and
+  // colors are animated by UpdateLighting().
+  paper_scene_->point_lights.resize(1);
+
+  paper_scene_->bounding_box = escher::BoundingBox(
+      vec3(0.f, 0.f, kFar),
+      vec3(window_params.width, window_params.height, kNear));
+}
+
+void WaterfallDemo::InitializeDemoScenes() {
+  demo_scenes_.emplace_back(new PaperDemoScene1(this));
+  for (auto& scene : demo_scenes_) {
+    scene->Init(paper_scene_.get());
+  }
+}
+
 void WaterfallDemo::ProcessCommandLineArgs(int argc, char** argv) {
   for (int i = 1; i < argc; ++i) {
-    if (!strcmp("--scene", argv[i])) {
-      if (i == argc - 1) {
-        FXL_LOG(ERROR) << "--scene must be followed by a numeric argument";
-      } else {
-        char* end;
-        int scene = strtol(argv[i + 1], &end, 10);
-        if (argv[i + 1] == end) {
-          FXL_LOG(ERROR) << "--scene must be followed by a numeric argument";
-        } else {
-          current_scene_ = scene;
-        }
-      }
-    } else if (!strcmp("--debug", argv[i])) {
+    if (!strcmp("--debug", argv[i])) {
       show_debug_info_ = true;
     } else if (!strcmp("--no-debug", argv[i])) {
       show_debug_info_ = false;
@@ -76,92 +93,82 @@ void WaterfallDemo::ProcessCommandLineArgs(int argc, char** argv) {
   }
 }
 
-void WaterfallDemo::InitializeEscherStage(
-    const DemoHarness::WindowParams& window_params) {
-  stage_.set_viewing_volume(escher::ViewingVolume(
-      window_params.width, window_params.height, kNear, kFar));
-  stage_.set_key_light(
-      escher::DirectionalLight(escher::vec2(1.5f * M_PI, 1.5f * M_PI),
-                               0.15f * M_PI, vec3(kLightIntensity)));
-  stage_.set_fill_light(escher::AmbientLight(1.f - kLightIntensity));
-}
-
-void WaterfallDemo::InitializeDemoScenes() {
-  scenes_.emplace_back(new RingTricks2(this));
-  scenes_.emplace_back(new UberScene3(this));
-  scenes_.emplace_back(new WobblyOceanScene(this));
-  scenes_.emplace_back(new WobblyRingsScene(
-      this, vec3(0.012, 0.047, 0.427), vec3(0.929f, 0.678f, 0.925f),
-      vec3(0.259f, 0.956f, 0.667), vec3(0.039f, 0.788f, 0.788f),
-      vec3(0.188f, 0.188f, 0.788f), vec3(0.588f, 0.239f, 0.729f)));
-  scenes_.emplace_back(new UberScene2(this));
-  scenes_.emplace_back(new RingTricks3(this));
-  // scenes_.emplace_back(new RingTricks1(this));
-
-  const int kNumColorsInScheme = 4;
-  vec3 color_schemes[4][kNumColorsInScheme]{
-      {vec3(0.565, 0.565, 0.560), vec3(0.868, 0.888, 0.438),
-       vec3(0.905, 0.394, 0.366), vec3(0.365, 0.376, 0.318)},
-      {vec3(0.299, 0.263, 0.209), vec3(0.986, 0.958, 0.553),
-       vec3(0.773, 0.750, 0.667), vec3(0.643, 0.785, 0.765)},
-      {vec3(0.171, 0.245, 0.120), vec3(0.427, 0.458, 0.217),
-       vec3(0.750, 0.736, 0.527), vec3(0.366, 0.310, 0.280)},
-      {vec3(0.170, 0.255, 0.276), vec3(0.300, 0.541, 0.604),
-       vec3(0.637, 0.725, 0.747), vec3(0.670, 0.675, 0.674)},
-  };
-  for (auto& color_scheme : color_schemes) {
-    // Convert colors from sRGB
-    for (int i = 0; i < kNumColorsInScheme; i++) {
-      color_scheme[i] = escher::SrgbToLinear(color_scheme[i]);
-    }
-
-    // Create a new scheme with each color scheme
-    scenes_.emplace_back(new WobblyRingsScene(
-        this, color_scheme[0], color_scheme[1], color_scheme[1],
-        color_scheme[1], color_scheme[2], color_scheme[3]));
-  }
-  for (auto& scene : scenes_) {
-    scene->Init(&stage_);
-  }
-}
-
 bool WaterfallDemo::HandleKeyPress(std::string key) {
   if (key.size() > 1) {
     if (key == "SPACE") {
-      shadow_mode_ = static_cast<ShadowMode>((shadow_mode_ + 1) %
-                                             ShadowMode::kNumShadowModes);
+      // Start/stop the animation stopwatch.
+      animation_stopwatch_.Toggle();
       return true;
     }
     return Demo::HandleKeyPress(key);
   } else {
     char key_char = key[0];
     switch (key_char) {
-      case 'A':
-        enable_ssdo_acceleration_ = !enable_ssdo_acceleration_;
-        FXL_LOG(INFO) << "Enable SSDO acceleration: "
-                      << (enable_ssdo_acceleration_ ? "true" : "false");
-        return true;
-      case 'B':
-        set_run_offscreen_benchmark();
-        return true;
-      case 'C':
-        camera_projection_mode_ = (camera_projection_mode_ + 1) % 3;
-        FXL_LOG(INFO) << "Camera projection mode: " << camera_projection_mode_;
+      // Cycle through camera projection modes.
+      case 'C': {
+        camera_projection_mode_ = (camera_projection_mode_ + 1) % 5;
+        const char* kCameraModeStrings[5] = {
+            "orthographic",
+            "perspective",
+            "tilted perspective",
+            "tilted perspective from corner",
+            "stereo",
+        };
+        FXL_LOG(INFO) << "Camera projection mode: "
+                      << kCameraModeStrings[camera_projection_mode_];
         return true;
-      case 'D':
+      }
+      // Toggle display of debug information.
+      case 'D': {
         show_debug_info_ = !show_debug_info_;
+        renderer_config_.debug = show_debug_info_;
+        FXL_LOG(INFO) << "WaterfallDemo "
+                      << (show_debug_info_ ? "enabled" : "disabled")
+                      << " debugging.";
+        renderer_->SetConfig(renderer_config_);
         return true;
-      case 'M':
-        stop_time_ = !stop_time_;
+      }
+      case 'L': {
+        uint32_t num_point_lights = (paper_scene_->num_point_lights() + 1) % 3;
+        paper_scene_->point_lights.resize(num_point_lights);
+        FXL_LOG(INFO) << "WaterfallDemo number of point lights: "
+                      << paper_scene_->num_point_lights();
         return true;
-      case 'P':
-        set_enable_gpu_logging(true);
+      }
+      // Cycle through MSAA sample counts.
+      case 'M': {
+        auto sample_count = renderer_config_.msaa_sample_count;
+        if (sample_count == 1) {
+          sample_count = 2;
+        } else if (sample_count == 2) {
+          // TODO(ES-156): there seems to be a RenderPass-caching bug where if
+          // we change the RenderPassInfo's images to have a different sample
+          // count, then the old cached RenderPass is not flushed from the
+          // cache.  For now, just toggle between two values.
+          sample_count = 1;
+          // sample_count = 4;
+        } else {
+          sample_count = 1;
+        }
+        FXL_LOG(INFO) << "MSAA sample count: " << sample_count;
+        renderer_config_.msaa_sample_count = sample_count;
+        renderer_->SetConfig(renderer_config_);
         return true;
-      case 'S':
-        sort_by_pipeline_ = !sort_by_pipeline_;
-        FXL_LOG(INFO) << "Sort object by pipeline: "
-                      << (sort_by_pipeline_ ? "true" : "false");
+      }
+      // Cycle through shadow algorithms..
+      case 'S': {
+        auto& shadow_type = renderer_config_.shadow_type;
+        shadow_type = EnumCycle(shadow_type);
+        while (!renderer_->SupportsShadowType(shadow_type)) {
+          FXL_LOG(INFO) << "WaterfallDemo skipping unsupported shadow type: "
+                        << shadow_type;
+          shadow_type = EnumCycle(shadow_type);
+        }
+        renderer_->SetConfig(renderer_config_);
+        FXL_LOG(INFO) << "WaterfallDemo changed shadow type: "
+                      << renderer_config_;
         return true;
+      }
       case '1':
       case '2':
       case '3':
@@ -173,7 +180,7 @@ bool WaterfallDemo::HandleKeyPress(std::string key) {
       case '9':
       case '0':
         current_scene_ =
-            (scenes_.size() + (key_char - '0') - 1) % scenes_.size();
+            (demo_scenes_.size() + (key_char - '0') - 1) % demo_scenes_.size();
         FXL_LOG(INFO) << "Current scene index: " << current_scene_;
         return true;
       default:
@@ -182,108 +189,182 @@ bool WaterfallDemo::HandleKeyPress(std::string key) {
   }
 }
 
-static escher::Camera GenerateCamera(int camera_projection_mode,
-                                     const escher::ViewingVolume& volume) {
+// Helper function for DrawFrame().
+static std::vector<escher::Camera> GenerateCameras(
+    int camera_projection_mode, const escher::ViewingVolume& volume,
+    const escher::FramePtr& frame) {
   switch (camera_projection_mode) {
-    case 0:
-      return escher::Camera::NewOrtho(volume);
-
-    case 1:
-      return escher::Camera::NewPerspective(
-          volume,
-          glm::translate(
-              vec3(-volume.width() / 2, -volume.height() / 2, -10000)),
-          glm::radians(8.f));
+    // Orthographic full-screen.
+    case 0: {
+      return {escher::Camera::NewOrtho(volume)};
+    }
+    // Perspective where floor plane is full-screen, and parallel to screen.
+    case 1: {
+      vec3 eye(volume.width() / 2, volume.height() / 2, -10000);
+      vec3 target(volume.width() / 2, volume.height() / 2, 0);
+      vec3 up(0, -1, 0);
+      return {escher::Camera::NewPerspective(
+          volume, glm::lookAt(eye, target, up), glm::radians(8.f))};
+    }
+    // Perspective from tilted viewpoint (from x-center of stage).
     case 2: {
-      vec3 eye(volume.width() / 3, 6000, 3000);
+      vec3 eye(volume.width() / 2, 6000, -2000);
+      vec3 target(volume.width() / 2, volume.height() / 2, 0);
+      vec3 up(0, -1, 0);
+      return {escher::Camera::NewPerspective(
+          volume, glm::lookAt(eye, target, up), glm::radians(15.f))};
+    } break;
+    // Perspective from tilted viewpoint (from corner).
+    case 3: {
+      vec3 eye(volume.width() / 3, 6000, -3000);
       vec3 target(volume.width() / 2, volume.height() / 3, 0);
-      vec3 up(0, 1, 0);
-      return escher::Camera::NewPerspective(
-          volume, glm::lookAt(eye, target, up), glm::radians(15.f));
+      vec3 up(0, -1, 0);
+      return {escher::Camera::NewPerspective(
+          volume, glm::lookAt(eye, target, up), glm::radians(15.f))};
+    } break;
+    // Stereo/Perspective from tilted viewpoint (from corner).  This also
+    // demonstrates the ability to provide the view-projection matrix in a
+    // buffer instead of having the PaperRenderer2 upload the vp-matrix itself.
+    // This is typically used with a "pose buffer" in HMD applications.
+    // NOTE: the camera's transform must be fairly close to what will be read
+    // from the pose buffer, because the camera's position is used for z-sorting
+    // etc.
+    case 4: {
+      vec3 eye(volume.width() / 2, 6000, -3500);
+      vec3 eye_offset(40.f, 0.f, 0.f);
+      vec3 target(volume.width() / 2, volume.height() / 2, 0);
+      vec3 up(0, -1, 0);
+      float fov = glm::radians(15.f);
+      auto left_camera = escher::Camera::NewPerspective(
+          volume, glm::lookAt(eye - eye_offset, target, up), fov);
+      auto right_camera = escher::Camera::NewPerspective(
+          volume, glm::lookAt(eye + eye_offset, target, up), fov);
+
+      // Obtain a buffer and populate it as though it were obtained by invoking
+      // PoseBufferLatchingShader.
+      auto binding = escher::NewPaperShaderUniformBinding<
+          escher::PaperShaderLatchedPoseBuffer>(frame);
+      binding.first->vp_matrix[0] =
+          left_camera.projection() * left_camera.transform();
+      binding.first->vp_matrix[1] =
+          right_camera.projection() * right_camera.transform();
+      escher::BufferPtr latched_pose_buffer(binding.second.buffer);
+
+      // Both cameras use the same buffer, but index into it using a different
+      // eye index.  NOTE: if you comment these lines out, there will be no
+      // visible difference, because PaperRenderer2 will compute/upload the same
+      // project * transform matrix.  What would happen if you swap the kLeft
+      // and kRight?
+      left_camera.SetLatchedPoseBuffer(latched_pose_buffer,
+                                       escher::CameraEye::kLeft);
+      right_camera.SetLatchedPoseBuffer(latched_pose_buffer,
+                                        escher::CameraEye::kRight);
+
+      left_camera.SetViewport({0.f, 0.25f, 0.5f, 0.5f});
+      right_camera.SetViewport({0.5f, 0.25f, 0.5f, 0.5f});
+      return {left_camera, right_camera};
     } break;
     default:
       // Should not happen.
       FXL_DCHECK(false);
-      return escher::Camera::NewOrtho(volume);
+      return {escher::Camera::NewOrtho(volume)};
   }
 }
 
-void WaterfallDemo::DrawFrame(const escher::FramePtr& frame,
-                              const escher::ImagePtr& output_image) {
-  current_scene_ = current_scene_ % scenes_.size();
-  auto& scene = scenes_.at(current_scene_);
-  escher::Model* model = scene->Update(stopwatch_, frame_count(), &stage_);
-  escher::Model* overlay_model = scene->UpdateOverlay(
-      stopwatch_, frame_count(), output_image->width(), output_image->height());
-
-  renderer_->set_show_debug_info(show_debug_info_);
-  renderer_->set_sort_by_pipeline(sort_by_pipeline_);
-  renderer_->set_enable_ssdo_acceleration(enable_ssdo_acceleration_);
-  switch (shadow_mode_) {
-    case ShadowMode::kNone:
-      renderer_->set_shadow_type(escher::PaperRendererShadowType::kNone);
-      break;
-    case ShadowMode::kSsdo:
-      renderer_->set_shadow_type(escher::PaperRendererShadowType::kSsdo);
-      break;
-    case ShadowMode::kShadowMap:
-      renderer_->set_shadow_type(escher::PaperRendererShadowType::kShadowMap);
-      break;
-    case ShadowMode::kMomentShadowMap:
-      renderer_->set_shadow_type(
-          escher::PaperRendererShadowType::kMomentShadowMap);
-      break;
-    default:
-      FXL_LOG(ERROR) << "Invalid shadow_mode_: " << shadow_mode_;
-      shadow_mode_ = ShadowMode::kNone;
-      renderer_->set_shadow_type(escher::PaperRendererShadowType::kNone);
+static void UpdateLighting(PaperScene* paper_scene,
+                           const escher::Stopwatch& stopwatch,
+                           PaperRendererShadowType shadow_type) {
+  const size_t num_point_lights = paper_scene->num_point_lights();
+  if (num_point_lights == 0 || shadow_type == PaperRendererShadowType::kNone) {
+    paper_scene->ambient_light.color = vec3(1, 1, 1);
+    return;
   }
 
-  escher::Camera camera =
-      GenerateCamera(camera_projection_mode_, stage_.viewing_volume());
+  // Set the ambient light to an arbitrary value that looks OK.  The intensities
+  // of the point lights will be chosen so that the total light intensity on an
+  // unshadowed fragment is vec3(1,1,1).
+  const vec3 kAmbientLightColor(0.4f, 0.5f, 0.5f);
+  paper_scene->ambient_light.color = kAmbientLightColor;
 
-  if (stop_time_) {
-    stopwatch_.Stop();
-  } else {
-    stopwatch_.Start();
-  }
+  for (auto& pl : paper_scene->point_lights) {
+    pl.color =
+        (vec3(1.f, 1.f, 1.f) - kAmbientLightColor) / float(num_point_lights);
 
-  if (animate_light_) {
-    light_azimuth_radians_ += 0.02;
+    // Choose a light intensity that looks good with the falloff.  If an object
+    // is too close to the light it will appear washed out.
+    // TODO(ES-170): add HDR support to address this.
+    pl.color *= 2.5f;
+    pl.falloff = 0.001f;
   }
-  vec3 light_direction = glm::normalize(vec3(-cos(light_azimuth_radians_),
-                                             -sin(light_azimuth_radians_),
-                                             -tan(kLightElevationRadians)));
-
-  stage_.set_key_light(escher::DirectionalLight(
-      escher::vec2(light_azimuth_radians_, kLightElevationRadians),
-      kLightDispersion, vec3(kLightIntensity)));
-
-  escher::ShadowMapPtr shadow_map;
-  if (shadow_mode_ == kShadowMap || shadow_mode_ == kMomentShadowMap) {
-    const vec3 directional_light_color(kLightIntensity);
-    renderer_->set_ambient_light_color(vec3(1.f) - directional_light_color);
-    const auto& shadow_renderer =
-        shadow_mode_ == kShadowMap ? shadow_renderer_ : moment_shadow_renderer_;
-    shadow_map = shadow_renderer->GenerateDirectionalShadowMap(
-        frame, stage_, *model, light_direction, directional_light_color);
+
+  // Simple animation of point light.
+  const float width = paper_scene->width();
+  const float height = paper_scene->height();
+  if (num_point_lights == 1) {
+    paper_scene->point_lights[0].position =
+        vec3(width * .3f, height * .3f,
+             -(800.f + 200.f * sin(stopwatch.GetElapsedSeconds() * 1.2f)));
+  } else {
+    FXL_DCHECK(num_point_lights == 2);
+
+    paper_scene->point_lights[0].position =
+        vec3(width * .3f, height * .3f,
+             -(800.f + 300.f * sin(stopwatch.GetElapsedSeconds() * 1.2f)));
+    paper_scene->point_lights[1].position =
+        vec3(width * (0.6f + 0.3f * sin(stopwatch.GetElapsedSeconds() * 0.7f)),
+             height * (0.4f + 0.2f * sin(stopwatch.GetElapsedSeconds() * 0.6f)),
+             -900.f);
+
+    // Make the light colors subtly different.
+    vec3 color_diff =
+        vec3(.02f, -.01f, .04f) * paper_scene->point_lights[0].color;
+    paper_scene->point_lights[0].color += color_diff;
+    paper_scene->point_lights[1].color -= color_diff;
   }
+}
 
-  renderer_->DrawFrame(frame, stage_, *model, camera, output_image, shadow_map,
-                       overlay_model);
+double WaterfallDemo::ComputeFps() {
+  // Omit the first frame when computing the average, because it is generating
+  // pipelines.  We subtract 2 instead of 1 because we just incremented it in
+  // DrawFrame().
+  //
+  // TODO(ES-157): This could be improved.  For example, when called from the
+  // destructor we don't know how much time has elapsed since the last
+  // DrawFrame(); it might be more accurate to subtract 1 instead of 2.  Also,
+  // on Linux the swapchain allows us to queue up many DrawFrame() calls so if
+  // we quit after a short time then the FPS will be artificially high.
+  auto microseconds = stopwatch_.GetElapsedMicroseconds();
+  return (frame_count_ - 2) * 1000000.0 /
+         (microseconds - first_frame_microseconds_);
+}
+
+void WaterfallDemo::DrawFrame(const FramePtr& frame,
+                              const ImagePtr& output_image) {
+  TRACE_DURATION("gfx", "WaterfallDemo::DrawFrame");
+
+  std::vector<Camera> cameras =
+      GenerateCameras(camera_projection_mode_,
+                      ViewingVolume(paper_scene_->bounding_box), frame);
+
+  // Animate light positions and intensities.
+  UpdateLighting(paper_scene_.get(), stopwatch_, renderer_config_.shadow_type);
+
+  renderer_->BeginFrame(frame, paper_scene_, std::move(cameras), output_image);
+  {
+    TRACE_DURATION("gfx", "WaterfallDemo::DrawFrame[scene]");
+    demo_scenes_[current_scene_]->Update(animation_stopwatch_, frame_count(),
+                                         paper_scene_.get(), renderer_.get());
+  }
+  renderer_->EndFrame();
 
-  if (frame_count() == 1) {
+  if (++frame_count_ == 1) {
     first_frame_microseconds_ = stopwatch_.GetElapsedMicroseconds();
     stopwatch_.Reset();
-  } else if (frame_count() % 200 == 0) {
+  } else if (frame_count_ % 200 == 0) {
     set_enable_gpu_logging(true);
 
-    // Print out FPS stats.  Omit the first frame when computing the
-    // average, because it is generating pipelines.
-    auto microseconds = stopwatch_.GetElapsedMicroseconds();
-    double fps = (frame_count() - 2) * 1000000.0 /
-                 (microseconds - first_frame_microseconds_);
-    FXL_LOG(INFO) << "---- Average frame rate: " << fps;
+    // Print out FPS and memory stats.
+    FXL_LOG(INFO) << "---- Average frame rate: " << ComputeFps();
     FXL_LOG(INFO) << "---- Total GPU memory: "
                   << (escher()->GetNumGpuBytesAllocated() / 1024) << "kB";
   } else {
diff --git a/garnet/examples/escher/waterfall/waterfall_demo.h b/garnet/examples/escher/waterfall/waterfall_demo.h
index 2417febddb2a156bb393bc2503906e0477b0eafc..e09860b265938cde41c076cf3d89c95dc3ea4baa 100644
--- a/garnet/examples/escher/waterfall/waterfall_demo.h
+++ b/garnet/examples/escher/waterfall/waterfall_demo.h
@@ -1,9 +1,9 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef GARNET_EXAMPLES_ESCHER_WATERFALL_WATERFALL_DEMO_H_
-#define GARNET_EXAMPLES_ESCHER_WATERFALL_WATERFALL_DEMO_H_
+#ifndef GARNET_EXAMPLES_ESCHER_WATERFALL2_WATERFALL_DEMO_H_
+#define GARNET_EXAMPLES_ESCHER_WATERFALL2_WATERFALL_DEMO_H_
 
 #include <stdlib.h>
 #include <cmath>
@@ -14,15 +14,10 @@
 #include "garnet/examples/escher/waterfall/scenes/scene.h"
 
 #include "lib/escher/escher.h"
-
-#include "lib/escher/geometry/types.h"
-#include "lib/escher/material/color_utils.h"
-#include "lib/escher/renderer/moment_shadow_map_renderer.h"
-#include "lib/escher/renderer/paper_renderer.h"
-#include "lib/escher/renderer/shadow_map_renderer.h"
-#include "lib/escher/scene/stage.h"
+#include "lib/escher/forward_declarations.h"
+#include "lib/escher/fs/hack_filesystem.h"
+#include "lib/escher/paper/paper_renderer2.h"
 #include "lib/escher/util/stopwatch.h"
-#include "lib/escher/vk/vulkan_swapchain_helper.h"
 #include "src/lib/fxl/logging.h"
 
 class WaterfallDemo : public Demo {
@@ -32,7 +27,6 @@ class WaterfallDemo : public Demo {
 
   enum ShadowMode {
     kNone,
-    kSsdo,
     kShadowMap,
     kMomentShadowMap,
     kNumShadowModes,
@@ -48,38 +42,37 @@ class WaterfallDemo : public Demo {
 
  private:
   void ProcessCommandLineArgs(int argc, char** argv);
-  void InitializeEscherStage(const DemoHarness::WindowParams& window_params);
+
+  void InitializePaperScene(const DemoHarness::WindowParams& window_params);
   void InitializeDemoScenes();
 
-  // Toggle debug overlays.
-  bool show_debug_info_ = false;
+  double ComputeFps();
 
-  ShadowMode shadow_mode_ = ShadowMode::kMomentShadowMap;
-  int current_scene_ = 0;
-  // True if the Model objects should be binned by pipeline, false if they
-  // should be rendered in their natural order.
-  bool sort_by_pipeline_ = true;
-  // True if SSDO should be accelerated by generating a lookup table each frame.
-  bool enable_ssdo_acceleration_ = true;
-  bool stop_time_ = false;
-  // True if the direction of the light source is animating.
-  bool animate_light_ = true;
-
-  // 3 camera projection modes:
-  // - orthogonal full-screen
+  escher::PaperRendererConfig renderer_config_;
+  escher::PaperRenderer2Ptr renderer_;
+
+  escher::PaperScenePtr paper_scene_;
+
+  // 4 camera projection modes:
+  // - orthographic full-screen
   // - perspective where floor plane is full-screen, and parallel to screen
-  // - perspective from diagonal viewpoint.
+  // - perspective from tilted viewpoint (from x-center of stage).
+  // - perspective from tilted viewpoint (from corner).
   int camera_projection_mode_ = 0;
 
-  std::vector<std::unique_ptr<Scene>> scenes_;
-  escher::PaperRendererPtr renderer_;
-  escher::ShadowMapRendererPtr shadow_renderer_;
-  escher::ShadowMapRendererPtr moment_shadow_renderer_;
-  escher::Stage stage_;
-  double light_azimuth_radians_ = 0.f;
+  int current_scene_ = 0;
+  std::vector<std::unique_ptr<Scene>> demo_scenes_;
 
+  // Used for FPS calculations and animating lighting params.
   escher::Stopwatch stopwatch_;
+  // Used for animating object shapes and positions.
+  escher::Stopwatch animation_stopwatch_;
+
+  uint64_t frame_count_ = 0;
   uint64_t first_frame_microseconds_;
+
+  // Toggle debug overlays.
+  bool show_debug_info_ = false;
 };
 
-#endif  // GARNET_EXAMPLES_ESCHER_WATERFALL_WATERFALL_DEMO_H_
+#endif  // GARNET_EXAMPLES_ESCHER_WATERFALL2_WATERFALL_DEMO_H_
diff --git a/garnet/examples/escher/waterfall2/BUILD.gn b/garnet/examples/escher/waterfall2/BUILD.gn
deleted file mode 100644
index e5912e2ddccbeddf381e86af03ed0948ccd5472a..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall2/BUILD.gn
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2018 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-executable("waterfall2") {
-  sources = [
-    "waterfall_demo.cc",
-    "waterfall_demo.h",
-    "waterfall_main.cc",
-  ]
-
-  deps = [
-    "//garnet/examples/escher/common",
-    "//garnet/examples/escher/waterfall:scenes",
-    "//garnet/public/lib/escher:vulkan",
-  ]
-
-  include_dirs = [
-    "//lib",
-    "//garnet/public/lib/escher",
-    "//third_party/glm",
-  ]
-
-  if (is_fuchsia) {
-    deps += [ "//zircon/public/lib/trace" ]
-  }
-}
diff --git a/garnet/examples/escher/waterfall2/waterfall_demo.cc b/garnet/examples/escher/waterfall2/waterfall_demo.cc
deleted file mode 100644
index 50a97cc4327b62c747a013d2f9d41cd8d1525065..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall2/waterfall_demo.cc
+++ /dev/null
@@ -1,367 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "garnet/examples/escher/waterfall2/waterfall_demo.h"
-
-#include "garnet/examples/escher/waterfall/scenes/paper_demo_scene1.h"
-#include "lib/escher/defaults/default_shader_program_factory.h"
-#include "lib/escher/geometry/tessellation.h"
-#include "lib/escher/paper/paper_scene.h"
-#include "lib/escher/paper/paper_shader_structs.h"
-#include "lib/escher/scene/camera.h"
-#include "lib/escher/scene/viewing_volume.h"
-#include "lib/escher/shape/mesh.h"
-#include "lib/escher/util/enum_utils.h"
-#include "lib/escher/util/trace_macros.h"
-#include "lib/escher/vk/shader_module_template.h"
-#include "lib/escher/vk/shader_program.h"
-#include "lib/escher/vk/texture.h"
-
-using namespace escher;
-
-static constexpr float kNear = 1.f;
-static constexpr float kFar = -200.f;
-
-WaterfallDemo::WaterfallDemo(DemoHarness* harness, int argc, char** argv)
-    : Demo(harness, "Waterfall Demo") {
-  ProcessCommandLineArgs(argc, argv);
-
-  // Initialize filesystem with files before creating renderer; it will use them
-  // to generate the necessary ShaderPrograms.
-  escher()->shader_program_factory()->filesystem()->InitializeWithRealFiles(
-      {"shaders/model_renderer/main.frag", "shaders/model_renderer/main.vert",
-       "shaders/model_renderer/default_position.vert",
-       "shaders/model_renderer/shadow_map_generation.frag",
-       "shaders/model_renderer/shadow_map_lighting.frag",
-       "shaders/model_renderer/wobble_position.vert",
-       "shaders/paper/common/use.glsl",
-       "shaders/paper/frag/main_ambient_light.frag",
-       "shaders/paper/frag/main_point_light.frag",
-       "shaders/paper/vert/compute_model_space_position.vert",
-       "shaders/paper/vert/compute_world_space_position.vert",
-       "shaders/paper/vert/main_shadow_volume_extrude.vert",
-       "shaders/paper/vert/vertex_attributes.vert"});
-
-  renderer_ = escher::PaperRenderer2::New(GetEscherWeakPtr());
-
-  renderer_config_.shadow_type = PaperRendererShadowType::kShadowVolume;
-  renderer_config_.msaa_sample_count = 2;
-  renderer_config_.num_depth_buffers =
-      harness->GetVulkanSwapchain().images.size();
-  renderer_->SetConfig(renderer_config_);
-
-  InitializePaperScene(harness->GetWindowParams());
-  InitializeDemoScenes();
-}
-
-WaterfallDemo::~WaterfallDemo() {
-  // Print out FPS stats.  Omit the first frame when computing the average,
-  // because it is generating pipelines.
-  auto microseconds = stopwatch_.GetElapsedMicroseconds();
-  double fps = (frame_count_ - 2) * 1000000.0 /
-               (microseconds - first_frame_microseconds_);
-  FXL_LOG(INFO) << "Average frame rate: " << fps;
-  FXL_LOG(INFO) << "First frame took: " << first_frame_microseconds_ / 1000.0
-                << " milliseconds";
-
-  escher()->Cleanup();
-}
-
-void WaterfallDemo::InitializePaperScene(
-    const DemoHarness::WindowParams& window_params) {
-  paper_scene_ = fxl::MakeRefCounted<PaperScene>();
-
-  // Number of lights can be cycled via keyboard event.  Light positions and
-  // colors are animated by UpdateLighting().
-  paper_scene_->point_lights.resize(1);
-
-  paper_scene_->bounding_box = escher::BoundingBox(
-      vec3(0.f, 0.f, kFar),
-      vec3(window_params.width, window_params.height, kNear));
-}
-
-void WaterfallDemo::InitializeDemoScenes() {
-  demo_scenes_.emplace_back(new PaperDemoScene1(this));
-  for (auto& scene : demo_scenes_) {
-    scene->Init(paper_scene_.get());
-  }
-}
-
-void WaterfallDemo::ProcessCommandLineArgs(int argc, char** argv) {
-  for (int i = 1; i < argc; ++i) {
-    if (!strcmp("--debug", argv[i])) {
-      show_debug_info_ = true;
-    } else if (!strcmp("--no-debug", argv[i])) {
-      show_debug_info_ = false;
-    }
-  }
-}
-
-bool WaterfallDemo::HandleKeyPress(std::string key) {
-  if (key.size() > 1) {
-    if (key == "SPACE") {
-      // Start/stop the animation stopwatch.
-      animation_stopwatch_.Toggle();
-      return true;
-    }
-    return Demo::HandleKeyPress(key);
-  } else {
-    char key_char = key[0];
-    switch (key_char) {
-      // Cycle through camera projection modes.
-      case 'C': {
-        camera_projection_mode_ = (camera_projection_mode_ + 1) % 5;
-        const char* kCameraModeStrings[5] = {
-            "orthographic",
-            "perspective",
-            "tilted perspective",
-            "tilted perspective from corner",
-            "stereo",
-        };
-        FXL_LOG(INFO) << "Camera projection mode: "
-                      << kCameraModeStrings[camera_projection_mode_];
-        return true;
-      }
-      // Toggle display of debug information.
-      case 'D': {
-        show_debug_info_ = !show_debug_info_;
-        renderer_config_.debug = show_debug_info_;
-        FXL_LOG(INFO) << "WaterfallDemo "
-                      << (show_debug_info_ ? "enabled" : "disabled")
-                      << " debugging.";
-        renderer_->SetConfig(renderer_config_);
-        return true;
-      }
-      case 'L': {
-        uint32_t num_point_lights = (paper_scene_->num_point_lights() + 1) % 3;
-        paper_scene_->point_lights.resize(num_point_lights);
-        FXL_LOG(INFO) << "WaterfallDemo number of point lights: "
-                      << paper_scene_->num_point_lights();
-        return true;
-      }
-      // Cycle through MSAA sample counts.
-      case 'M': {
-        auto sample_count = renderer_config_.msaa_sample_count;
-        if (sample_count == 1) {
-          sample_count = 2;
-        } else if (sample_count == 2) {
-          // TODO(ES-156): there seems to be a RenderPass-caching bug where if
-          // we change the RenderPassInfo's images to have a different sample
-          // count, then the old cached RenderPass is not flushed from the
-          // cache.  For now, just toggle between two values.
-          sample_count = 1;
-          // sample_count = 4;
-        } else {
-          sample_count = 1;
-        }
-        FXL_LOG(INFO) << "MSAA sample count: " << sample_count;
-        renderer_config_.msaa_sample_count = sample_count;
-        renderer_->SetConfig(renderer_config_);
-        return true;
-      }
-      // Cycle through shadow algorithms..
-      case 'S': {
-        auto& shadow_type = renderer_config_.shadow_type;
-        shadow_type = EnumCycle(shadow_type);
-        while (!renderer_->SupportsShadowType(shadow_type)) {
-          FXL_LOG(INFO) << "WaterfallDemo skipping unsupported shadow type: "
-                        << shadow_type;
-          shadow_type = EnumCycle(shadow_type);
-        }
-        renderer_->SetConfig(renderer_config_);
-        FXL_LOG(INFO) << "WaterfallDemo changed shadow type: "
-                      << renderer_config_;
-        return true;
-      }
-      case '1':
-      case '2':
-      case '3':
-      case '4':
-      case '5':
-      case '6':
-      case '7':
-      case '8':
-      case '9':
-      case '0':
-        current_scene_ =
-            (demo_scenes_.size() + (key_char - '0') - 1) % demo_scenes_.size();
-        FXL_LOG(INFO) << "Current scene index: " << current_scene_;
-        return true;
-      default:
-        return Demo::HandleKeyPress(key);
-    }
-  }
-}
-
-// Helper function for DrawFrame().
-static std::vector<escher::Camera> GenerateCameras(
-    int camera_projection_mode, const escher::ViewingVolume& volume,
-    const escher::FramePtr& frame) {
-  switch (camera_projection_mode) {
-    // Orthographic full-screen.
-    case 0: {
-      return {escher::Camera::NewOrtho(volume)};
-    }
-    // Perspective where floor plane is full-screen, and parallel to screen.
-    case 1: {
-      vec3 eye(volume.width() / 2, volume.height() / 2, -10000);
-      vec3 target(volume.width() / 2, volume.height() / 2, 0);
-      vec3 up(0, -1, 0);
-      return {escher::Camera::NewPerspective(
-          volume, glm::lookAt(eye, target, up), glm::radians(8.f))};
-    }
-    // Perspective from tilted viewpoint (from x-center of stage).
-    case 2: {
-      vec3 eye(volume.width() / 2, 6000, -2000);
-      vec3 target(volume.width() / 2, volume.height() / 2, 0);
-      vec3 up(0, -1, 0);
-      return {escher::Camera::NewPerspective(
-          volume, glm::lookAt(eye, target, up), glm::radians(15.f))};
-    } break;
-    // Perspective from tilted viewpoint (from corner).
-    case 3: {
-      vec3 eye(volume.width() / 3, 6000, -3000);
-      vec3 target(volume.width() / 2, volume.height() / 3, 0);
-      vec3 up(0, -1, 0);
-      return {escher::Camera::NewPerspective(
-          volume, glm::lookAt(eye, target, up), glm::radians(15.f))};
-    } break;
-    // Stereo/Perspective from tilted viewpoint (from corner).  This also
-    // demonstrates the ability to provide the view-projection matrix in a
-    // buffer instead of having the PaperRenderer2 upload the vp-matrix itself.
-    // This is typically used with a "pose buffer" in HMD applications.
-    // NOTE: the camera's transform must be fairly close to what will be read
-    // from the pose buffer, because the camera's position is used for z-sorting
-    // etc.
-    case 4: {
-      vec3 eye(volume.width() / 2, 6000, -3500);
-      vec3 eye_offset(40.f, 0.f, 0.f);
-      vec3 target(volume.width() / 2, volume.height() / 2, 0);
-      vec3 up(0, -1, 0);
-      float fov = glm::radians(15.f);
-      auto left_camera = escher::Camera::NewPerspective(
-          volume, glm::lookAt(eye - eye_offset, target, up), fov);
-      auto right_camera = escher::Camera::NewPerspective(
-          volume, glm::lookAt(eye + eye_offset, target, up), fov);
-
-      // Obtain a buffer and populate it as though it were obtained by invoking
-      // PoseBufferLatchingShader.
-      auto binding = escher::NewPaperShaderUniformBinding<
-          escher::PaperShaderLatchedPoseBuffer>(frame);
-      binding.first->vp_matrix[0] =
-          left_camera.projection() * left_camera.transform();
-      binding.first->vp_matrix[1] =
-          right_camera.projection() * right_camera.transform();
-      escher::BufferPtr latched_pose_buffer(binding.second.buffer);
-
-      // Both cameras use the same buffer, but index into it using a different
-      // eye index.  NOTE: if you comment these lines out, there will be no
-      // visible difference, because PaperRenderer2 will compute/upload the same
-      // project * transform matrix.  What would happen if you swap the kLeft
-      // and kRight?
-      left_camera.SetLatchedPoseBuffer(latched_pose_buffer,
-                                       escher::CameraEye::kLeft);
-      right_camera.SetLatchedPoseBuffer(latched_pose_buffer,
-                                        escher::CameraEye::kRight);
-
-      left_camera.SetViewport({0.f, 0.25f, 0.5f, 0.5f});
-      right_camera.SetViewport({0.5f, 0.25f, 0.5f, 0.5f});
-      return {left_camera, right_camera};
-    } break;
-    default:
-      // Should not happen.
-      FXL_DCHECK(false);
-      return {escher::Camera::NewOrtho(volume)};
-  }
-}
-
-static void UpdateLighting(PaperScene* paper_scene,
-                           const escher::Stopwatch& stopwatch,
-                           PaperRendererShadowType shadow_type) {
-  const size_t num_point_lights = paper_scene->num_point_lights();
-  if (num_point_lights == 0 || shadow_type == PaperRendererShadowType::kNone) {
-    paper_scene->ambient_light.color = vec3(1, 1, 1);
-    return;
-  }
-
-  // Set the ambient light to an arbitrary value that looks OK.  The intensities
-  // of the point lights will be chosen so that the total light intensity on an
-  // unshadowed fragment is vec3(1,1,1).
-  const vec3 kAmbientLightColor(0.4f, 0.5f, 0.5f);
-  paper_scene->ambient_light.color = kAmbientLightColor;
-
-  for (auto& pl : paper_scene->point_lights) {
-    pl.color =
-        (vec3(1.f, 1.f, 1.f) - kAmbientLightColor) / float(num_point_lights);
-
-    // Choose a light intensity that looks good with the falloff.  If an object
-    // is too close to the light it will appear washed out.
-    // TODO(ES-170): add HDR support to address this.
-    pl.color *= 2.5f;
-    pl.falloff = 0.001f;
-  }
-
-  // Simple animation of point light.
-  const float width = paper_scene->width();
-  const float height = paper_scene->height();
-  if (num_point_lights == 1) {
-    paper_scene->point_lights[0].position =
-        vec3(width * .3f, height * .3f,
-             -(800.f + 200.f * sin(stopwatch.GetElapsedSeconds() * 1.2f)));
-  } else {
-    FXL_DCHECK(num_point_lights == 2);
-
-    paper_scene->point_lights[0].position =
-        vec3(width * .3f, height * .3f,
-             -(800.f + 300.f * sin(stopwatch.GetElapsedSeconds() * 1.2f)));
-    paper_scene->point_lights[1].position =
-        vec3(width * (0.6f + 0.3f * sin(stopwatch.GetElapsedSeconds() * 0.7f)),
-             height * (0.4f + 0.2f * sin(stopwatch.GetElapsedSeconds() * 0.6f)),
-             -900.f);
-
-    // Make the light colors subtly different.
-    vec3 color_diff =
-        vec3(.02f, -.01f, .04f) * paper_scene->point_lights[0].color;
-    paper_scene->point_lights[0].color += color_diff;
-    paper_scene->point_lights[1].color -= color_diff;
-  }
-}
-
-void WaterfallDemo::DrawFrame(const FramePtr& frame,
-                              const ImagePtr& output_image) {
-  TRACE_DURATION("gfx", "WaterfallDemo::DrawFrame");
-
-  std::vector<Camera> cameras =
-      GenerateCameras(camera_projection_mode_,
-                      ViewingVolume(paper_scene_->bounding_box), frame);
-
-  // Animate light positions and intensities.
-  UpdateLighting(paper_scene_.get(), stopwatch_, renderer_config_.shadow_type);
-
-  renderer_->BeginFrame(frame, paper_scene_, std::move(cameras), output_image);
-  {
-    TRACE_DURATION("gfx", "WaterfallDemo::DrawFrame[scene]");
-    demo_scenes_[current_scene_]->Update(animation_stopwatch_, frame_count(),
-                                         paper_scene_.get(), renderer_.get());
-  }
-  renderer_->EndFrame();
-
-  if (++frame_count_ == 1) {
-    first_frame_microseconds_ = stopwatch_.GetElapsedMicroseconds();
-    stopwatch_.Reset();
-  } else if (frame_count_ % 200 == 0) {
-    set_enable_gpu_logging(true);
-
-    // Print out FPS stats.  Omit the first frame when computing the
-    // average, because it is generating pipelines.
-    auto microseconds = stopwatch_.GetElapsedMicroseconds();
-    double fps = (frame_count_ - 2) * 1000000.0 /
-                 (microseconds - first_frame_microseconds_);
-    FXL_LOG(INFO) << "---- Average frame rate: " << fps;
-    FXL_LOG(INFO) << "---- Total GPU memory: "
-                  << (escher()->GetNumGpuBytesAllocated() / 1024) << "kB";
-  } else {
-    set_enable_gpu_logging(false);
-  }
-}
diff --git a/garnet/examples/escher/waterfall2/waterfall_demo.h b/garnet/examples/escher/waterfall2/waterfall_demo.h
deleted file mode 100644
index 11fb22f0800ce53d016b9a6ea5f1fcc5123e4e85..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall2/waterfall_demo.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef GARNET_EXAMPLES_ESCHER_WATERFALL2_WATERFALL_DEMO_H_
-#define GARNET_EXAMPLES_ESCHER_WATERFALL2_WATERFALL_DEMO_H_
-
-#include <stdlib.h>
-#include <cmath>
-#include <iostream>
-
-#include "garnet/examples/escher/common/demo.h"
-#include "garnet/examples/escher/common/demo_harness.h"
-#include "garnet/examples/escher/waterfall/scenes/scene.h"
-
-#include "lib/escher/escher.h"
-#include "lib/escher/forward_declarations.h"
-#include "lib/escher/fs/hack_filesystem.h"
-#include "lib/escher/paper/paper_renderer2.h"
-#include "lib/escher/util/stopwatch.h"
-#include "src/lib/fxl/logging.h"
-
-class WaterfallDemo : public Demo {
- public:
-  static constexpr uint32_t kDemoWidth = 2160;
-  static constexpr uint32_t kDemoHeight = 1440;
-
-  enum ShadowMode {
-    kNone,
-    kShadowMap,
-    kMomentShadowMap,
-    kNumShadowModes,
-  };
-
-  WaterfallDemo(DemoHarness* harness, int argc, char** argv);
-  virtual ~WaterfallDemo();
-
-  bool HandleKeyPress(std::string key) override;
-
-  void DrawFrame(const escher::FramePtr& frame,
-                 const escher::ImagePtr& output_image) override;
-
- private:
-  void ProcessCommandLineArgs(int argc, char** argv);
-
-  void InitializePaperScene(const DemoHarness::WindowParams& window_params);
-  void InitializeDemoScenes();
-
-  escher::PaperRendererConfig renderer_config_;
-  escher::PaperRenderer2Ptr renderer_;
-
-  escher::PaperScenePtr paper_scene_;
-
-  // 4 camera projection modes:
-  // - orthographic full-screen
-  // - perspective where floor plane is full-screen, and parallel to screen
-  // - perspective from tilted viewpoint (from x-center of stage).
-  // - perspective from tilted viewpoint (from corner).
-  int camera_projection_mode_ = 0;
-
-  int current_scene_ = 0;
-  std::vector<std::unique_ptr<Scene>> demo_scenes_;
-
-  // Used for FPS calculations and animating lighting params.
-  escher::Stopwatch stopwatch_;
-  // Used for animating object shapes and positions.
-  escher::Stopwatch animation_stopwatch_;
-
-  uint64_t frame_count_ = 0;
-  uint64_t first_frame_microseconds_;
-
-  // Toggle debug overlays.
-  bool show_debug_info_ = false;
-};
-
-#endif  // GARNET_EXAMPLES_ESCHER_WATERFALL2_WATERFALL_DEMO_H_
diff --git a/garnet/examples/escher/waterfall2/waterfall_main.cc b/garnet/examples/escher/waterfall2/waterfall_main.cc
deleted file mode 100644
index 37d490a281ba1604423a7a429e1bdc83bc8e4572..0000000000000000000000000000000000000000
--- a/garnet/examples/escher/waterfall2/waterfall_main.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdlib.h>
-#include <cmath>
-
-#include "garnet/examples/escher/common/demo_harness.h"
-#include "garnet/examples/escher/waterfall2/waterfall_demo.h"
-
-std::unique_ptr<DemoHarness> CreateHarnessDemo(std::string demo_name,
-                                               uint32_t width, uint32_t height,
-                                               int argc, char** argv) {
-  bool use_fullscreen = false;
-  for (int i = 1; i < argc; ++i) {
-    if (!strcmp("--fullscreen", argv[i])) {
-      use_fullscreen = true;
-    }
-  }
-
-  DemoHarness::WindowParams window_params{demo_name, width, height, 2,
-                                          use_fullscreen};
-
-  return DemoHarness::New(window_params, DemoHarness::InstanceParams());
-}
-
-int main(int argc, char** argv) {
-  auto harness =
-      CreateHarnessDemo("Escher Waterfall Demo", WaterfallDemo::kDemoWidth,
-                        WaterfallDemo::kDemoHeight, argc, argv);
-  {
-    WaterfallDemo demo(harness.get(), argc, argv);
-    harness->Run(&demo);
-  }
-  harness->Shutdown();
-  return 0;
-}
diff --git a/garnet/packages/examples/BUILD.gn b/garnet/packages/examples/BUILD.gn
index 4429c800f07324a4dba089e22223b03677513de6..08ee90fb662bae6d2cea2450b98faa0c10ef5209 100644
--- a/garnet/packages/examples/BUILD.gn
+++ b/garnet/packages/examples/BUILD.gn
@@ -59,7 +59,6 @@ group("escher") {
   testonly = true
   public_deps = [
     "//garnet/examples/escher:escher_waterfall",
-    "//garnet/examples/escher:escher_waterfall2",
   ]
 }
 
diff --git a/garnet/public/lib/escher/README.md b/garnet/public/lib/escher/README.md
index d3693622b5e76f15ae7ea43d4b5f3a3cf87a4f06..c373779478f4d534d14fbb5c74a5e7c291195065 100644
--- a/garnet/public/lib/escher/README.md
+++ b/garnet/public/lib/escher/README.md
@@ -10,7 +10,7 @@ Escher is a physically based renderer.
  * Lens effect
 
 ## Building for Fuchsia
-Escher is part of the default Fuchsia build.  The "waterfall" and "waterfall2" demos are not installed in `/system/bin`, but they used to be!
+Escher is part of the default Fuchsia build.  The "waterfall" demo is not installed in `/system/bin`, but it used to be!
 
 ## Building for Linux
 Escher can also build on Linux.  In order to do so, you need to:
@@ -41,7 +41,7 @@ Escher can also build on Linux.  In order to do so, you need to:
     ```
     * See `$FUCHSIA_DIR/docs/getting_source.md` for how to set up the `fx` tool.
     * Adding `--with //garnet/packages/examples:all` would also work, or anything else that includes `//garnet/packages/examples:escher`.  This should also work with any other product than `terminal`.
-  * Do the following each time you want to rebuild and run the `waterfall2` example:
+  * Do the following each time you want to rebuild and run the `waterfall` example:
     ```
-    fx build host_x64/waterfall2 && out/default/host_x64/waterfall2
+    fx build host_x64/waterfall && out/default/host_x64/waterfall
     ```
diff --git a/garnet/public/lib/escher/build_linux/BUILD.gn b/garnet/public/lib/escher/build_linux/BUILD.gn
index 8efabf8e686935f6bf93c28ab353ee61dfe1f571..f7913cc929ce384da1187330407b93ecc9d5563c 100644
--- a/garnet/public/lib/escher/build_linux/BUILD.gn
+++ b/garnet/public/lib/escher/build_linux/BUILD.gn
@@ -9,7 +9,6 @@
 group("examples") {
   deps = [
     "//garnet/examples/escher/waterfall($host_toolchain)",
-    "//garnet/examples/escher/waterfall2($host_toolchain)",
   ]
 }
 
diff --git a/garnet/public/lib/escher/test/BUILD.gn b/garnet/public/lib/escher/test/BUILD.gn
index e4df7da83b4a1efd60a8ed48bf02fcda0060491a..f565531fd9f126d666dea4b66086a4c6381914c1 100644
--- a/garnet/public/lib/escher/test/BUILD.gn
+++ b/garnet/public/lib/escher/test/BUILD.gn
@@ -154,11 +154,12 @@ source_set("gtest_escher") {
   ]
 }
 
+# Guarantees that buildbots at least build the Escher examples on Linux,
+# even if they are not run.
 group("force_waterfall_to_build_on_host") {
   if (is_linux) {
     deps = [
       "//garnet/examples/escher/waterfall($host_toolchain)",
-      "//garnet/examples/escher/waterfall2($host_toolchain)",
     ]
   }
 }