Merge branch 'master' of github.com:domokit/sky_engine
diff --git a/packages/flutter/BUILD.gn b/packages/flutter/BUILD.gn
index 9e896d6..8ee6c83 100644
--- a/packages/flutter/BUILD.gn
+++ b/packages/flutter/BUILD.gn
@@ -9,6 +9,7 @@
     "CHANGELOG.md",
     "bin/init.dart",
     "lib/animation/animated_simulation.dart",
+    "lib/animation/animated_value.dart",
     "lib/animation/animation_performance.dart",
     "lib/animation/curves.dart",
     "lib/animation/forces.dart",
diff --git a/packages/flutter/CHANGELOG.md b/packages/flutter/CHANGELOG.md
index 448e203..7dd98e6 100644
--- a/packages/flutter/CHANGELOG.md
+++ b/packages/flutter/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.20
+
+  - 167 changes: https://github.com/domokit/mojo/compare/f2830c7...603f589
+
 ## 0.0.19
 
   - 49 changes: https://github.com/domokit/mojo/compare/a64559a...1b8968c
diff --git a/packages/flutter/example/demo_launcher/apk/AndroidManifest.xml b/packages/flutter/example/demo_launcher/apk/AndroidManifest.xml
index a10f9ce..dc14953 100644
--- a/packages/flutter/example/demo_launcher/apk/AndroidManifest.xml
+++ b/packages/flutter/example/demo_launcher/apk/AndroidManifest.xml
@@ -3,7 +3,7 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file.
  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.domokit.sky.demo" android:versionCode="19" android:versionName="0.0.19">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.domokit.sky.demo" android:versionCode="20" android:versionName="0.0.20">
 
     <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
     <uses-permission android:name="android.permission.INTERNET" />
diff --git a/packages/flutter/example/demo_launcher/apk/release_notes/0.0.20.txt b/packages/flutter/example/demo_launcher/apk/release_notes/0.0.20.txt
new file mode 100644
index 0000000..1deb9ce
--- /dev/null
+++ b/packages/flutter/example/demo_launcher/apk/release_notes/0.0.20.txt
@@ -0,0 +1 @@
+Fixes crash on Nexus 6
diff --git a/packages/flutter/example/fitness/lib/home.dart b/packages/flutter/example/fitness/lib/home.dart
index df616c7..515c413 100644
--- a/packages/flutter/example/fitness/lib/home.dart
+++ b/packages/flutter/example/fitness/lib/home.dart
@@ -14,7 +14,6 @@
 import 'package:sky/widgets/floating_action_button.dart';
 import 'package:sky/widgets/icon_button.dart';
 import 'package:sky/widgets/icon.dart';
-import 'package:sky/widgets/ink_well.dart';
 import 'package:sky/widgets/material.dart';
 import 'package:sky/widgets/navigator.dart';
 import 'package:sky/widgets/scaffold.dart';
diff --git a/packages/flutter/example/fitness/lib/measurement.dart b/packages/flutter/example/fitness/lib/measurement.dart
index 6487fd5..c791338 100644
--- a/packages/flutter/example/fitness/lib/measurement.dart
+++ b/packages/flutter/example/fitness/lib/measurement.dart
@@ -4,7 +4,6 @@
 
 import 'package:sky/editing/input.dart';
 import 'package:sky/widgets/basic.dart';
-import 'package:sky/widgets/flat_button.dart';
 import 'package:sky/widgets/icon_button.dart';
 import 'package:sky/widgets/ink_well.dart';
 import 'package:sky/widgets/material.dart';
diff --git a/packages/flutter/example/raw/mutating-dom.dart b/packages/flutter/example/raw/mutating-dom.dart
index f157e47..0d27a3f 100644
--- a/packages/flutter/example/raw/mutating-dom.dart
+++ b/packages/flutter/example/raw/mutating-dom.dart
@@ -148,26 +148,27 @@
         break;
       }
     } else {
-      assert(node is sky.Text); // 
+      assert(node is sky.Text); //
+      final sky.Text text = node;
       if (pickThis(0.1)) {
         report("appending a new text node (ASCII)");
-        node.appendData(generateCharacter(0x20, 0x7F));
+        text.appendData(generateCharacter(0x20, 0x7F));
         break;
       } else if (pickThis(0.05)) {
         report("appending a new text node (Latin1)");
-        node.appendData(generateCharacter(0x20, 0xFF));
+        text.appendData(generateCharacter(0x20, 0xFF));
         break;
       } else if (pickThis(0.025)) {
         report("appending a new text node (BMP)");
-        node.appendData(generateCharacter(0x20, 0xFFFF));
+        text.appendData(generateCharacter(0x20, 0xFFFF));
         break;
       } else if (pickThis(0.0125)) {
         report("appending a new text node (Unicode)");
-        node.appendData(generateCharacter(0x20, 0x10FFFF));
+        text.appendData(generateCharacter(0x20, 0x10FFFF));
         break;
-      } else if (node.length > 1 && pickThis(0.1)) {
+      } else if (text.length > 1 && pickThis(0.1)) {
         report("deleting character from Text node");
-        node.deleteData(random.nextInt(node.length), 1);
+        text.deleteData(random.nextInt(text.length), 1);
         break;
       }
     }
