Merge branch 'master' of github.com:airbnb/lottie-web
diff --git a/player/index.html b/player/index.html
index 35b569d..976102c 100644
--- a/player/index.html
+++ b/player/index.html
@@ -4,7 +4,7 @@
     <meta charset="UTF-8">
     <style>
         body, html{
-            background-color:#ff0;
+            background-color:#ccc;
             margin: 0px;
             height: 100%;
             overflow-x: hidden;
@@ -117,7 +117,8 @@
     <script src="js/elements/svgElements/effects/SVGProLevelsFilter.js" data-builds="full,svg,svg_light,html,html_light"></script>
     <script src="js/elements/svgElements/effects/SVGDropShadowEffect.js" data-builds="full,svg,svg_light,html,html_light"></script>
     <script src="js/elements/svgElements/effects/SVGMatte3Effect.js" data-builds="full,svg,svg_light,html,html_light"></script>
-    <script src="js/elements/svgElements/SVGEffects.js" data-builds="full,svg,svg_light,html,html_light"></script>
+    <script src="js/elements/svgElements/SVGEffectsPlaceholder.js" data-builds="svg_light,html_light"></script>
+    <script src="js/elements/svgElements/SVGEffects.js" data-builds="full,svg,html"></script>
     <script src="js/elements/canvasElements/CVContextData.js" data-builds="full,canvas,canvas_light,canvas_worker"></script>
     <script src="js/elements/canvasElements/CVBaseElement.js" data-builds="full,canvas,canvas_light,canvas_worker"></script>
     <script src="js/elements/canvasElements/CVImageElement.js" data-builds="full,canvas,canvas_light"></script>
@@ -159,8 +160,8 @@
     <script src="js/utils/expressions/ExpressionValueFactory.js" data-builds="full,svg,canvas,html,canvas_worker"></script>
     <script src="js/utils/expressions/TextSelectorPropertyDecorator.js" data-builds="full,svg,canvas,html,canvas_worker"></script>
     <script src="js/effects/SliderEffect.js" data-builds="full,svg,canvas,html,canvas_worker"></script>
-    <script src="js/effects/EffectsManagerPlaceholder.js" ></script>
-    <script src="js/EffectsManager.js" data-builds="full,svg,canvas,html,canvas_worker"></script>
+    <script src="js/effects/EffectsManagerPlaceholder.js"  data-builds="svg_light,canvas,html_light,canvas_worker" ></script>
+    <script src="js/EffectsManager.js" data-builds="full,svg,html"></script>
     <!-- end Expressions -->
     <!-- endbuild -->
     <script src="js/module.js" ></script>
@@ -179,8 +180,8 @@
     var animData = {
         container: elem,
         renderer: 'svg',
-        loop: false,
-        autoplay: false,
+        loop: true,
+        autoplay: true,
         rendererSettings: {
             progressiveLoad:false,
             preserveAspectRatio: 'xMidYMid meet',
@@ -209,7 +210,7 @@
         console.log(error)
     })
 
-    setTimeout(()=>anim.goToAndStop(10, true), 250);
+    // setTimeout(()=>anim.destroy(), 1000);
 
     function createAudio(assetPath) {
         return new Howl({
diff --git a/player/js/3rd_party/transformation-matrix.js b/player/js/3rd_party/transformation-matrix.js
index dd11ebf..9d3c303 100644
--- a/player/js/3rd_party/transformation-matrix.js
+++ b/player/js/3rd_party/transformation-matrix.js
@@ -231,6 +231,7 @@
         for(i=0;i<16;i+=1){
             matr.props[i] = this.props[i];
         }
+        return matr;
     }
 
     function cloneFromProps(props){
diff --git a/player/js/elements/svgElements/SVGEffectsPlaceholder.js b/player/js/elements/svgElements/SVGEffectsPlaceholder.js
new file mode 100644
index 0000000..29f89f0
--- /dev/null
+++ b/player/js/elements/svgElements/SVGEffectsPlaceholder.js
@@ -0,0 +1 @@
+function SVGEffects(){}
\ No newline at end of file
diff --git a/player/js/renderers/HybridRenderer.js b/player/js/renderers/HybridRenderer.js
index 6f75f23..c2f8797 100644
--- a/player/js/renderers/HybridRenderer.js
+++ b/player/js/renderers/HybridRenderer.js
@@ -233,7 +233,9 @@
 };
 
 HybridRenderer.prototype.destroy = function () {
-    this.animationItem.wrapper.innerText = '';
+    if (this.animationItem.wrapper) {
+        this.animationItem.wrapper.innerText = '';
+    }
     this.animationItem.container = null;
     this.globalData.defs = null;
     var i, len = this.layers ? this.layers.length : 0;
diff --git a/player/js/renderers/SVGRenderer.js b/player/js/renderers/SVGRenderer.js
index 1ae2e4f..5b2b3d9 100644
--- a/player/js/renderers/SVGRenderer.js
+++ b/player/js/renderers/SVGRenderer.js
@@ -140,7 +140,9 @@
 
 
 SVGRenderer.prototype.destroy = function () {
-    this.animationItem.wrapper.innerText = '';
+    if (this.animationItem.wrapper) {
+        this.animationItem.wrapper.innerText = '';
+    }
     this.layerElement = null;
     this.globalData.defs = null;
     var i, len = this.layers ? this.layers.length : 0;
diff --git a/player/js/utils/FontManager.js b/player/js/utils/FontManager.js
index 42b50a8..bb4457b 100644
--- a/player/js/utils/FontManager.js
+++ b/player/js/utils/FontManager.js
@@ -237,7 +237,12 @@
             }
             i+= 1;
         }
-        if((typeof char === 'string' && char.charCodeAt(0) !== 13 || !char) && console && console.warn) {
+        if ((typeof char === 'string' && char.charCodeAt(0) !== 13 || !char)
+            && console
+            && console.warn
+            && !this._warned
+           ) {
+            this._warned = true
             console.warn('Missing character from exported characters list: ', char, style, font);
         }
         return emptyChar;
@@ -290,6 +295,7 @@
         this.chars = null;
         this.typekitLoaded = 0;
         this.isLoaded = false;
+        this._warned = false;
         this.initTime = Date.now();
         this.setIsLoadedBinded = this.setIsLoaded.bind(this)
         this.checkLoadedFontsBinded = this.checkLoadedFonts.bind(this)
diff --git a/player/js/utils/PropertyFactory.js b/player/js/utils/PropertyFactory.js
index 2daf5f4..5cbae79 100644
--- a/player/js/utils/PropertyFactory.js
+++ b/player/js/utils/PropertyFactory.js
@@ -388,6 +388,7 @@
             }
         }
         this.effectsSequence = [getValueAtCurrentTime.bind(this)];
+        this.data = data;
         this.keyframes = data.k;
         this.offsetTime = elem.data.st;
         this.k = true;
diff --git a/player/js/utils/expressions/ExpressionPropertyDecorator.js b/player/js/utils/expressions/ExpressionPropertyDecorator.js
index b4fa8d2..ff63c91 100644
--- a/player/js/utils/expressions/ExpressionPropertyDecorator.js
+++ b/player/js/utils/expressions/ExpressionPropertyDecorator.js
@@ -191,51 +191,67 @@
         matrix.cloneFromProps(this.pre.props);
         if (this.appliedTransformations < 1) {
             var anchor = this.a.getValueAtTime(time);
-            matrix.translate(-anchor[0], -anchor[1], anchor[2]);
+            matrix.translate(
+                -anchor[0] * this.a.mult,
+                -anchor[1] * this.a.mult,
+                anchor[2] * this.a.mult
+            );
         }
         if (this.appliedTransformations < 2) {
             var scale = this.s.getValueAtTime(time);
-            matrix.scale(scale[0], scale[1], scale[2]);
+            matrix.scale(
+                scale[0] * this.s.mult,
+                scale[1] * this.s.mult,
+                scale[2] * this.s.mult
+            );
         }
         if (this.sk && this.appliedTransformations < 3) {
             var skew = this.sk.getValueAtTime(time);
             var skewAxis = this.sa.getValueAtTime(time);
-            matrix.skewFromAxis(-skew, skewAxis);
+            matrix.skewFromAxis(-skew * this.sk.mult, skewAxis * this.sa.mult);
         }
         if (this.r && this.appliedTransformations < 4) {
             var rotation = this.r.getValueAtTime(time);
-            matrix.rotate(-rotation);
+            matrix.rotate(-rotation * this.r.mult);
         } else if (!this.r && this.appliedTransformations < 4){
             var rotationZ = this.rz.getValueAtTime(time);
             var rotationY = this.ry.getValueAtTime(time);
             var rotationX = this.rx.getValueAtTime(time);
             var orientation = this.or.getValueAtTime(time);
-            matrix.rotateZ(-rotationZ.v)
-            .rotateY(rotationY.v)
-            .rotateX(rotationX.v)
-            .rotateZ(-orientation[2])
-            .rotateY(orientation[1])
-            .rotateX(orientation[0]);
+            matrix.rotateZ(-rotationZ * this.rz.mult)
+            .rotateY(rotationY * this.ry.mult)
+            .rotateX(rotationX * this.rx.mult)
+            .rotateZ(-orientation[2] * this.or.mult)
+            .rotateY(orientation[1] * this.or.mult)
+            .rotateX(orientation[0] * this.or.mult);
         }
         if (this.data.p && this.data.p.s) {
             var positionX = this.px.getValueAtTime(time);
             var positionY = this.py.getValueAtTime(time);
             if (this.data.p.z) {
                 var positionZ = this.pz.getValueAtTime(time);
-                matrix.translate(positionX, positionY, -positionZ);
+                matrix.translate(
+                    positionX * this.px.mult,
+                    positionY * this.py.mult,
+                    -positionZ * this.pz.mult
+                );
             } else {
-                matrix.translate(positionX, positionY, 0);
+                matrix.translate(positionX * this.px.mult, positionY * this.py.mult, 0);
             }
         } else {
             var position = this.p.getValueAtTime(time);
-            matrix.translate(position[0], position[1], -position[2]);
+            matrix.translate(
+                position[0] * this.p.mult,
+                position[1] * this.p.mult,
+                -position[2] * this.p.mult
+            );
         }
         return matrix;
         ////
     }
 
     function getTransformStaticValueAtTime(time) {
-
+        return this.v.clone(new Matrix());
     }
 
     var getTransformProperty = TransformPropertyFactory.getTransformProperty;
diff --git a/player/js/utils/expressions/ExpressionValueFactory.js b/player/js/utils/expressions/ExpressionValueFactory.js
index 233503c..f92dd4d 100644
--- a/player/js/utils/expressions/ExpressionValueFactory.js
+++ b/player/js/utils/expressions/ExpressionValueFactory.js
@@ -63,7 +63,7 @@
             property = defaultMultidimensionalValue;
         }
         var mult = 1 / property.mult;
-        var len = property.pv.length;
+        var len = (property.data && property.data.l) || property.pv.length;
         var expressionValue = createTypedArray('float32', len);
         var arrValue = createTypedArray('float32', len);
         expressionValue.value = arrValue;
diff --git a/player/js/utils/expressions/LayerInterface.js b/player/js/utils/expressions/LayerInterface.js
index 2fad619..9614356 100644
--- a/player/js/utils/expressions/LayerInterface.js
+++ b/player/js/utils/expressions/LayerInterface.js
@@ -1,42 +1,59 @@
 var LayerExpressionInterface = (function (){
-    function toWorld(arr, time){
+
+    function getMatrix(time) {
         var toWorldMat = new Matrix();
-        toWorldMat.reset();
-        var transformMat;
         if (time !== undefined) {
-            toWorldMat = this._elem.finalTransform.mProp.getValueAtTime(time);
+            var propMatrix = this._elem.finalTransform.mProp.getValueAtTime(time);
+            propMatrix.clone(toWorldMat);
         } else {
-            transformMat = this._elem.finalTransform.mProp;
+            var transformMat = this._elem.finalTransform.mProp;
             transformMat.applyToMatrix(toWorldMat);
         }
+        return toWorldMat;
+    }
+
+    function toWorldVec(arr, time){
+        var toWorldMat = this.getMatrix(time);
+        toWorldMat.props[12] = toWorldMat.props[13] = toWorldMat.props[14] = 0;
+        return this.applyPoint(toWorldMat, arr);
+    }
+
+    function toWorld(arr, time){
+        var toWorldMat = this.getMatrix(time);
+        return this.applyPoint(toWorldMat, arr);
+    }
+
+    function fromWorldVec(arr, time){
+        var toWorldMat = this.getMatrix(time);
+        toWorldMat.props[12] = toWorldMat.props[13] = toWorldMat.props[14] = 0;
+        return this.invertPoint(toWorldMat, arr);
+    }
+
+    function fromWorld(arr, time){
+        var toWorldMat = this.getMatrix(time);
+        return this.invertPoint(toWorldMat, arr);
+    }
+
+    function applyPoint(matrix, arr) {
         if(this._elem.hierarchy && this._elem.hierarchy.length){
             var i, len = this._elem.hierarchy.length;
             for(i=0;i<len;i+=1){
-                this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(toWorldMat);
+                this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(matrix);
             }
-            return toWorldMat.applyToPointArray(arr[0],arr[1],arr[2]||0);
         }
-        return toWorldMat.applyToPointArray(arr[0],arr[1],arr[2]||0);
+        return matrix.applyToPointArray(arr[0],arr[1],arr[2]||0);
     }
-    function fromWorld(arr, time){
-        var toWorldMat = new Matrix();
-        toWorldMat.reset();
-        var transformMat;
-        if (time !== undefined) {
-            toWorldMat = this._elem.finalTransform.mProp.getValueAtTime(time);
-        } else {
-            transformMat = this._elem.finalTransform.mProp;
-            transformMat.applyToMatrix(toWorldMat);
-        }
+
+    function invertPoint(matrix, arr) {
         if (this._elem.hierarchy && this._elem.hierarchy.length){
             var i, len = this._elem.hierarchy.length;
             for(i=0;i<len;i+=1){
-                this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(toWorldMat);
+                this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(matrix);
             }
-            return toWorldMat.inversePoint(arr);
         }
-        return toWorldMat.inversePoint(arr);
+        return matrix.inversePoint(arr);
     }
+
     function fromComp(arr){
         var toWorldMat = new Matrix();
         toWorldMat.reset();
@@ -88,8 +105,13 @@
                     return _thisLayerFunction.textInterface;
             }
         }
+        _thisLayerFunction.getMatrix = getMatrix;
+        _thisLayerFunction.invertPoint = invertPoint;
+        _thisLayerFunction.applyPoint = applyPoint;
         _thisLayerFunction.toWorld = toWorld;
+        _thisLayerFunction.toWorldVec = toWorldVec;
         _thisLayerFunction.fromWorld = fromWorld;
+        _thisLayerFunction.fromWorldVec = fromWorldVec;
         _thisLayerFunction.toComp = toWorld;
         _thisLayerFunction.fromComp = fromComp;
         _thisLayerFunction.sampleImage = sampleImage;
diff --git a/player/js/utils/expressions/ShapeInterface.js b/player/js/utils/expressions/ShapeInterface.js
index 2299a82..7882ada 100644
--- a/player/js/utils/expressions/ShapeInterface.js
+++ b/player/js/utils/expressions/ShapeInterface.js
@@ -474,9 +474,13 @@
                 }
             }
         }