@@ -178,7 +179,7 @@
   int count = 1;
   while (node != null) {
     if (node is sky.Element && node.firstChild != null) {
-      node = node.firstChild;
+      node = (node as sky.Element).firstChild;
       count += 1;
     } else {
       while (node != null && node.nextSibling == null)
diff --git a/packages/flutter/example/rendering/align_items.dart b/packages/flutter/example/rendering/align_items.dart
index 5a9c247..58d0004 100644
--- a/packages/flutter/example/rendering/align_items.dart
+++ b/packages/flutter/example/rendering/align_items.dart
@@ -20,7 +20,7 @@
     TextStyle style = const TextStyle(color: const Color(0xFF000000));
     RenderParagraph paragraph = new RenderParagraph(new InlineStyle(style, [new InlineText("${alignItems}")]));
     table.add(new RenderPadding(child: paragraph, padding: new EdgeDims.only(top: 20.0)));
-    var row = new RenderFlex(alignItems: alignItems, baseline: TextBaseline.alphabetic);
+    var row = new RenderFlex(alignItems: alignItems, textBaseline: TextBaseline.alphabetic);
 
     style = new TextStyle(fontSize: 15.0, color: const Color(0xFF000000));
     row.add(new RenderDecoratedBox(
@@ -32,7 +32,7 @@
       decoration: new BoxDecoration(backgroundColor: const Color(0x7FCCFFCC)),
       child: new RenderParagraph(new InlineStyle(style, [new InlineText('foo foo foo')]))
     ));
-    var subrow = new RenderFlex(alignItems: alignItems, baseline: TextBaseline.alphabetic);
+    var subrow = new RenderFlex(alignItems: alignItems, textBaseline: TextBaseline.alphabetic);
     style = new TextStyle(fontSize: 25.0, color: const Color(0xFF000000));
     subrow.add(new RenderDecoratedBox(
       decoration: new BoxDecoration(backgroundColor: const Color(0x7FCCCCFF)),
diff --git a/packages/flutter/example/rendering/interactive_flex.dart b/packages/flutter/example/rendering/interactive_flex.dart
index 24f6f60..940aacf 100644
--- a/packages/flutter/example/rendering/interactive_flex.dart
+++ b/packages/flutter/example/rendering/interactive_flex.dart
@@ -25,15 +25,15 @@
 class RenderImageGrow extends RenderImage {
   final Size _startingSize;
 
-  RenderImageGrow(Image image, Size size) : _startingSize = size, super(image, size);
+  RenderImageGrow(Image image, Size size)
+    : _startingSize = size, super(image: image, width: size.width, height: size.height);
 
   double _growth = 0.0;
   double get growth => _growth;
   void set growth(double value) {
     _growth = value;
-    double newWidth = _startingSize.width == null ? null : _startingSize.width + growth;
-    double newHeight = _startingSize.height == null ? null : _startingSize.height + growth;
-    requestedSize = new Size(newWidth, newHeight);
+    width = _startingSize.width == null ? null : _startingSize.width + growth;
+    height = _startingSize.height == null ? null : _startingSize.height + growth;
   }
 }
 
diff --git a/packages/flutter/example/stocks/lib/stock_home.dart b/packages/flutter/example/stocks/lib/stock_home.dart
index b7a314c..4ce3187 100644
--- a/packages/flutter/example/stocks/lib/stock_home.dart
+++ b/packages/flutter/example/stocks/lib/stock_home.dart
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import 'package:sky/editing/input.dart';
-import 'package:sky/animation/animation_performance.dart';
+import 'package:sky/animation/animated_value.dart';
 import 'package:sky/widgets/animated_component.dart';
 import 'package:sky/widgets/animation_builder.dart';
 import 'package:sky/theme/colors.dart' as colors;
@@ -69,7 +69,8 @@
   }
 
   void _handleSearchEnd() {
-    assert(navigator.currentRoute.key == this);
+    assert(navigator.currentRoute is RouteState);
+    assert((navigator.currentRoute as RouteState).owner == this); // TODO(ianh): remove cast once analyzer is cleverer
     navigator.pop();
     setState(() {
       _isSearching = false;
@@ -280,10 +281,10 @@
   void _handleStockPurchased() {
     setState(() {
       _snackbarTransform = new AnimationBuilder()
-        ..position = new AnimatedType<Point>(const Point(0.0, 45.0), end: Point.origin);
+        ..position = new AnimatedValue<Point>(const Point(0.0, 45.0), end: Point.origin);
       var performance = _snackbarTransform.createPerformance(
           [_snackbarTransform.position], duration: _kSnackbarSlideDuration);
-      watch(performance);
+      watch(performance); // TODO(mpcomplete): need to unwatch
       performance.play();
     });
   }
diff --git a/packages/flutter/example/stocks/lib/stock_settings.dart b/packages/flutter/example/stocks/lib/stock_settings.dart
index a49047c..76e5c03 100644
--- a/packages/flutter/example/stocks/lib/stock_settings.dart
+++ b/packages/flutter/example/stocks/lib/stock_settings.dart
@@ -61,7 +61,7 @@
         break;
       case StockMode.pessimistic:
         showModeDialog = true;
-        navigator.pushState("/settings/confirm", (_) {
+        navigator.pushState(this, (_) {
           showModeDialog = false;
         });
         break;
diff --git a/packages/flutter/example/widgets/card_collection.dart b/packages/flutter/example/widgets/card_collection.dart
index 6725e37..c3b7cb2 100644
--- a/packages/flutter/example/widgets/card_collection.dart
+++ b/packages/flutter/example/widgets/card_collection.dart
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'package:sky/animation/animated_value.dart';
 import 'package:sky/animation/animation_performance.dart';
 import 'package:sky/animation/curves.dart';
 import 'package:sky/base/lerp.dart';
@@ -27,8 +28,6 @@
   AnimationPerformance performance;
   String get label => "Item $value";
   String get key => value.toString();
-  bool operator ==(other) => other is CardModel && other.value == value;
-  int get hashCode => 373 * 37 * value.hashCode;
 }
 
 class ShrinkingCard extends AnimatedComponent {
@@ -44,7 +43,7 @@
   Function onUpdated;
   Function onCompleted;
 
-  double get currentHeight => card.performance.variable.value;
+  double get currentHeight => (card.performance.variable as AnimatedValue).value;
 
   void initState() {
     assert(card.performance != null);
@@ -100,7 +99,7 @@
       assert(card.performance == null);
       card.performance = new AnimationPerformance()
         ..duration = const Duration(milliseconds: 300)
-        ..variable = new AnimatedType<double>(
+        ..variable = new AnimatedValue<double>(
           card.height + kCardMargins.top + kCardMargins.bottom,
           end: 0.0,
           curve: ease,
diff --git a/packages/flutter/example/widgets/container.dart b/packages/flutter/example/widgets/container.dart
index 9ebea3a..836d731 100644
--- a/packages/flutter/example/widgets/container.dart
+++ b/packages/flutter/example/widgets/container.dart
@@ -16,7 +16,8 @@
           decoration: new BoxDecoration(backgroundColor: const Color(0xFFCCCCCC)),
           child: new NetworkImage(
             src: "https://www.dartlang.org/logos/dart-logo.png",
-            size: new Size(300.0, 300.0)
+            width: 300.0,
+            height: 300.0
           )
         ),
         new Container(
diff --git a/packages/flutter/lib/animation/animated_value.dart b/packages/flutter/lib/animation/animated_value.dart
new file mode 100644
index 0000000..9251029
--- /dev/null
+++ b/packages/flutter/lib/animation/animated_value.dart
@@ -0,0 +1,79 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import "dart:sky";
+
+import 'package:sky/animation/curves.dart';
+import 'package:sky/base/lerp.dart';
+
+abstract class AnimatedVariable {
+  void setProgress(double t);
+  String toString();
+}
+
+class Interval {
+  final double start;
+  final double end;
+
+  double adjustTime(double t) {
+    return ((t - start) / (end - start)).clamp(0.0, 1.0);
+  }
+
+  Interval(this.start, this.end) {
+    assert(start >= 0.0);
+    assert(start <= 1.0);
+    assert(end >= 0.0);
+    assert(end <= 1.0);
+  }
+}
+
+class AnimatedValue<T extends dynamic> extends AnimatedVariable {
+  AnimatedValue(this.begin, { this.end, this.interval, this.curve: linear }) {
+    value = begin;
+  }
+
+  T value;
+  T begin;
+  T end;
+  Interval interval;
+  Curve curve;
+
+  void setProgress(double t) {
+    if (end != null) {
+      double adjustedTime = interval == null ? t : interval.adjustTime(t);
+      if (adjustedTime == 1.0) {
+        value = end;
+      } else {
+        // TODO(mpcomplete): Reverse the timeline and curve.
+        value = begin + (end - begin) * curve.transform(adjustedTime);
+      }
+    }
+  }
+
+  String toString() => 'AnimatedValue(begin=$begin, end=$end, value=$value)';
+}
+
+class AnimatedList extends AnimatedVariable {
+  List<AnimatedVariable> variables;
+  Interval interval;
+
+  AnimatedList(this.variables, { this.interval });
+
+  void setProgress(double t) {
+    double adjustedTime = interval == null ? t : interval.adjustTime(t);
+    for (AnimatedVariable variable in variables)
+      variable.setProgress(adjustedTime);
+  }
+
+  String toString() => 'AnimatedList([$variables])';
+}
+
+class AnimatedColor extends AnimatedValue<Color> {
+  AnimatedColor(Color begin, { Color end, Curve curve: linear })
+    : super(begin, end: end, curve: curve);
+
+  void setProgress(double t) {
+    value = lerpColor(begin, end, t);
+  }
+}
diff --git a/packages/flutter/lib/animation/animation_performance.dart b/packages/flutter/lib/animation/animation_performance.dart
index 5c678c1..716165a 100644
--- a/packages/flutter/lib/animation/animation_performance.dart
+++ b/packages/flutter/lib/animation/animation_performance.dart
@@ -4,71 +4,9 @@
 
 import 'dart:async';
 
-import 'package:sky/animation/timeline.dart';
-import 'package:sky/animation/curves.dart';
+import 'package:sky/animation/animated_value.dart';
 import 'package:sky/animation/forces.dart';
-
-abstract class AnimatedVariable {
-  void setFraction(double t);
-  String toString();
-}
-
-class Interval {
-  final double start;
-  final double end;
-
-  double adjustTime(double t) {
-    return ((t - start) / (end - start)).clamp(0.0, 1.0);
-  }
-
-  Interval(this.start, this.end) {
-    assert(start >= 0.0);
-    assert(start <= 1.0);
-    assert(end >= 0.0);
-    assert(end <= 1.0);
-  }
-}
-
-class AnimatedType<T extends dynamic> extends AnimatedVariable {
-  AnimatedType(this.begin, { this.end, this.interval, this.curve: linear }) {
-    value = begin;
-  }
-
-  T value;
-  T begin;
-  T end;
-  Interval interval;
-  Curve curve;
-
-  void setFraction(double t) {
-    if (end != null) {
-      double adjustedTime = interval == null ? t : interval.adjustTime(t);
-      if (adjustedTime == 1.0) {
-        value = end;
-      } else {
-        // TODO(mpcomplete): Reverse the timeline and curve.
-        value = begin + (end - begin) * curve.transform(adjustedTime);
-      }
-    }
-  }
-
-  String toString() => 'AnimatedType(begin=$begin, end=$end, value=$value)';
-}
-
-class AnimatedList extends AnimatedVariable {
-  List<AnimatedVariable> variables;
-  Interval interval;
-
-  AnimatedList(this.variables, { this.interval });
-
-  void setFraction(double t) {
-    double adjustedTime = interval == null ? t : interval.adjustTime(t);
-    for (AnimatedVariable variable in variables)
-      variable.setFraction(adjustedTime);
-  }
-
-  String toString() => 'AnimatedList([$variables])';
-}
+import 'package:sky/animation/timeline.dart';
 
 // This class manages a "performance" - a collection of values that change
 // based on a timeline. For example, a performance may handle an animation
@@ -82,7 +20,6 @@
     _timeline = new Timeline(_tick);
   }
 
-  // TODO(mpcomplete): make this a list, or composable somehow.
   AnimatedVariable variable;
   // TODO(mpcomplete): duration should be on a director.
   Duration duration;
@@ -142,7 +79,7 @@
   }
 
   void _tick(double t) {
-    variable.setFraction(t);
+    variable.setProgress(t);
     _notifyListeners();
   }
 }
diff --git a/packages/flutter/lib/animation/timeline.dart b/packages/flutter/lib/animation/timeline.dart
index 680130d..1ea2039 100644
--- a/packages/flutter/lib/animation/timeline.dart
+++ b/packages/flutter/lib/animation/timeline.dart
@@ -54,11 +54,12 @@
     double end: 1.0
   }) {
     assert(!_animation.isAnimating);
-
+    assert(duration > Duration.ZERO);
     return _animation.start(new TweenSimulation(duration, begin, end));
   }
 
   Future animateTo(double target, { Duration duration }) {
+    assert(duration > Duration.ZERO);
     return _start(duration: duration, begin: value, end: target);
   }
 
diff --git a/packages/flutter/lib/rendering/box.dart b/packages/flutter/lib/rendering/box.dart
index 5f6142a..eafd40d 100644
--- a/packages/flutter/lib/rendering/box.dart
+++ b/packages/flutter/lib/rendering/box.dart
@@ -1249,9 +1249,10 @@
 
 class RenderImage extends RenderBox {
 
-  RenderImage(sky.Image image, Size requestedSize, { sky.ColorFilter colorFilter })
+  RenderImage({ sky.Image image, double width, double height, sky.ColorFilter colorFilter })
     : _image = image,
-      _requestedSize = requestedSize,
+      _width = width,
+      _height = height,
       _colorFilter = colorFilter;
 
   sky.Image _image;
@@ -1261,18 +1262,25 @@
       return;
     _image = value;
     markNeedsPaint();
-    if (_requestedSize.width == null || _requestedSize.height == null)
+    if (_width == null || _height == null)
       markNeedsLayout();
   }
 
-  Size _requestedSize;
-  Size get requestedSize => _requestedSize;
-  void set requestedSize (Size value) {
-    if (value == null)
-      value = const Size(null, null);
-    if (value == _requestedSize)
+  double _width;
+  double get width => _width;
+  void set width (double value) {
+    if (value == _width)
       return;
-    _requestedSize = value;
+    _width = value;
+    markNeedsLayout();
+  }
+
+  double _height;
+  double get height => _height;
+  void set height (double value) {
+    if (value == _height)
+      return;
+    _height = value;
     markNeedsLayout();
   }
 
@@ -1299,8 +1307,8 @@
   Size _sizeForConstraints(BoxConstraints constraints) {
     // If there's no image, we can't size ourselves automatically
     if (_image == null) {
-      double width = requestedSize.width == null ? 0.0 : requestedSize.width;
-      double height = requestedSize.height == null ? 0.0 : requestedSize.height;
+      double width = _width == null ? 0.0 : _width;
+      double height = _height == null ? 0.0 : _height;
       return constraints.constrain(new Size(width, height));
     }
 
@@ -1310,8 +1318,8 @@
       // other dimension to maintain the aspect ratio. In both cases,
       // constrain dimensions first, otherwise we end up losing the
       // ratio after constraining.
-      if (requestedSize.width == null) {
-        if (requestedSize.height == null) {
+      if (_width == null) {
+        if (_height == null) {
           // autosize
           double width = constraints.constrainWidth(_image.width.toDouble());
           double maxHeight = constraints.constrainHeight(_image.height.toDouble());
@@ -1323,21 +1331,21 @@
           }
           return constraints.constrain(new Size(width, height));
         }
-        // determine width from height
-        double width = requestedSize.height * _image.width / _image.height;
-        return constraints.constrain(new Size(width, requestedSize.height));
+        // Determine width from height
+        double width = _height * _image.width / _image.height;
+        return constraints.constrain(new Size(width, height));
       }
-      if (requestedSize.height == null) {
-        // determine height from width
-        double height = requestedSize.width * _image.height / _image.width;
-        return constraints.constrain(new Size(requestedSize.width, height));
+      if (_height == null) {
+        // Determine height from width
+        double height = _width * _image.height / _image.width;
+        return constraints.constrain(new Size(width, height));
       }
     }
-    return constraints.constrain(requestedSize);
+    return constraints.constrain(new Size(width, height));
   }
 
   double getMinIntrinsicWidth(BoxConstraints constraints) {
-    if (requestedSize.width == null && requestedSize.height == null)
+    if (_width == null && _height == null)
       return constraints.constrainWidth(0.0);
     return _sizeForConstraints(constraints).width;
   }
@@ -1347,7 +1355,7 @@
   }
 
   double getMinIntrinsicHeight(BoxConstraints constraints) {
-    if (requestedSize.width == null && requestedSize.height == null)
+    if (_width == null && _height == null)
       return constraints.constrainHeight(0.0);
     return _sizeForConstraints(constraints).height;
   }
@@ -1377,7 +1385,7 @@
       canvas.restore();
   }
 
-  String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}dimensions: ${requestedSize}\n';
+  String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}width: ${width}\n${prefix}height: ${height}\n';
 }
 
 class RenderDecoratedBox extends RenderProxyBox {
diff --git a/packages/flutter/lib/rendering/flex.dart b/packages/flutter/lib/rendering/flex.dart
index a25aa29..8b61489 100644
--- a/packages/flutter/lib/rendering/flex.dart
+++ b/packages/flutter/lib/rendering/flex.dart
@@ -83,6 +83,7 @@
     }
   }
 
+  // Set during layout if overflow occurred on the main axis
   TextBaseline _textBaseline;
   TextBaseline get textBaseline => _textBaseline;
   void set textBaseline (TextBaseline value) {
@@ -92,7 +93,6 @@
     }
   }
 
-  // Set during layout if overflow occurred on the main axis
   double _overflow;
 
   void setupParentData(RenderBox child) {
diff --git a/packages/flutter/lib/widgets/animated_container.dart b/packages/flutter/lib/widgets/animated_container.dart
index 1898664..d493a68 100644
--- a/packages/flutter/lib/widgets/animated_container.dart
+++ b/packages/flutter/lib/widgets/animated_container.dart
@@ -4,6 +4,7 @@
 
 import 'package:vector_math/vector_math.dart';
 
+import 'package:sky/animation/animated_value.dart';
 import 'package:sky/animation/animation_performance.dart';
 import 'package:sky/animation/curves.dart';
 import 'package:sky/base/lerp.dart';
@@ -11,21 +12,21 @@
 import 'package:sky/widgets/basic.dart';
 import 'package:sky/widgets/animated_component.dart';
 
-class AnimatedBoxConstraintsValue extends AnimatedType<BoxConstraints> {
+class AnimatedBoxConstraintsValue extends AnimatedValue<BoxConstraints> {
   AnimatedBoxConstraintsValue(BoxConstraints begin, { BoxConstraints end, Curve curve: linear })
     : super(begin, end: end, curve: curve);
 
-  void setFraction(double t) {
+  void setProgress(double t) {
     // TODO(abarth): We should lerp the BoxConstraints.
     value = end;
   }
 }
 
-class AnimatedBoxDecorationValue extends AnimatedType<BoxDecoration> {
+class AnimatedBoxDecorationValue extends AnimatedValue<BoxDecoration> {
   AnimatedBoxDecorationValue(BoxDecoration begin, { BoxDecoration end, Curve curve: linear })
     : super(begin, end: end, curve: curve);
 
-  void setFraction(double t) {
+  void setProgress(double t) {
     if (t == 1.0) {
       value = end;
       return;
@@ -34,11 +35,11 @@
   }
 }
 
-class AnimatedEdgeDimsValue extends AnimatedType<EdgeDims> {
+class AnimatedEdgeDimsValue extends AnimatedValue<EdgeDims> {
   AnimatedEdgeDimsValue(EdgeDims begin, { EdgeDims end, Curve curve: linear })
     : super(begin, end: end, curve: curve);
 
-  void setFraction(double t) {
+  void setProgress(double t) {
     if (t == 1.0) {
       value = end;
       return;
@@ -54,7 +55,7 @@
 
 class ImplicitlyAnimatedValue<T> {
   final AnimationPerformance performance = new AnimationPerformance();
-  final AnimatedType<T> _variable;
+  final AnimatedValue<T> _variable;
 
   ImplicitlyAnimatedValue(this._variable, Duration duration) {
     performance
@@ -168,21 +169,21 @@
 
   void _updateTransform() {
     _updateField(transform, _transform, () {
-      _transform = new ImplicitlyAnimatedValue<Matrix4>(new AnimatedType<Matrix4>(transform), duration);
+      _transform = new ImplicitlyAnimatedValue<Matrix4>(new AnimatedValue<Matrix4>(transform), duration);
       watch(_transform.performance);
     });
   }
 
   void _updateWidth() {
     _updateField(width, _width, () {
-      _width = new ImplicitlyAnimatedValue<double>(new AnimatedType<double>(width), duration);
+      _width = new ImplicitlyAnimatedValue<double>(new AnimatedValue<double>(width), duration);
       watch(_width.performance);
     });
   }
 
   void _updateHeight() {
     _updateField(height, _height, () {
-      _height = new ImplicitlyAnimatedValue<double>( new AnimatedType<double>(height), duration);
+      _height = new ImplicitlyAnimatedValue<double>( new AnimatedValue<double>(height), duration);
       watch(_height.performance);
     });
   }
diff --git a/packages/flutter/lib/widgets/animation_builder.dart b/packages/flutter/lib/widgets/animation_builder.dart
index 15cff58..a0362f3 100644
--- a/packages/flutter/lib/widgets/animation_builder.dart
+++ b/packages/flutter/lib/widgets/animation_builder.dart
@@ -4,9 +4,8 @@
 
 import 'package:vector_math/vector_math.dart';
 
+import 'package:sky/animation/animated_value.dart';
 import 'package:sky/animation/animation_performance.dart';
-import 'package:sky/animation/curves.dart';
-import 'package:sky/base/lerp.dart';
 import 'package:sky/painting/box_painter.dart';
 import 'package:sky/theme/shadows.dart';
 import 'package:sky/widgets/basic.dart';
@@ -18,9 +17,9 @@
 
   AnimationBuilder();
 
-  AnimatedType<double> opacity;
-  AnimatedType<Point> position;
-  AnimatedType<double> shadow;
+  AnimatedValue<double> opacity;
+  AnimatedValue<Point> position;
+  AnimatedValue<double> shadow;
   AnimatedColor backgroundColor;
 
   // These don't animate, but are used to build the AnimationBuilder anyway.
@@ -30,7 +29,7 @@
   Map<AnimatedVariable, AnimationPerformance> _variableToPerformance =
       new Map<AnimatedVariable, AnimationPerformance>();
 
-  AnimationPerformance createPerformance(List<AnimatedType> variables,
+  AnimationPerformance createPerformance(List<AnimatedValue> variables,
                                          { Duration duration }) {
     AnimationPerformance performance = new AnimationPerformance()
       ..duration = duration
@@ -67,7 +66,7 @@
   }
 
   void updateFields({
-    AnimatedType<double> shadow,
+    AnimatedValue<double> shadow,
     AnimatedColor backgroundColor,
     double borderRadius,
     Shape shape
@@ -78,7 +77,7 @@
     this.shape = shape;
   }
 
-  void _updateField(AnimatedType variable, AnimatedType sourceVariable) {
+  void _updateField(AnimatedValue variable, AnimatedValue sourceVariable) {
     if (variable == null)
       return; // TODO(mpcomplete): Should we handle transition from null?
 
@@ -101,15 +100,6 @@
   }
 }
 
-class AnimatedColor extends AnimatedType<Color> {
-  AnimatedColor(Color begin, { Color end, Curve curve: linear })
-    : super(begin, end: end, curve: curve);
-
-  void setFraction(double t) {
-    value = lerpColor(begin, end, t);
-  }
-}
-
 List<BoxShadow> _computeShadow(double level) {
   if (level < 1.0)  // shadows[1] is the first shadow
     return null;
diff --git a/packages/flutter/lib/widgets/basic.dart b/packages/flutter/lib/widgets/basic.dart
index 2952168..8e3e8f7 100644
--- a/packages/flutter/lib/widgets/basic.dart
+++ b/packages/flutter/lib/widgets/basic.dart
@@ -488,31 +488,34 @@
 }
 
 class Image extends LeafRenderObjectWrapper {
-  Image({ sky.Image image, this.size, this.colorFilter })
+  Image({ sky.Image image, this.width, this.height, this.colorFilter })
     : image = image,
       super(key: image.hashCode.toString()); // TODO(ianh): Find a way to uniquely identify the sky.Image rather than using hashCode, which could collide
 
   final sky.Image image;
-  final Size size;
+  final double width;
+  final double height;
   final sky.ColorFilter colorFilter;
 
-  RenderImage createNode() => new RenderImage(image, size, colorFilter: colorFilter);
+  RenderImage createNode() => new RenderImage(image: image, width: width, height: height, colorFilter: colorFilter);
   RenderImage get root => super.root;
 
   void syncRenderObject(Widget old) {
     super.syncRenderObject(old);
     root.image = image;
-    root.requestedSize = size;
+    root.width = width;
+    root.height = height;
     root.colorFilter = colorFilter;
   }
 }
 
 class FutureImage extends StatefulComponent {
-  FutureImage({ String key, this.image, this.size, this.colorFilter })
+  FutureImage({ String key, this.image, this.width, this.height, this.colorFilter })
     : super(key: key);
 
   Future<sky.Image> image;
-  Size size;
+  double width;
+  double height;
   sky.ColorFilter colorFilter;
 
   sky.Image _resolvedImage;
@@ -535,48 +538,57 @@
   void syncFields(FutureImage source) {
     bool needToResolveImage = (image != source.image);
     image = source.image;
-    size = source.size;
+    width = source.width;
+    height = source.height;
     if (needToResolveImage)
       _resolveImage();
   }
 
   Widget build() {
-    return new Image(image: _resolvedImage, size: size, colorFilter: colorFilter);
+    return new Image(
+      image: _resolvedImage,
+      width: width,
+      height: height,
+      colorFilter: colorFilter
+    );
   }
 }
 
 class NetworkImage extends Component {
-  NetworkImage({ String src, this.size, this.colorFilter })
-    : src = src,
-      super(key: src);
+  NetworkImage({ String src, this.width, this.height, this.colorFilter })
+    : src = src, super(key: src);
 
   final String src;
-  final Size size;
+  final double width;
+  final double height;
   final sky.ColorFilter colorFilter;
 
   Widget build() {
     return new FutureImage(
       image: image_cache.load(src),
-      size: size,
+      width: width,
+      height: height,
       colorFilter: colorFilter
     );
   }
 }
 
 class AssetImage extends Component {
-  AssetImage({ String name, this.bundle, this.size, this.colorFilter })
+  AssetImage({ String name, this.bundle, this.width, this.height, this.colorFilter })
     : name = name,
       super(key: name);
 
   final String name;
   final AssetBundle bundle;
-  final Size size;
+  final double width;
+  final double height;
   final sky.ColorFilter colorFilter;
 
   Widget build() {
     return new FutureImage(
       image: bundle.loadImage(name),
-      size: size,
+      width: width,
+      height: height,
       colorFilter: colorFilter
     );
   }
diff --git a/packages/flutter/lib/widgets/dismissable.dart b/packages/flutter/lib/widgets/dismissable.dart
index 614f1f0..9362dfc 100644
--- a/packages/flutter/lib/widgets/dismissable.dart
+++ b/packages/flutter/lib/widgets/dismissable.dart
@@ -4,6 +4,7 @@
 
 import 'dart:sky' as sky;
 
+import 'package:sky/animation/animated_value.dart';
 import 'package:sky/animation/animation_performance.dart';
 import 'package:sky/widgets/animated_component.dart';
 import 'package:sky/widgets/basic.dart';
@@ -13,7 +14,7 @@
 const Duration _kCardDismissFadeout = const Duration(milliseconds: 200);
 const double _kMinFlingVelocity = 700.0;
 const double _kMinFlingVelocityDelta = 400.0;
-const double _kFlingVelocityScale = 1.0/300.0;
+const double _kFlingVelocityScale = 1.0 / 300.0;
 const double _kDismissCardThreshold = 0.6;
 
 typedef void DismissedCallback();
@@ -30,8 +31,8 @@
   Widget child;
   DismissedCallback onDismissed;
 
-  AnimatedType<Point> _position;
-  AnimatedType<double> _opacity;
+  AnimatedValue<Point> _position;
+  AnimatedValue<double> _opacity;
   AnimationPerformance _performance;
 
   double _width;
@@ -39,8 +40,8 @@
   bool _dragUnderway = false;
 
   void initState() {
-    _position = new AnimatedType<Point>(Point.origin);
-    _opacity = new AnimatedType<double>(1.0, end: 0.0);
+    _position = new AnimatedValue<Point>(Point.origin);
+    _opacity = new AnimatedValue<double>(1.0, end: 0.0);
     _performance = new AnimationPerformance()
       ..duration = _kCardDismissFadeout
       ..variable = new AnimatedList([_position, _opacity])
diff --git a/packages/flutter/lib/widgets/drawer.dart b/packages/flutter/lib/widgets/drawer.dart
index 60f3682..b45aa9f 100644
--- a/packages/flutter/lib/widgets/drawer.dart
+++ b/packages/flutter/lib/widgets/drawer.dart
@@ -4,11 +4,11 @@
 
 import 'dart:sky' as sky;
 
+import 'package:sky/animation/animated_value.dart';
 import 'package:sky/animation/animation_performance.dart';
 import 'package:sky/theme/shadows.dart';
 import 'package:sky/theme/colors.dart' as colors;
 import 'package:sky/widgets/animated_component.dart';
-import 'package:sky/widgets/animation_builder.dart';
 import 'package:sky/widgets/basic.dart';
 import 'package:sky/widgets/navigator.dart';
 import 'package:sky/widgets/scrollable_viewport.dart';
@@ -30,7 +30,7 @@
 
 const double _kWidth = 304.0;
 const double _kMinFlingVelocity = 365.0;
-const double _kFlingVelocityScale = 1.0/300.0;
+const double _kFlingVelocityScale = 1.0 / 300.0;
 const Duration _kBaseSettleDuration = const Duration(milliseconds: 246);
 const Point _kOpenPosition = Point.origin;
 const Point _kClosedPosition = const Point(-_kWidth, 0.0);
@@ -60,12 +60,12 @@
   DrawerStatusChangedCallback onStatusChanged;
   Navigator navigator;
 
-  AnimatedType<Point> _position;
+  AnimatedValue<Point> _position;
   AnimatedColor _maskColor;
   AnimationPerformance _performance;
 
   void initState() {
-    _position = new AnimatedType<Point>(_kClosedPosition, end: _kOpenPosition);
+    _position = new AnimatedValue<Point>(_kClosedPosition, end: _kOpenPosition);
     _maskColor = new AnimatedColor(colors.transparent, end: const Color(0x7F000000));
     _performance = new AnimationPerformance()
       ..duration = _kBaseSettleDuration
@@ -143,7 +143,8 @@
     if (_lastStatus != null && status != _lastStatus) {
       if (status == DrawerStatus.inactive &&
           navigator != null &&
-          navigator.currentRoute.key == this)
+          navigator.currentRoute is RouteState &&
+          (navigator.currentRoute as RouteState).owner == this) // TODO(ianh): remove cast once analyzer is cleverer
         navigator.pop();
       if (onStatusChanged != null)
         onStatusChanged(status);
diff --git a/packages/flutter/lib/widgets/icon.dart b/packages/flutter/lib/widgets/icon.dart
index 7229d9e..c460228 100644
--- a/packages/flutter/lib/widgets/icon.dart
+++ b/packages/flutter/lib/widgets/icon.dart
@@ -93,7 +93,8 @@
     return new AssetImage(
       bundle: _iconBundle,
       name: '${category}/${density}/ic_${subtype}_${colorSuffix}_${size}dp.png',
-      size: new Size(size.toDouble(), size.toDouble()),
+      width: size.toDouble(),
+      height: size.toDouble(),
       colorFilter: colorFilter
     );
   }
diff --git a/packages/flutter/lib/widgets/ink_well.dart b/packages/flutter/lib/widgets/ink_well.dart
index f711fe1..158c6e4 100644
--- a/packages/flutter/lib/widgets/ink_well.dart
+++ b/packages/flutter/lib/widgets/ink_well.dart
@@ -5,6 +5,7 @@
 import 'dart:math' as math;
 import 'dart:sky' as sky;
 
+import 'package:sky/animation/animated_value.dart';
 import 'package:sky/animation/animation_performance.dart';
 import 'package:sky/animation/curves.dart';
 import 'package:sky/rendering/box.dart';
@@ -29,7 +30,7 @@
 class InkSplash {
   InkSplash(this.pointer, this.position, this.well) {
     _targetRadius = _getSplashTargetSize(well.size, position);
-    _radius = new AnimatedType<double>(
+    _radius = new AnimatedValue<double>(
         _kSplashInitialSize, end: _targetRadius, curve: easeOut);
 
     _performance = new AnimationPerformance()
@@ -45,7 +46,7 @@
 
   double _targetRadius;
   double _pinnedRadius;
-  AnimatedType<double> _radius;
+  AnimatedValue<double> _radius;
   AnimationPerformance _performance;
 
   void _updateVelocity(double velocity) {
diff --git a/packages/flutter/lib/widgets/navigator.dart b/packages/flutter/lib/widgets/navigator.dart
index 42df2d2..1a20b5a 100644
--- a/packages/flutter/lib/widgets/navigator.dart
+++ b/packages/flutter/lib/widgets/navigator.dart
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'package:sky/animation/animated_value.dart';
 import 'package:sky/animation/animation_performance.dart';
 import 'package:sky/animation/curves.dart';
 import 'package:sky/widgets/animated_component.dart';
@@ -11,25 +12,24 @@
 typedef Widget Builder(Navigator navigator, RouteBase route);
 
 abstract class RouteBase {
-  RouteBase({ this.key });
-  final Object key;
   Widget build(Navigator navigator, RouteBase route);
   void popState() { }
 }
 
 class Route extends RouteBase {
-  Route({ String name, this.builder }) : super(key: name);
-  String get name => key;
+  Route({ this.name, this.builder });
+  final String name;
   final Builder builder;
   Widget build(Navigator navigator, RouteBase route) => builder(navigator, route);
 }
 
 class RouteState extends RouteBase {
 
-  RouteState({ this.callback, this.route, Object key }) : super(key: key);
+  RouteState({ this.callback, this.route, this.owner });
 
-  RouteBase route;
   Function callback;
+  RouteBase route;
+  StatefulComponent owner;
 
   Widget build(Navigator navigator, RouteBase route) => null;
 
@@ -59,17 +59,17 @@
   Function onDismissed;
   Function onCompleted;
 
-  AnimatedType<Point> _position;
-  AnimatedType<double> _opacity;
+  AnimatedValue<Point> _position;
+  AnimatedValue<double> _opacity;
   AnimationPerformance _performance;
 
   void initState() {
-    _position = new AnimatedType<Point>(
+    _position = new AnimatedValue<Point>(
       _kTransitionStartPoint,
       end: Point.origin,
       curve: easeOut
     );
-    _opacity = new AnimatedType<double>(0.0, end: 1.0)
+    _opacity = new AnimatedValue<double>(0.0, end: 1.0)
       ..curve = easeOut;
     _performance = new AnimationPerformance()
       ..duration = _kTransitionDuration
@@ -143,9 +143,8 @@
 }
 
 class HistoryEntry {
-  HistoryEntry({ this.route, this.key });
+  HistoryEntry({ this.route });
   final RouteBase route;
-  final int key;
   bool transitionFinished = false;
   // TODO(jackson): Keep track of the requested transition
 }
@@ -157,12 +156,11 @@
       if (route.name != null)
         namedRoutes[route.name] = route;
     }
-    history.add(new HistoryEntry(route: routes[0], key: _lastKey++));
+    history.add(new HistoryEntry(route: routes[0]));
   }
 
   List<HistoryEntry> history = new List<HistoryEntry>();
   int historyIndex = 0;
-  int _lastKey = 0;
   Map<String, RouteBase> namedRoutes = new Map<String, RouteBase>();
 
   RouteBase get currentRoute => history[historyIndex].route;
@@ -175,7 +173,7 @@
   }
 
   void push(RouteBase route) {
-    HistoryEntry historyEntry = new HistoryEntry(route: route, key: _lastKey++);
+    HistoryEntry historyEntry = new HistoryEntry(route: route);
     history.insert(historyIndex + 1, historyEntry);
     historyIndex++;
   }
@@ -202,9 +200,9 @@
 
   RouteBase get currentRoute => state.currentRoute;
 
-  void pushState(Object key, Function callback) {
+  void pushState(StatefulComponent owner, Function callback) {
     RouteBase route = new RouteState(
-      key: key,
+      owner: owner,
       callback: callback,
       route: state.currentRoute
     );
@@ -244,7 +242,7 @@
       if (content == null)
         continue;
       Transition transition = new Transition(
-        key: historyEntry.key.toString(),
+        key: historyEntry.hashCode.toString(), // TODO(ianh): make it not collide
         content: content,
         direction: (i <= state.historyIndex) ? TransitionDirection.forward : TransitionDirection.reverse,
         interactive: (i == state.historyIndex),
diff --git a/packages/flutter/lib/widgets/popup_menu.dart b/packages/flutter/lib/widgets/popup_menu.dart
index 2d8a0dd..49d6aa9 100644
--- a/packages/flutter/lib/widgets/popup_menu.dart
+++ b/packages/flutter/lib/widgets/popup_menu.dart
@@ -5,6 +5,7 @@
 import 'dart:math' as math;
 import 'dart:sky' as sky;
 
+import 'package:sky/animation/animated_value.dart';
 import 'package:sky/animation/animation_performance.dart';
 import 'package:sky/painting/box_painter.dart';
 import 'package:sky/theme/colors.dart';
@@ -48,10 +49,10 @@
   int level;
   Navigator navigator;
 
-  AnimatedType<double> _opacity;
-  AnimatedType<double> _width;
-  AnimatedType<double> _height;
-  List<AnimatedType<double>> _itemOpacities;
+  AnimatedValue<double> _opacity;
+  AnimatedValue<double> _width;
+  AnimatedValue<double> _height;
+  List<AnimatedValue<double>> _itemOpacities;
   AnimatedList _animationList;
   AnimationPerformance _performance;
 
@@ -88,14 +89,14 @@
 
   void _updateAnimationVariables() {
     double unit = 1.0 / (items.length + 1.5); // 1.0 for the width and 0.5 for the last item's fade.
-    _opacity = new AnimatedType<double>(0.0, end: 1.0);
-    _width = new AnimatedType<double>(0.0, end: 1.0, interval: new Interval(0.0, unit));
-    _height = new AnimatedType<double>(0.0, end: 1.0, interval: new Interval(0.0, unit * items.length));
-    _itemOpacities = new List<AnimatedType<double>>();
+    _opacity = new AnimatedValue<double>(0.0, end: 1.0);
+    _width = new AnimatedValue<double>(0.0, end: 1.0, interval: new Interval(0.0, unit));
+    _height = new AnimatedValue<double>(0.0, end: 1.0, interval: new Interval(0.0, unit * items.length));
+    _itemOpacities = new List<AnimatedValue<double>>();
     for (int i = 0; i < items.length; ++i) {
       double start = (i + 1) * unit;
       double end = (start + 1.5 * unit).clamp(0.0, 1.0);
-      _itemOpacities.add(new AnimatedType<double>(
+      _itemOpacities.add(new AnimatedValue<double>(
           0.0, end: 1.0, interval: new Interval(start, end)));
     }
     List<AnimatedVariable> variables = new List<AnimatedVariable>()
@@ -122,7 +123,8 @@
     if (_lastStatus != null && status != _lastStatus) {
       if (status == PopupMenuStatus.inactive &&
           navigator != null && 
-          navigator.currentRoute.key == this)
+          navigator.currentRoute is RouteState &&
+          (navigator.currentRoute as RouteState).owner == this) // TODO(ianh): remove cast once analyzer is cleverer
         navigator.pop();
       if (onStatusChanged != null)
         onStatusChanged(status);
diff --git a/packages/flutter/lib/widgets/toggleable.dart b/packages/flutter/lib/widgets/toggleable.dart
index 6ef04d0..8fd8b1c 100644
--- a/packages/flutter/lib/widgets/toggleable.dart
+++ b/packages/flutter/lib/widgets/toggleable.dart
@@ -4,6 +4,7 @@
 
 import 'dart:sky' as sky;
 
+import 'package:sky/animation/animated_value.dart';
 import 'package:sky/animation/animation_performance.dart';
 import 'package:sky/animation/curves.dart';
 import 'package:sky/widgets/animated_component.dart';
@@ -24,14 +25,14 @@
   bool value;
   ValueChanged onChanged;
 
-  AnimatedType<double> _position;
-  AnimatedType<double> get position => _position;
+  AnimatedValue<double> _position;
+  AnimatedValue<double> get position => _position;
 
   AnimationPerformance _performance;
   AnimationPerformance get performance => _performance;
 
   void initState() {
-    _position = new AnimatedType<double>(0.0, end: 1.0);
+    _position = new AnimatedValue<double>(0.0, end: 1.0);
     _performance = new AnimationPerformance()
       ..variable = position
       ..duration = _kCheckDuration
diff --git a/packages/flutter/lib/widgets/variable_height_scrollable.dart b/packages/flutter/lib/widgets/variable_height_scrollable.dart
index 7799d91..66f060f 100644
--- a/packages/flutter/lib/widgets/variable_height_scrollable.dart
+++ b/packages/flutter/lib/widgets/variable_height_scrollable.dart
@@ -8,6 +8,8 @@
 import 'package:sky/widgets/scrollable.dart';
 import 'package:sky/widgets/widget.dart';
 
+export 'package:sky/widgets/block_viewport.dart' show BlockViewportLayoutState;
+
 class VariableHeightScrollable extends Scrollable {
   VariableHeightScrollable({
     String key,
diff --git a/packages/flutter/lib/widgets/widget.dart b/packages/flutter/lib/widgets/widget.dart
index 637f390..6f96239 100644
--- a/packages/flutter/lib/widgets/widget.dart
+++ b/packages/flutter/lib/widgets/widget.dart
@@ -6,7 +6,6 @@
 import 'dart:collection';
 import 'dart:sky' as sky;
 
-import 'package:sky/base/debug.dart';
 import 'package:sky/base/hit_test.dart';
 import 'package:sky/mojo/activity.dart' as activity;
 import 'package:sky/rendering/box.dart';
@@ -600,17 +599,20 @@
 
 class LayoutCallbackBuilderHandle { bool _active = true; }
 LayoutCallbackBuilderHandle enterLayoutCallbackBuilder() {
-  if (!inDebugBuild)
-    return null;
-  _inLayoutCallbackBuilder += 1;
+  assert(() {
+    _inLayoutCallbackBuilder += 1;
+    return true;
+  });
   return new LayoutCallbackBuilderHandle();
 }
 void exitLayoutCallbackBuilder(LayoutCallbackBuilderHandle handle) {
-  if (!inDebugBuild)
-    return;
-  assert(handle._active);
-  handle._active = false;
-  _inLayoutCallbackBuilder -= 1;
+  assert(() {
+    assert(handle._active);
+    handle._active = false;
+    _inLayoutCallbackBuilder -= 1;
+    return true;
+  });
+  Widget._notifyMountStatusChanged();
 }
 
 List<int> _debugFrameTimes = <int>[];
diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml
index 89af220..7ef9c6b 100644
--- a/packages/flutter/pubspec.yaml
+++ b/packages/flutter/pubspec.yaml
@@ -11,4 +11,4 @@
   sdk: '>=1.8.0 <2.0.0'
 homepage: https://github.com/domokit/mojo/tree/master/sky
 name: sky
-version: 0.0.19
+version: 0.0.20