-        _interfaceFunction.propertyGroup = propertyGroup;
-        interfaces = iterateElements(shapes, view, _interfaceFunction);
+        function parentGroupWrapper() {
+            return propertyGroup
+        }
+        _interfaceFunction.propertyGroup = propertyGroupFactory(_interfaceFunction, parentGroupWrapper);
+        interfaces = iterateElements(shapes, view, _interfaceFunction.propertyGroup);
         _interfaceFunction.numProperties = interfaces.length;
+        _interfaceFunction._name = 'Contents';
         return _interfaceFunction;
     };
 }());
diff --git a/player/js/utils/expressions/TransformInterface.js b/player/js/utils/expressions/TransformInterface.js
index a514f5e..a06111f 100644
--- a/player/js/utils/expressions/TransformInterface.js
+++ b/player/js/utils/expressions/TransformInterface.js
@@ -40,7 +40,6 @@
                     return _thisFunction.opacity;
             }
         }
-
         Object.defineProperty(_thisFunction, "rotation", {
             get: ExpressionPropertyInterface(transform.r || transform.rz)
         });
diff --git a/tasks/build.js b/tasks/build.js
index 3fc7641..497b87d 100644
--- a/tasks/build.js
+++ b/tasks/build.js
@@ -382,7 +382,11 @@
 	},
 	{
 		src: 'js/elements/svgElements/SVGEffects.js',
-		builds: ['full','svg','svg_light','html','html_light']
+		builds: ['full','svg','html']
+	},
+	{
+		src: 'js/elements/svgElements/SVGEffectsPlaceholder.js',
+		builds: ['svg_light','html_light']
 	},
 	{
 		src: 'js/elements/canvasElements/CVContextData.js',
@@ -546,7 +550,7 @@
 	},
 	{
 		src: 'js/effects/EffectsManagerPlaceholder.js',
-		builds: defaultBuilds
+		builds: ['svg_light','html_light']
 	},
 	{
 		src: 'js/EffectsManager.js',