source text expression
diff --git a/gulpfile.js b/gulpfile.js
index 686b58c..959ab85 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -15,6 +15,7 @@
 var fs = require('fs');
 var htmlreplace = require('gulp-html-replace');
 var eventstream = require("event-stream");
+var jslint = require('gulp-jslint');
 
 var bm_version = '4.6.0';
 
@@ -34,10 +35,16 @@
     .pipe(gulp.dest('demo/'));
 });
 
+gulp.task('lint-code', function () {
+    return gulp.src(['.player/js/**/*'])
+            .pipe(jslint({ /* this object represents the JSLint directives being passed down */ }))
+            .pipe(jslint.reporter( 'my-reporter' ));
+});
+
 gulp.task('buildPlayer', function(){
     gulp.src('./player/index.html')
         .pipe(usemin({
-            js: [uglify()]
+            js: [uglify(uglifyOptions)]
         }))
         //.pipe(wrap('(function(window){"use strict";<%= contents %>}(window));'))
         .pipe(wrap(moduleWrap))
@@ -54,7 +61,7 @@
 gulp.task('zipPlayer',['buildPlayer','buildUnminifiedPlayer'], function(){
     gulp.src('./player/index.html')
         .pipe(usemin({
-            js: [uglify()]
+            js: [uglify(uglifyOptions)]
         }))
         //.pipe(wrap('(function(window){"use strict";<%= contents %>}(window));'))
         .pipe(wrap(moduleWrap))
@@ -64,6 +71,10 @@
 
 var srcs = [];
 
+var demoBuiltData = '';
+var uglifyOptions = {output: {ascii_only:true}};
+
+
 gulp.task('getBuildSources', function(cb) {
     srcs.length = 0;
     gulp.src('./player/index.html')
@@ -124,7 +135,7 @@
     return gulp.src(srcs)
         .pipe(concat('bodymovin_light.min.js'))
         .pipe(wrap(moduleWrap))
-        .pipe(uglify())
+        .pipe(uglify(uglifyOptions))
         .pipe(gulp.dest('build/player/'));
 });
 
@@ -132,7 +143,7 @@
     return gulp.src(srcs)
         .pipe(concat('bodymovin.min.js'))
         .pipe(wrap(moduleWrap))
-        .pipe(uglify())
+        .pipe(uglify(uglifyOptions))
         .pipe(gulp.dest('build/player/'));
 });
 
diff --git a/player/index.html b/player/index.html
index e6dabe6..8d2f0a4 100644
--- a/player/index.html
+++ b/player/index.html
@@ -11,9 +11,9 @@
         }
 
         #bodymovin{
-            background-color:#000;
-            width:100%;
-            height:100%;
+            background-color:#099;
+            width:960px;
+            height:540px;
             /*width:800px;
             height:500px;*/
             display:block;
@@ -41,6 +41,7 @@
     <script src="js/utils/DataManager.js"></script>
     <script src="js/utils/FontManager.js"></script>
     <script src="js/utils/PropertyFactory.js"></script>
+    <script src="js/utils/shapes/shape_helper.js"></script>
     <script src="js/utils/shapes/ShapeProperty.js"></script>
     <script src="js/utils/shapes/ShapeModifiers.js"></script>
     <script src="js/utils/shapes/TrimModifier.js"></script>
@@ -62,6 +63,7 @@
     <script src="js/elements/svgElements/effects/SVGStrokeEffect.js"></script>
     <script src="js/elements/svgElements/effects/SVGTritoneFilter.js"></script>
     <script src="js/elements/svgElements/effects/SVGProLevelsFilter.js"></script>
+    <script src="js/elements/svgElements/effects/SVGDropShadowEffect.js"></script>
     <script src="js/elements/svgElements/SVGEffects.js"></script>
     <script src="js/elements/CompElement.js"></script>
     <script src="js/elements/ImageElement.js"></script>
@@ -94,6 +96,7 @@
     <script src="js/utils/expressions/TransformInterface.js" data-light-skip="true"></script>
     <script src="js/utils/expressions/ProjectInterface.js" data-light-skip="true"></script>
     <script src="js/utils/expressions/EffectInterface.js" data-light-skip="true"></script>
+    <script src="js/utils/expressions/ExpressionValue.js" data-light-skip="true"></script>
     <script src="js/effects/SliderEffect.js" data-light-skip="true"></script>
     <script src="js/effects.js" data-light-skip="true"></script>
     <!-- end Expressions -->
@@ -117,7 +120,7 @@
         rendererSettings: {
             progressiveLoad:false
         },
-        path: 'exports/render/data.json'
+        path: 'exports/render/cetan.json'
     };
     anim = bodymovin.loadAnimation(animData);
 
diff --git a/player/js/elements/BaseElement.js b/player/js/elements/BaseElement.js
index 2db1aba..833c499 100644
--- a/player/js/elements/BaseElement.js
+++ b/player/js/elements/BaseElement.js
@@ -41,15 +41,18 @@
     }
     var i, len = this.dynamicProperties.length;
     for(i=0;i<len;i+=1){
-        this.dynamicProperties[i].getValue();
-        if(this.dynamicProperties[i].mdf){
-            this.elemMdf = true;
-            this.globalData.mdf = true;
+        if(this.isVisible || (this._isParent && this.dynamicProperties[i].type === 'transform')){
+            this.dynamicProperties[i].getValue();
+            if(this.dynamicProperties[i].mdf){
+                this.elemMdf = true;
+                this.globalData.mdf = true;
+            }
         }
     }
-    if(this.data.hasMask){
+    if(this.data.hasMask && this.isVisible){
         this.maskManager.prepareFrame(num*this.data.sr);
     }
+    
     /* TODO check this
     if(this.data.sy){
         if(this.data.sy[0].renderedData[num]){
@@ -178,6 +181,7 @@
     this.hidden = false;
     this.firstFrame = true;
     this.isVisible = false;
+    this._isParent = false;
     this.currentFrameNum = -99999;
     this.lastNum = -99999;
     if(this.data.ks){
diff --git a/player/js/elements/ShapeElement.js b/player/js/elements/ShapeElement.js
index 4f13ce7..6d0ca40 100644
--- a/player/js/elements/ShapeElement.js
+++ b/player/js/elements/ShapeElement.js
@@ -179,7 +179,7 @@
             var g = document.createElementNS(svgNS,'g');
             container.appendChild(g);
             data[i].gr = g;
-            this.searchShapes(arr[i].it,data[i].it,g,dynamicProperties, level + 1, transformers);
+            this.searchShapes(arr[i].it,data[i].it,g,dynamicProperties, level + 1, ownTransformers);
         }else if(arr[i].ty == 'tr'){
             data[i] = {
                 transform : {
@@ -364,16 +364,19 @@
     var lvl = viewData.lvl;
     for(l=0;l<lLen;l+=1){
         redraw = viewData.sh.mdf || this.firstFrame;
-        pathStringTransformed = '';
+        pathStringTransformed = 'M0 0';
         var paths = viewData.sh.paths;
         jLen = paths.length;
         if(viewData.elements[l].st.lvl < lvl){
             var mat = this.mHelper.reset(), props;
-            var k;
-            for(k=viewData.transformers.length-1;k>=0;k-=1){
+            var iterations = lvl - viewData.elements[l].st.lvl;
+            var k = viewData.transformers.length-1;
+            while(iterations > 0) {
                 redraw = viewData.transformers[k].mProps.mdf || redraw;
                 props = viewData.transformers[k].mProps.v.props;
                 mat.transform(props[0],props[1],props[2],props[3],props[4],props[5],props[6],props[7],props[8],props[9],props[10],props[11],props[12],props[13],props[14],props[15]);
+                iterations --;
+                k --;
             }
             if(redraw){
                 for(j=0;j<jLen;j+=1){
diff --git a/player/js/elements/htmlElements/HTextElement.js b/player/js/elements/htmlElements/HTextElement.js
index c77e489..c787deb 100644
--- a/player/js/elements/htmlElements/HTextElement.js
+++ b/player/js/elements/htmlElements/HTextElement.js
@@ -30,8 +30,8 @@
         var cont = document.createElementNS(svgNS,'svg');
         styleDiv(cont);
         this.cont = cont;
-        this.compW = this.comp.data ? this.comp.data.w : this.globalData.compSize.w;
-        this.compH = this.comp.data ? this.comp.data.h : this.globalData.compSize.h;
+        this.compW = this.comp.data.w;
+        this.compH = this.comp.data.h;
         cont.setAttribute('width',this.compW);
         cont.setAttribute('height',this.compH);
         var g = document.createElementNS(svgNS,'g');
diff --git a/player/js/elements/svgElements/SVGBaseElement.js b/player/js/elements/svgElements/SVGBaseElement.js
index 1289b4e..5a37137 100644
--- a/player/js/elements/svgElements/SVGBaseElement.js
+++ b/player/js/elements/svgElements/SVGBaseElement.js
@@ -66,8 +66,8 @@
             feCTr.appendChild(feFunc);*/
             this.globalData.defs.appendChild(fil);
             var alphaRect = document.createElementNS(svgNS,'rect');
-            alphaRect.setAttribute('width',this.comp.data ? this.comp.data.w : this.globalData.compSize.w);
-            alphaRect.setAttribute('height',this.comp.data ? this.comp.data.h : this.globalData.compSize.h);
+            alphaRect.setAttribute('width',this.comp.data.w);
+            alphaRect.setAttribute('height',this.comp.data.h);
             alphaRect.setAttribute('x','0');
             alphaRect.setAttribute('y','0');
             alphaRect.setAttribute('fill','#ffffff');
diff --git a/player/js/elements/svgElements/SVGEffects.js b/player/js/elements/svgElements/SVGEffects.js
index 0ffa66a..e8e63e0 100644
--- a/player/js/elements/svgElements/SVGEffects.js
+++ b/player/js/elements/svgElements/SVGEffects.js
@@ -25,6 +25,10 @@
             count += 1;
             filterManager = new SVGProLevelsFilter(fil, elem.effects.effectElements[i]);
             this.filters.push(filterManager);
+        }else if(elem.data.ef[i].ty === 25){
+            count += 1;
+            filterManager = new SVGDropShadowEffect(fil, elem.effects.effectElements[i]);
+            this.filters.push(filterManager);
         }
     }
     if(count){
diff --git a/player/js/elements/svgElements/effects/SVGDropShadowEffect.js b/player/js/elements/svgElements/effects/SVGDropShadowEffect.js
new file mode 100644
index 0000000..16103b8
--- /dev/null
+++ b/player/js/elements/svgElements/effects/SVGDropShadowEffect.js
@@ -0,0 +1,87 @@
+function SVGDropShadowEffect(filter, filterManager){
+    /*<feGaussianBlur in="SourceAlpha" stdDeviation="3"/> <!-- stdDeviation is how much to blur -->
+  <feOffset dx="2" dy="2" result="offsetblur"/> <!-- how much to offset -->
+  <feMerge> 
+    <feMergeNode/> <!-- this contains the offset blurred image -->
+    <feMergeNode in="SourceGraphic"/> <!-- this contains the element that the filter is applied to -->
+  </feMerge>*/
+  /*<feFlood flood-color="#3D4574" flood-opacity="0.5" result="offsetColor"/>*/
+    filter.setAttribute('x','-100%');
+    filter.setAttribute('y','-100%');
+    filter.setAttribute('width','400%');
+    filter.setAttribute('height','400%');
+    this.filterManager = filterManager;
+
+    var feGaussianBlur = document.createElementNS(svgNS,'feGaussianBlur');
+    feGaussianBlur.setAttribute('in','SourceAlpha');
+    feGaussianBlur.setAttribute('result','drop_shadow_1');
+    feGaussianBlur.setAttribute('stdDeviation','0');
+    this.feGaussianBlur = feGaussianBlur;
+    filter.appendChild(feGaussianBlur);
+
+    var feOffset = document.createElementNS(svgNS,'feOffset');
+    feOffset.setAttribute('dx','25');
+    feOffset.setAttribute('dy','0');
+    feOffset.setAttribute('in','drop_shadow_1');
+    feOffset.setAttribute('result','drop_shadow_2');
+    this.feOffset = feOffset;
+    filter.appendChild(feOffset);
+    var feFlood = document.createElementNS(svgNS,'feFlood');
+    feFlood.setAttribute('flood-color','#00ff00');
+    feFlood.setAttribute('flood-opacity','1');
+    feFlood.setAttribute('result','drop_shadow_3');
+    this.feFlood = feFlood;
+    filter.appendChild(feFlood);
+
+    var feComposite = document.createElementNS(svgNS,'feComposite');
+    feComposite.setAttribute('in','drop_shadow_3');
+    feComposite.setAttribute('in2','drop_shadow_2');
+    feComposite.setAttribute('operator','in');
+    feComposite.setAttribute('result','drop_shadow_4');
+    filter.appendChild(feComposite);
+
+
+    var feMerge = document.createElementNS(svgNS,'feMerge');
+    filter.appendChild(feMerge);
+    var feMergeNode;
+    feMergeNode = document.createElementNS(svgNS,'feMergeNode');
+    feMerge.appendChild(feMergeNode);
+    feMergeNode = document.createElementNS(svgNS,'feMergeNode');
+    feMergeNode.setAttribute('in','SourceGraphic');
+    this.feMergeNode = feMergeNode;
+    this.feMerge = feMerge;
+    this.originalNodeAdded = false;
+    feMerge.appendChild(feMergeNode);
+}
+
+SVGDropShadowEffect.prototype.renderFrame = function(forceRender){
+    if(forceRender || this.filterManager.mdf){
+        if(forceRender || this.filterManager.effectElements[4].p.mdf){
+            this.feGaussianBlur.setAttribute('stdDeviation', this.filterManager.effectElements[4].p.v / 4);
+        }
+        if(forceRender || this.filterManager.effectElements[0].p.mdf){
+            var col = this.filterManager.effectElements[0].p.v;
+            this.feFlood.setAttribute('flood-color',rgbToHex(Math.round(col[0]*255),Math.round(col[1]*255),Math.round(col[2]*255)));
+        }
+        if(forceRender || this.filterManager.effectElements[1].p.mdf){
+            this.feFlood.setAttribute('flood-opacity',this.filterManager.effectElements[1].p.v/255);
+        }
+        if(forceRender || this.filterManager.effectElements[2].p.mdf || this.filterManager.effectElements[3].p.mdf){
+            var distance = this.filterManager.effectElements[3].p.v
+            var angle = (this.filterManager.effectElements[2].p.v - 90) * degToRads
+            var x = distance * Math.cos(angle)
+            var y = distance * Math.sin(angle)
+            this.feOffset.setAttribute('dx', x);
+            this.feOffset.setAttribute('dy', y);
+        }
+        /*if(forceRender || this.filterManager.effectElements[5].p.mdf){
+            if(this.filterManager.effectElements[5].p.v === 1 && this.originalNodeAdded) {
+                this.feMerge.removeChild(this.feMergeNode);
+                this.originalNodeAdded = false;
+            } else if(this.filterManager.effectElements[5].p.v === 0 && !this.originalNodeAdded) {
+                this.feMerge.appendChild(this.feMergeNode);
+                this.originalNodeAdded = true;
+            }
+        }*/
+    }
+};
\ No newline at end of file
diff --git a/player/js/mask.js b/player/js/mask.js
index 66ac039..826c738 100644
--- a/player/js/mask.js
+++ b/player/js/mask.js
@@ -30,8 +30,8 @@
         if((properties[i].mode == 's' || properties[i].mode == 'i') && count == 0){
             rect = document.createElementNS(svgNS, 'rect');
             rect.setAttribute('fill', '#ffffff');
-            rect.setAttribute('width', this.element.comp.data ? this.element.comp.data.w : this.element.globalData.compSize.w);
-            rect.setAttribute('height', this.element.comp.data ? this.element.comp.data.h : this.element.globalData.compSize.h);
+            rect.setAttribute('width', this.element.comp.data.w);
+            rect.setAttribute('height', this.element.comp.data.h);
             currentMasks.push(rect);
         } else {
             rect = null;
diff --git a/player/js/renderers/BaseRenderer.js b/player/js/renderers/BaseRenderer.js
index 30a86fb..4068609 100644
--- a/player/js/renderers/BaseRenderer.js
+++ b/player/js/renderers/BaseRenderer.js
@@ -77,9 +77,11 @@
                 this.addPendingElement(element);
             } else if(layers[i].parent !== undefined){
                 hierarchy.push(elements[i]);
+                elements[i]._isParent = true;
                 this.buildElementParenting(element,layers[i].parent, hierarchy);
             } else {
                 hierarchy.push(elements[i]);
+                elements[i]._isParent = true;
                 element.setHierarchy(hierarchy);
             }
 
diff --git a/player/js/renderers/CanvasRenderer.js b/player/js/renderers/CanvasRenderer.js
index c64fbfa..2c4ca28 100644
--- a/player/js/renderers/CanvasRenderer.js
+++ b/player/js/renderers/CanvasRenderer.js
@@ -147,6 +147,7 @@
     }else{
         this.canvasContext = this.renderConfig.context;
     }
+    this.data = animData;
     this.globalData.canvasContext = this.canvasContext;
     this.globalData.renderer = this;
     this.globalData.isDashed = false;
diff --git a/player/js/renderers/HybridRenderer.js b/player/js/renderers/HybridRenderer.js
index 8edf531..cd656b1 100644
--- a/player/js/renderers/HybridRenderer.js
+++ b/player/js/renderers/HybridRenderer.js
@@ -178,6 +178,7 @@
     var defs = document.createElementNS(svgNS,'defs');
     svg.appendChild(defs);
     this.globalData.defs = defs;
+    this.data = animData;
     //Mask animation
     this.globalData.getAssetData = this.animationItem.getAssetData.bind(this.animationItem);
     this.globalData.getAssetsPath = this.animationItem.getAssetsPath.bind(this.animationItem);
diff --git a/player/js/renderers/SVGRenderer.js b/player/js/renderers/SVGRenderer.js
index 3f6bdf7..5b6bacd 100644
--- a/player/js/renderers/SVGRenderer.js
+++ b/player/js/renderers/SVGRenderer.js
@@ -63,10 +63,12 @@
     this.globalData.getAssetsPath = this.animationItem.getAssetsPath.bind(this.animationItem);
     this.globalData.progressiveLoad = this.renderConfig.progressiveLoad;
     this.globalData.frameId = 0;
+    this.globalData.nm = animData.nm;
     this.globalData.compSize = {
         w: animData.w,
         h: animData.h
     };
+    this.data = animData;
     this.globalData.frameRate = animData.fr;
     var maskElement = document.createElementNS(svgNS, 'clipPath');
     var rect = document.createElementNS(svgNS,'rect');
diff --git a/player/js/utils/PropertyFactory.js b/player/js/utils/PropertyFactory.js
index ad87841..22327ed 100644
--- a/player/js/utils/PropertyFactory.js
+++ b/player/js/utils/PropertyFactory.js
@@ -268,160 +268,111 @@
         this.lastFrame = initFrame;
     }
 
-    var TransformProperty = (function(){
-        function positionGetter(){
-            if(this.p.k){
-                this.p.getValue();
-            }
-            if(!this.p.v.key){
-                this.p.v.key = function(pos){
-                    if(!this.p.v.numKeys){
-                        return 0;
-                    } else {
-                        return this.p.keyframes[pos-1].t;
-                    }
-                }.bind(this);
-            }
-            if(!this.p.v.numKeys){
-                this.p.v.numKeys = this.p.keyframes ? this.p.keyframes.length : 0;
-            }
-            if(!this.p.v.valueAtTime){
-                this.p.v.valueAtTime = this.p.getValueAtTime.bind(this.p);
-            }
-            return this.p.v;
+    var TransformProperty = (function() {
+        function positionGetter() {
+            return ExpressionValue(this.p);
         }
-        function xPositionGetter(){
-            if(this.px.k){
-                this.px.getValue();
-            }
-            return this.px.v;
+        function xPositionGetter() {
+            return ExpressionValue(this.px);
         }
-        function yPositionGetter(){
-            if(this.py.k){
-                this.py.getValue();
-            }
-            return this.py.v;
+        function yPositionGetter() {
+            return ExpressionValue(this.py);
         }
-        function zPositionGetter(){
-            if(this.pz.k){
-                this.pz.getValue();
-            }
-            return this.pz.v;
+        function zPositionGetter() {
+            return ExpressionValue(this.pz);
         }
-        function anchorGetter(){
-            if(this.a.k){
-                this.a.getValue();
-            }
-            return this.a.v;
+        function anchorGetter() {
+            return ExpressionValue(this.a);
         }
-        function orientationGetter(){
-            if(this.or.k){
-                this.or.getValue();
-            }
-            return this.or.v;
+        function orientationGetter() {
+            return ExpressionValue(this.or);
         }
-        function rotationGetter(){
-            if(this.r.k){
-                this.r.getValue();
-            }
-            return this.r.v/degToRads;
+        function rotationGetter() {
+            return ExpressionValue(this.r, 1/degToRads);
         }
-        function scaleGetter(){
-            if(this.s.k){
-                this.s.getValue();
-            }
-            return this.s.v;
+        function scaleGetter() {
+            return ExpressionValue(this.s, 100);
         }
-        function opacityGetter(){
-            if(this.o.k){
-                this.o.getValue();
-            }
-            return this.o.v;
+        function opacityGetter() {
+            return ExpressionValue(this.o, 100);
         }
-        function skewGetter(){
-            if(this.sk.k){
-                this.sk.getValue();
-            }
-            return this.sk.v;
+        function skewGetter() {
+            return ExpressionValue(this.sk);
         }
-        function skewAxisGetter(){
-            if(this.sa.k){
-                this.sa.getValue();
-            }
-            return this.sa.v;
+        function skewAxisGetter() {
+            return ExpressionValue(this.sa);
         }
-        function applyToMatrix(mat){
+        function applyToMatrix(mat) {
             var i, len = this.dynamicProperties.length;
-            for(i=0;i<len;i+=1){
+            for(i = 0; i < len; i += 1) {
                 this.dynamicProperties[i].getValue();
-                if(this.dynamicProperties[i].mdf){
+                if (this.dynamicProperties[i].mdf) {
                     this.mdf = true;
                 }
             }
-            if(this.a){
-                mat.translate(-this.a.v[0],-this.a.v[1],this.a.v[2]);
+            if (this.a) {
+                mat.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]);
             }
-            if(this.s){
-                mat.scale(this.s.v[0],this.s.v[1],this.s.v[2]);
+            if (this.s) {
+                mat.scale(this.s.v[0], this.s.v[1], this.s.v[2]);
             }
-            if(this.r){
+            if (this.r) {
                 mat.rotate(-this.r.v);
-            }else{
+            } else {
                 mat.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]);
             }
-            if(this.data.p.s){
-                if(this.data.p.z) {
+            if (this.data.p.s) {
+                if (this.data.p.z) {
                     mat.translate(this.px.v, this.py.v, -this.pz.v);
                 } else {
                     mat.translate(this.px.v, this.py.v, 0);
                 }
-            }else{
-                mat.translate(this.p.v[0],this.p.v[1],-this.p.v[2]);
+            } else {
+                mat.translate(this.p.v[0], this.p.v[1], -this.p.v[2]);
             }
         }
         function processKeys(){
-            if(this.elem.globalData.frameId === this.frameId){
+            if (this.elem.globalData.frameId === this.frameId) {
                 return;
             }
 
             this.mdf = false;
             var i, len = this.dynamicProperties.length;
 
-            for(i=0;i<len;i+=1){
+            for(i = 0; i < len; i += 1) {
                 this.dynamicProperties[i].getValue();
-                if(this.dynamicProperties[i].mdf){
+                if (this.dynamicProperties[i].mdf) {
                     this.mdf = true;
                 }
             }
-            if(this.mdf){
+            if (this.mdf) {
                 this.v.reset();
-                if(this.a){
-                    this.v.translate(-this.a.v[0],-this.a.v[1],this.a.v[2]);
+                if (this.a) {
+                    this.v.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]);
                 }
-                if(this.s){
-                    this.v.scale(this.s.v[0],this.s.v[1],this.s.v[2]);
+                if(this.s) {
+                    this.v.scale(this.s.v[0], this.s.v[1], this.s.v[2]);
                 }
-                if(this.sk){
-                    this.v.skewFromAxis(-this.sk.v,this.sa.v);
+                if (this.sk) {
+                    this.v.skewFromAxis(-this.sk.v, this.sa.v);
                 }
-                if(this.r){
+                if (this.r) {
                     this.v.rotate(-this.r.v);
-                }else{
+                } else {
                     this.v.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]);
                 }
-                if(this.autoOriented && this.p.keyframes && this.p.getValueAtTime){
+                if (this.autoOriented && this.p.keyframes && this.p.getValueAtTime) {
                     var v1,v2;
-                    if(this.p.lastFrame+this.p.offsetTime < this.p.keyframes[0].t){
-                        v1 = this.p.getValueAtTime(this.p.keyframes[0].t+0.01,0);
-                        v2 = this.p.getValueAtTime(this.p.keyframes[0].t, 0);
-                    }else if(this.p.lastFrame+this.p.offsetTime > this.p.keyframes[this.p.keyframes.length - 1].t){
-                        v1 = this.p.getValueAtTime(this.p.keyframes[this.p.keyframes.length - 1].t,0);
-                        v2 = this.p.getValueAtTime(this.p.keyframes[this.p.keyframes.length - 1].t-0.01, 0);
+                    if (this.p.lastFrame+this.p.offsetTime <= this.p.keyframes[0].t) {
+                        v1 = this.p.getValueAtTime((this.p.keyframes[0].t + 0.01) / this.elem.globalData.frameRate,0);
+                        v2 = this.p.getValueAtTime(this.p.keyframes[0].t / this.elem.globalData.frameRate, 0);
+                    } else if(this.p.lastFrame+this.p.offsetTime >= this.p.keyframes[this.p.keyframes.length - 1].t) {
+                        v1 = this.p.getValueAtTime((this.p.keyframes[this.p.keyframes.length - 1].t / this.elem.globalData.frameRate), 0);
+                        v2 = this.p.getValueAtTime((this.p.keyframes[this.p.keyframes.length - 1].t - 0.01) / this.elem.globalData.frameRate, 0);
                     } else {
                         v1 = this.p.pv;
-                        v2 = this.p.getValueAtTime(this.p.lastFrame+this.p.offsetTime - 0.01, this.p.offsetTime);
+                        v2 = this.p.getValueAtTime((this.p.lastFrame+this.p.offsetTime - 0.01) / this.elem.globalData.frameRate, this.p.offsetTime);
                     }
-                    //var prevV = this.p.getValueAtTime(this.p.lastFrame - 0.01, true);
                     this.v.rotate(-Math.atan2(v1[1] - v2[1], v1[0] - v2[0]));
                 }
                 if(this.data.p.s){
@@ -434,6 +385,7 @@
                     this.v.translate(this.p.v[0],this.p.v[1],-this.p.v[2]);
                 }
             }
+            //console.log(this.v.to2dCSS())
             this.frameId = this.elem.globalData.frameId;
         }
 
@@ -468,6 +420,7 @@
         return function TransformProperty(elem,data,arr){
             this.elem = elem;
             this.frameId = -1;
+            this.type = 'transform';
             this.dynamicProperties = [];
             this.mdf = false;
             this.data = data;
diff --git a/player/js/utils/common.js b/player/js/utils/common.js
index 3ca3c9d..877adde 100644
--- a/player/js/utils/common.js
+++ b/player/js/utils/common.js
@@ -37,7 +37,7 @@
     return Math.abs(val);
 
 }
-var defaultCurveSegments = 75;
+var defaultCurveSegments = 150;
 var degToRads = Math.PI/180;
 var roundCorner = 0.5519;
 
diff --git a/player/js/utils/expressions/CompInterface.js b/player/js/utils/expressions/CompInterface.js
index a012a0e..13cd592 100644
--- a/player/js/utils/expressions/CompInterface.js
+++ b/player/js/utils/expressions/CompInterface.js
@@ -3,12 +3,14 @@
         function _thisLayerFunction(name){
             var i=0, len = comp.layers.length;
             while(i<len){
-                if(comp.layers[i].nm === name || comp.layers[i].ind === name - 1){
+                if(comp.layers[i].nm === name || comp.layers[i].ind === name){
                     return comp.elements[i].layerInterface;
                 }
                 i += 1;
             }
+            return {active:false}
         }
+        Object.defineProperty(_thisLayerFunction, "_name", { value:comp.data.nm });
         _thisLayerFunction.layer = _thisLayerFunction;
         _thisLayerFunction.pixelAspect = 1;
         _thisLayerFunction.height = comp.globalData.compSize.h;
diff --git a/player/js/utils/expressions/EffectInterface.js b/player/js/utils/expressions/EffectInterface.js
index 75fe8e4..239f6d0 100644
--- a/player/js/utils/expressions/EffectInterface.js
+++ b/player/js/utils/expressions/EffectInterface.js
@@ -58,18 +58,7 @@
             if(type === 10){
                 return elem.comp.compInterface(element.p.v);
             }
-            if(element.p.k){
-                element.p.getValue();
-            }
-            if(typeof element.p.v === 'number'){
-                return element.p.v;
-            }
-            var i, len = element.p.v.length;
-            var arr = Array.apply(null,{length:len});
-            for(i=0;i<len;i+=1){
-                arr[i] = element.p.v[i];
-            }
-            return arr;
+            return ExpressionValue(element.p);
         }
     }
 
diff --git a/player/js/utils/expressions/ExpressionManager.js b/player/js/utils/expressions/ExpressionManager.js
index 66ebf88..f3fa1ef 100644
--- a/player/js/utils/expressions/ExpressionManager.js
+++ b/player/js/utils/expressions/ExpressionManager.js
@@ -5,7 +5,7 @@
     function duplicatePropertyValue(value, mult){
         mult = mult || 1;
 
-        if(typeof value === 'number'){
+        if(typeof value === 'number'  || value instanceof Number){
             return value*mult;
         }else if(value.i){
             return JSON.parse(JSON.stringify(value));
@@ -21,10 +21,10 @@
 
     function $bm_neg(a){
         var tOfA = typeof a;
-        if(tOfA === 'number' || tOfA === 'boolean'){
+        if(tOfA === 'number' || tOfA === 'boolean'  || a instanceof Number ){
             return -a;
         }
-        if(tOfA === 'object'){
+        if(a.constructor === Array){
             var i, lenA = a.length;
             var retArr = [];
             for(i=0;i<lenA;i+=1){
@@ -40,18 +40,18 @@
         if(tOfA === 'string' || tOfB === 'string'){
             return a + b;
         }
-        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string') && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string')) {
+        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number) && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string'  || b instanceof Number)) {
             return a + b;
         }
-        if(tOfA === 'object' && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string')){
+        if(a.constructor === Array && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number )){
             a[0] = a[0] + b;
             return a;
         }
-        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string') && tOfB === 'object'){
+        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) && b .constructor === Array){
             b[0] = a + b[0];
             return b;
         }
-        if(tOfA === 'object' && tOfB === 'object'){
+        if(a.constructor === Array && b.constructor === Array){
             var i = 0, lenA = a.length, lenB = b.length;
             var retArr = [];
             while(i<lenA || i < lenB){
@@ -66,22 +66,23 @@
         }
         return 0;
     }
+    var add = sum;
 
     function sub(a,b) {
         var tOfA = typeof a;
         var tOfB = typeof b;
-        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string') && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string')) {
+        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number )) {
             return a - b;
         }
-        if(tOfA === 'object' && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string')){
+        if( a.constructor === Array && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number )){
             a[0] = a[0] - b;
             return a;
         }
-        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string') && tOfB === 'object'){
+        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) &&  b.constructor === Array){
             b[0] = a - b[0];
             return b;
         }
-        if(tOfA === 'object' && tOfB === 'object'){
+        if(a.constructor === Array && b.constructor === Array){
             var i = 0, lenA = a.length, lenB = b.length;
             var retArr = [];
             while(i<lenA || i < lenB){
@@ -101,12 +102,12 @@
         var tOfA = typeof a;
         var tOfB = typeof b;
         var arr;
-        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string') && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string')) {
+        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number )) {
             return a * b;
         }
 
         var i, len;
-        if(tOfA === 'object' && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string')){
+        if(a.constructor === Array && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number )){
             len = a.length;
             arr = Array.apply(null,{length:len});
             for(i=0;i<len;i+=1){
@@ -114,7 +115,7 @@
             }
             return arr;
         }
-        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string') && tOfB === 'object'){
+        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) && b.constructor === Array){
             len = b.length;
             arr = Array.apply(null,{length:len});
             for(i=0;i<len;i+=1){
@@ -129,11 +130,11 @@
         var tOfA = typeof a;
         var tOfB = typeof b;
         var arr;
-        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string') && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string')) {
+        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number )) {
             return a / b;
         }
         var i, len;
-        if(tOfA === 'object' && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string')){
+        if(a.constructor === Array && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number  )){
             len = a.length;
             arr = Array.apply(null,{length:len});
             for(i=0;i<len;i+=1){
@@ -141,7 +142,7 @@
             }
             return arr;
         }
-        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string') && tOfB === 'object'){
+        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) && b.constructor === Array){
             len = b.length;
             arr = Array.apply(null,{length:len});
             for(i=0;i<len;i+=1){
@@ -294,6 +295,7 @@
     function initiateExpression(elem,data,property){
         var val = data.x;
         var needsVelocity = val.indexOf('velocity') !== -1;
+        var _needsRandom = val.indexOf('random') !== -1;
         var elemType = elem.data.ty;
         var transform,content,effect;
         var thisComp = elem.comp;
@@ -307,7 +309,7 @@
         //eval(fnStr);
         var fn = eval('[function(){' + val+';this.v = $bm_rt;}' + ']')[0];
         var bindedFn = fn.bind(this);
-        var numKeys = data.k ? data.k.length : 0;
+        var numKeys = property.kf ? data.k.length : 0;
 
         var wiggle = function wiggle(freq,amp){
             var i,j, len = this.pv.length ? this.pv.length : 1;
@@ -368,12 +370,12 @@
                 if(type === 'pingpong') {
                     var iterations = Math.floor((firstKeyFrame - currentFrame)/cycleDuration);
                     if(iterations % 2 === 0){
-                        return this.getValueAtTime((firstKeyFrame - currentFrame)%cycleDuration +  firstKeyFrame, 0);
+                        return this.getValueAtTime(((firstKeyFrame - currentFrame)%cycleDuration +  firstKeyFrame) / this.comp.globalData.frameRate, 0);
                     }
                 } else if(type === 'offset'){
-                    var initV = this.getValueAtTime(firstKeyFrame, 0);
-                    var endV = this.getValueAtTime(lastKeyFrame, 0);
-                    var current = this.getValueAtTime(cycleDuration - (firstKeyFrame - currentFrame)%cycleDuration +  firstKeyFrame, 0);
+                    var initV = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0);
+                    var endV = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0);
+                    var current = this.getValueAtTime((cycleDuration - (firstKeyFrame - currentFrame)%cycleDuration +  firstKeyFrame) / this.comp.globalData.frameRate, 0);
                     var repeats = Math.floor((firstKeyFrame - currentFrame)/cycleDuration)+1;
                     if(this.pv.length){
                         ret = new Array(initV.length);
@@ -385,19 +387,19 @@
                     }
                     return current-(endV-initV)*repeats;
                 } else if(type === 'continue'){
-                    var firstValue = this.getValueAtTime(firstKeyFrame, 0);
-                    var nextFirstValue = this.getValueAtTime(firstKeyFrame + 0.001, 0);
+                    var firstValue = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0);
+                    var nextFirstValue = this.getValueAtTime((firstKeyFrame + 0.001) / this.comp.globalData.frameRate, 0);
                     if(this.pv.length){
                         ret = new Array(firstValue.length);
                         len = ret.length;
                         for(i=0;i<len;i+=1){
-                            ret[i] = firstValue[i] + (firstValue[i]-nextFirstValue[i])*(firstKeyFrame - currentFrame)/0.0005;
+                            ret[i] = firstValue[i] + (firstValue[i]-nextFirstValue[i])*(firstKeyFrame - currentFrame)/0.001;
                         }
                         return ret;
                     }
-                    return firstValue + (firstValue-nextFirstValue)*(firstKeyFrame - currentFrame)/0.0005;
+                    return firstValue + (firstValue-nextFirstValue)*(firstKeyFrame - currentFrame)/0.001;
                 }
-                return this.getValueAtTime(cycleDuration - (firstKeyFrame - currentFrame)%cycleDuration +  firstKeyFrame, 0);
+                return this.getValueAtTime((cycleDuration - (firstKeyFrame - currentFrame) % cycleDuration +  firstKeyFrame) / this.comp.globalData.frameRate, 0);
             }
         }.bind(this);
 
@@ -434,12 +436,12 @@
                 if(type === 'pingpong') {
                     var iterations = Math.floor((currentFrame - firstKeyFrame)/cycleDuration);
                     if(iterations % 2 !== 0){
-                        return this.getValueAtTime(cycleDuration - (currentFrame - firstKeyFrame)%cycleDuration +  firstKeyFrame, 0);
+                        return this.getValueAtTime((cycleDuration - (currentFrame - firstKeyFrame) % cycleDuration +  firstKeyFrame) / this.comp.globalData.frameRate, 0);
                     }
                 } else if(type === 'offset'){
-                    var initV = this.getValueAtTime(firstKeyFrame, 0);
-                    var endV = this.getValueAtTime(lastKeyFrame, 0);
-                    var current = this.getValueAtTime((currentFrame - firstKeyFrame)%cycleDuration +  firstKeyFrame, 0);
+                    var initV = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0);
+                    var endV = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0);
+                    var current = this.getValueAtTime(((currentFrame - firstKeyFrame) % cycleDuration +  firstKeyFrame) / this.comp.globalData.frameRate, 0);
                     var repeats = Math.floor((currentFrame - firstKeyFrame)/cycleDuration);
                     if(this.pv.length){
                         ret = new Array(initV.length);
@@ -451,19 +453,19 @@
                     }
                     return (endV-initV)*repeats + current;
                 } else if(type === 'continue'){
-                    var lastValue = this.getValueAtTime(lastKeyFrame, 0);
-                    var nextLastValue = this.getValueAtTime(lastKeyFrame - 0.001, 0);
+                    var lastValue = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0);
+                    var nextLastValue = this.getValueAtTime((lastKeyFrame - 0.001) / this.comp.globalData.frameRate, 0);
                     if(this.pv.length){
                         ret = new Array(lastValue.length);
                         len = ret.length;
                         for(i=0;i<len;i+=1){
-                            ret[i] = lastValue[i] + (lastValue[i]-nextLastValue[i])*(currentFrame - lastKeyFrame)/0.0005;
+                            ret[i] = lastValue[i] + (lastValue[i]-nextLastValue[i])*((currentFrame - lastKeyFrame)/ this.comp.globalData.frameRate)/0.0005;
                         }
                         return ret;
                     }
-                    return lastValue + (lastValue-nextLastValue)*(currentFrame - lastKeyFrame)/0.0005;
+                    return lastValue + (lastValue-nextLastValue)*(((currentFrame - lastKeyFrame))/0.001);
                 }
-                return this.getValueAtTime((currentFrame - firstKeyFrame)%cycleDuration +  firstKeyFrame, 0);
+                return this.getValueAtTime(((currentFrame - firstKeyFrame) % cycleDuration +  firstKeyFrame) / this.comp.globalData.frameRate, 0);
             }
         }.bind(this);
         var loop_out = loopOut;
@@ -473,7 +475,7 @@
         }.bind(this);
 
         var valueAtTime = function valueAtTime(t) {
-            return this.getValueAtTime(t*elem.comp.globalData.frameRate, 0);
+            return this.getValueAtTime(t, 0);
         }.bind(this);
 
         var velocityAtTime = function velocityAtTime(t) {
@@ -537,7 +539,7 @@
                 time: data.k[ind].t/elem.comp.globalData.frameRate
             };
             var arr;
-            if(ind === data.k.length - 1){
+            if(ind === data.k.length - 1 && !data.k[ind].h){
                 arr = data.k[ind-1].e;
             }else{
                 arr = data.k[ind].s;
@@ -600,12 +602,15 @@
             BMMath.seedrandom(randSeed + seed);
         };
 
-        var time,velocity, value,textIndex,textTotal,selectorValue, index = elem.data.ind + 1;
+        var time,velocity, value,textIndex,textTotal,selectorValue;
+        var index = elem.data.ind;
         var hasParent = !!(elem.hierarchy && elem.hierarchy.length);
         var parent;
         var randSeed = Math.floor(Math.random()*1000000);
         function execute(){
-            seedRandom(randSeed);
+            if(_needsRandom){
+                seedRandom(randSeed);
+            }
             if(this.frameExpressionId === elem.globalData.frameId && this.type !== 'textSelector'){
                 return;
             }
@@ -645,11 +650,17 @@
                 velocity = velocityAtTime(time);
             }
             bindedFn();
+            if(this.v.length && isNaN(this.v[0])){
+
+                console.log(val)
+            }
             this.frameExpressionId = elem.globalData.frameId;
             var i,len;
             if(this.mult){
-                if(typeof this.v === 'number' || typeof this.v === 'string'){
+                if(typeof this.v === 'number' || this.v instanceof Number || typeof this.v === 'string'){
                     this.v *= this.mult;
+                }else if(this.v.length === 1){
+                    this.v = this.v[0] * this.mult;
                 }else{
                     len = this.v.length;
                     if(value === this.v){
@@ -664,7 +675,10 @@
             /*if(!this.v){
                 console.log(val);
             }*/
-            if(typeof this.v === 'number' || typeof this.v === 'string'){
+            if(this.v.length === 1){
+                this.v = this.v[0];
+            }
+            if(typeof this.v === 'number' || this.v instanceof Number || typeof this.v === 'string'){
                 if(this.lastValue !== this.v){
                     this.lastValue = this.v;
                     this.mdf = true;
@@ -675,8 +689,6 @@
                 this.paths.length = 0;
                 this.paths[0] = this.v;
             }else{
-                /*if(!this.lastValue){
-                }*/
                 len = this.v.length;
                 for(i = 0; i < len; i += 1){
                     if(this.v[i] !== this.lastValue[i]){
diff --git a/player/js/utils/expressions/ExpressionPropertyDecorator.js b/player/js/utils/expressions/ExpressionPropertyDecorator.js
index 45ace06..2627f3c 100644
--- a/player/js/utils/expressions/ExpressionPropertyDecorator.js
+++ b/player/js/utils/expressions/ExpressionPropertyDecorator.js
@@ -1,10 +1,11 @@
-(function addPropertyDecorator(){
+(function addPropertyDecorator() {
 
-    function getStaticValueAtTime(){
+    function getStaticValueAtTime() {
         return this.pv;
     }
 
     function getValueAtTime(frameNum, offsetTime) {
+        frameNum *= this.elem.globalData.frameRate;
         var i = 0,len = this.keyframes.length- 1,dir= 1,flag = true;
         var keyData, nextKeyData;
         offsetTime = offsetTime === undefined ? this.offsetTime : 0;
@@ -31,58 +32,58 @@
         }
 
         var k, kLen,perc,jLen, j = 0, fnc;
-        if(keyData.to){
+        if (keyData.to) {
 
-            if(!keyData.bezierData){
+            if (!keyData.bezierData) {
                 bez.buildBezierData(keyData);
             }
             var bezierData = keyData.bezierData;
-            if(frameNum >= nextKeyData.t-offsetTime || frameNum < keyData.t-offsetTime){
+            if (frameNum >= nextKeyData.t-offsetTime || frameNum < keyData.t-offsetTime) {
                 var ind = frameNum >= nextKeyData.t-offsetTime ? bezierData.points.length - 1 : 0;
                 kLen = bezierData.points[ind].point.length;
                 for(k = 0; k < kLen; k += 1){
                     retVal[k] = bezierData.points[ind].point[k];
                 }
-            }else{
-                if(keyData.__fnct){
+            } else {
+                if (keyData.__fnct) {
                     fnc = keyData.__fnct;
-                }else{
+                } else {
                     //fnc = bez.getEasingCurve(keyData.o.x,keyData.o.y,keyData.i.x,keyData.i.y,keyData.n);
-                    fnc = BezierFactory.getBezierEasing(keyData.o.x,keyData.o.y,keyData.i.x,keyData.i.y,keyData.n).get;
+                    fnc = BezierFactory.getBezierEasing(keyData.o.x, keyData.o.y, keyData.i.x, keyData.i.y, keyData.n).get;
                     keyData.__fnct = fnc;
                 }
-                perc = fnc((frameNum-(keyData.t-offsetTime))/((nextKeyData.t-offsetTime)-(keyData.t-offsetTime)));
-                var distanceInLine = bezierData.segmentLength*perc;
+                perc = fnc((frameNum - (keyData.t - offsetTime)) / ((nextKeyData.t - offsetTime) - (keyData.t - offsetTime)));
+                var distanceInLine = bezierData.segmentLength * perc;
 
                 var segmentPerc;
                 var addedLength = 0;
                 dir = 1;
                 flag = true;
                 jLen = bezierData.points.length;
-                while(flag){
-                    addedLength +=bezierData.points[j].partialLength*dir;
-                    if(distanceInLine === 0 || perc === 0 || j == bezierData.points.length - 1){
+                while(flag) {
+                    addedLength += bezierData.points[j].partialLength*dir;
+                    if (distanceInLine === 0 || perc === 0 || j == bezierData.points.length - 1) {
                         kLen = bezierData.points[j].point.length;
-                        for(k=0;k<kLen;k+=1){
+                        for (k = 0; k < kLen; k += 1) {
                             retVal[k] = bezierData.points[j].point[k];
                         }
                         break;
-                    }else if(distanceInLine >= addedLength && distanceInLine < addedLength + bezierData.points[j+1].partialLength){
-                        segmentPerc = (distanceInLine-addedLength)/(bezierData.points[j+1].partialLength);
+                    } else if (distanceInLine >= addedLength && distanceInLine < addedLength + bezierData.points[j+1].partialLength){
+                        segmentPerc = (distanceInLine - addedLength) / (bezierData.points[j + 1].partialLength);
                         kLen = bezierData.points[j].point.length;
-                        for(k=0;k<kLen;k+=1){
-                            retVal[k] = bezierData.points[j].point[k] + (bezierData.points[j+1].point[k] - bezierData.points[j].point[k])*segmentPerc;
+                        for (k = 0; k < kLen; k += 1) {
+                            retVal[k] = bezierData.points[j].point[k] + (bezierData.points[j+1].point[k] - bezierData.points[j].point[k]) * segmentPerc;
                         }
                         break;
                     }
-                    if(j < jLen - 1 && dir == 1 || j > 0 && dir == -1){
+                    if (j < jLen - 1 && dir == 1 || j > 0 && dir == -1) {
                         j += dir;
-                    }else{
+                    } else {
                         flag = false;
                     }
                 }
             }
-        }else{
+        } else {
             var outX,outY,inX,inY, isArray = false, keyValue;
             len = keyData.s.length;
             for(i=0;i<len;i+=1){
@@ -159,10 +160,9 @@
             return this.vel;
         }
         var delta = -0.01;
-        frameNum *= this.elem.globalData.frameRate;
         //frameNum += this.elem.data.st;
-        var v1 = this.getValueAtTime(frameNum,0);
-        var v2 = this.getValueAtTime(frameNum + delta,0);
+        var v1 = this.getValueAtTime(frameNum, 0);
+        var v2 = this.getValueAtTime(frameNum + delta, 0);
         var velocity;
         if(v1.length){
             velocity = Array.apply(null,{length:v1.length});
@@ -213,9 +213,9 @@
             this.getMult = getValueProxy;
             this.getVelocityAtTime = getVelocityAtTime;
             if(this.kf){
-                this.getValueAtTime = getValueAtTime;
+                this.getValueAtTime = getValueAtTime.bind(this);
             } else {
-                this.getValueAtTime = getStaticValueAtTime;
+                this.getValueAtTime = getStaticValueAtTime.bind(this);
             }
             this.setGroupProperty = setGroupProperty;
         }
@@ -227,9 +227,9 @@
         var prop = propertyGetProp(elem,data,type, mult, arr);
         prop.getVelocityAtTime = getVelocityAtTime;
         if(prop.kf){
-            prop.getValueAtTime = getValueAtTime;
+            prop.getValueAtTime = getValueAtTime.bind(prop);
         } else {
-            prop.getValueAtTime = getStaticValueAtTime;
+            prop.getValueAtTime = getStaticValueAtTime.bind(prop);
         }
         prop.setGroupProperty = setGroupProperty;
         var isAdded = prop.k;
diff --git a/player/js/utils/expressions/ExpressionValue.js b/player/js/utils/expressions/ExpressionValue.js
new file mode 100644
index 0000000..4cdbf33
--- /dev/null
+++ b/player/js/utils/expressions/ExpressionValue.js
@@ -0,0 +1,43 @@
+var ExpressionValue = (function() {
+	return function(elementProp, mult, type) {
+        var expressionValue, arrayValue;
+		if (elementProp.k) {
+            elementProp.getValue();
+        }
+        var i, len, arrValue;
+        if (type) {
+        	if(type === 'color') {
+        		len = 4;
+		        expressionValue = Array.apply(null, {length: len});
+		        arrValue = Array.apply(null, {length: len});
+		        for (i = 0; i < len; i += 1) {
+		            expressionValue[i] = arrValue[i] = (mult && i < 3) ? elementProp.v[i] * mult : 1;
+		        }
+	        	expressionValue.value = arrValue;
+        	}
+        } else if (typeof elementProp.v === 'number' || elementProp.v instanceof Number){
+            expressionValue = mult ? new Number(elementProp.v * mult) : new Number(elementProp.v);
+            expressionValue.value = mult ? elementProp.v * mult : elementProp.v;
+        } else {
+        	len = elementProp.v.length;
+	        expressionValue = Array.apply(null, {length: len});
+	        arrValue = Array.apply(null, {length: len});
+	        for (i = 0; i < len; i += 1) {
+	            expressionValue[i] = arrValue[i] = mult ? elementProp.v[i] * mult : elementProp.v[i];
+	        }
+	        expressionValue.value = arrValue;
+        }
+        
+        expressionValue.numKeys = elementProp.keyframes ? elementProp.keyframes.length : 0;
+        expressionValue.key = function(pos) {
+            if (!expressionValue.numKeys) {
+                return 0;
+            } else {
+                return elementProp.keyframes[pos-1].t;
+            }
+        };
+        expressionValue.valueAtTime = elementProp.getValueAtTime;
+        expressionValue.propertyGroup = elementProp.propertyGroup;
+        return expressionValue;
+	}
+}())
\ No newline at end of file
diff --git a/player/js/utils/expressions/LayerInterface.js b/player/js/utils/expressions/LayerInterface.js
index 78ffb64..93482e5 100644
--- a/player/js/utils/expressions/LayerInterface.js
+++ b/player/js/utils/expressions/LayerInterface.js
@@ -28,6 +28,7 @@
         function _thisLayerFunction(name){
             switch(name){
                 case "ADBE Root Vectors Group":
+                case "Contents":
                 case 2:
                     return _thisLayerFunction.shapeInterface;
                 case 1:
@@ -81,19 +82,50 @@
                 return transformInterface;
             }
         });
+
+        Object.defineProperty(_thisLayerFunction, "width", {
+            get: function () {
+                if(elem.data.ty === 0) {
+                    return elem.data.w
+                }
+                return 100;
+            }
+        });
+
+        Object.defineProperty(_thisLayerFunction, "height", {
+            get: function () {
+                if(elem.data.ty === 0) {
+                    return elem.data.h
+                }
+                return 100;
+            }
+        });
+
+        Object.defineProperty(_thisLayerFunction, "source", {
+            get: function () {
+                return elem.data.refId;
+            }
+        });
+
         Object.defineProperty(_thisLayerFunction, "_name", { value:elem.data.nm });
         Object.defineProperty(_thisLayerFunction, "content", {
             get: function(){
                 return _thisLayerFunction.shapeInterface;
             }
         });
+
+        Object.defineProperty(_thisLayerFunction, "active", {
+            get: function(){
+                return elem.isVisible;
+            }
+        });
+
         Object.defineProperty(_thisLayerFunction, "text", {
             get: function(){
                 return _thisLayerFunction.textInterface;
             }
         });
 
-        _thisLayerFunction.active = true;
         _thisLayerFunction.registerMaskInterface = _registerMaskInterface;
         _thisLayerFunction.registerEffectsInterface = _registerEffectsInterface;
         return _thisLayerFunction;
diff --git a/player/js/utils/expressions/ProjectInterface.js b/player/js/utils/expressions/ProjectInterface.js
index 8fbc138..db262f1 100644
--- a/player/js/utils/expressions/ProjectInterface.js
+++ b/player/js/utils/expressions/ProjectInterface.js
@@ -14,7 +14,6 @@
                 }
                 i+=1;
             }
-            return this.compositions[0].compInterface;
         }
 
         _thisProjectFunction.compositions = [];
diff --git a/player/js/utils/expressions/ShapeInterface.js b/player/js/utils/expressions/ShapeInterface.js
index 143c63b..1b7b056 100644
--- a/player/js/utils/expressions/ShapeInterface.js
+++ b/player/js/utils/expressions/ShapeInterface.js
@@ -133,6 +133,7 @@
             var interfaceFunction = function _interfaceFunction(value){
                 switch(value){
                     case 'ADBE Vectors Group':
+                    case 'Contents':
                     case 2:
                         return interfaceFunction.content;
                     case 'ADBE Vector Transform Group':
@@ -190,25 +191,29 @@
     var fillInterfaceFactory = (function(){
         return function(shape,view,propertyGroup){
 
+            function interfaceFunction(val){
+                if(val === 'Color' || val === 'color'){
+                    return interfaceFunction.color;
+                } else if(val === 'Opacity' || val === 'opacity'){
+                    return interfaceFunction.opacity;
+                }
+            }
+            Object.defineProperty(interfaceFunction, 'color', {
+                get: function(){
+                    return ExpressionValue(view.c, 1 / view.c.mult, 'color');
+                }
+            });
+            Object.defineProperty(interfaceFunction, 'opacity', {
+                get: function(){
+                    return ExpressionValue(view.o, 100);
+                }
+            });
+            Object.defineProperty(interfaceFunction, '_name', { value: shape.nm });
+            Object.defineProperty(interfaceFunction, 'mn', { value: shape.mn });
+
             view.c.setGroupProperty(propertyGroup);
             view.o.setGroupProperty(propertyGroup);
-            var ob = {
-                get color(){
-                    if(view.c.k){
-                        view.c.getValue();
-                    }
-                    return [view.c.v[0]/view.c.mult,view.c.v[1]/view.c.mult,view.c.v[2]/view.c.mult,1];
-                },
-                get opacity(){
-                    if(view.o.k){
-                        view.o.getValue();
-                    }
-                    return view.o.v;
-                },
-                _name: shape.nm,
-                mn: shape.mn
-            };
-            return ob;
+            return interfaceFunction;
         }
     }());
 
@@ -221,46 +226,65 @@
                     return propertyGroup(val-1);
                 }
             };
+            function _dashPropertyGroup(val){
+                if(val === 1){
+                    return dashOb;
+                } else{
+                    return _propertyGroup(val-1);
+                }
+            };
+            function addPropertyToDashOb(i) {
+                Object.defineProperty(dashOb, shape.d[i].nm, {
+                    get: function(){
+                        return ExpressionValue(view.d.dataProps[i].p)
+                    }
+                });
+            }
             view.c.setGroupProperty(_propertyGroup);
             view.o.setGroupProperty(_propertyGroup);
             view.w.setGroupProperty(_propertyGroup);
-            var ob = {
-                get color(){
-                    if(view.c.k){
-                        view.c.getValue();
-                    }
-                    return [view.c.v[0]/view.c.mult,view.c.v[1]/view.c.mult,view.c.v[2]/view.c.mult,1];
-                },
-                get opacity(){
-                    if(view.o.k){
-                        view.o.getValue();
-                    }
-                    return view.o.v;
-                },
-                get strokeWidth(){
-                    if(view.w.k){
-                        view.w.getValue();
-                    }
-                    return view.w.v;
-                },
-                dashOb: {},
-                get dash(){
-                    var d = view.d;
-                    var dModels = shape.d;
-                    var i, len = dModels.length;
-                    for(i=0;i<len;i+=1){
-                        if(d.dataProps[i].p.k){
-                            d.dataProps[i].p.getValue();
-                        }
-                        d.dataProps[i].p.setGroupProperty(propertyGroup);
-                        this.dashOb[dModels[i].nm] = d.dataProps[i].p.v;
-                    }
-                    return this.dashOb;
-                },
-                _name: shape.nm,
-                mn: shape.mn
-            };
-            return ob;
+            var i, len = shape.d ? shape.d.length : 0;
+            var dashOb = {}
+            for (i = 0; i < len; i += 1) {
+                addPropertyToDashOb(i);
+                view.d.dataProps[i].p.setGroupProperty(_dashPropertyGroup);
+            }
+
+            function interfaceFunction(val){
+                if(val === 'Color' || val === 'color'){
+                    return interfaceFunction.color;
+                } else if(val === 'Opacity' || val === 'opacity'){
+                    return interfaceFunction.opacity;
+                } else if(val === 'Stroke Width' || val === 'stroke width'){
+                    return interfaceFunction.strokeWidth;
+                }
+            }
+            Object.defineProperty(interfaceFunction, 'color', {
+                get: function(){
+                    return ExpressionValue(view.c, 1 / view.c.mult, 'color');
+                }
+            });
+            Object.defineProperty(interfaceFunction, 'opacity', {
+                get: function(){
+                    return ExpressionValue(view.o, 100);
+                }
+            });
+            Object.defineProperty(interfaceFunction, 'strokeWidth', {
+                get: function(){
+                    return ExpressionValue(view.w);
+                }
+            });
+            Object.defineProperty(interfaceFunction, 'dash', {
+                get: function(){
+                    return dashOb;
+                }
+            });
+            Object.defineProperty(interfaceFunction, '_name', { value: shape.nm });
+            Object.defineProperty(interfaceFunction, 'mn', { value: shape.mn });
+
+            view.c.setGroupProperty(propertyGroup);
+            view.o.setGroupProperty(propertyGroup);
+            return interfaceFunction;
         }
     }());
 
@@ -293,26 +317,17 @@
             interfaceFunction.propertyIndex = shape.ix;
             Object.defineProperty(interfaceFunction, 'start', {
                 get: function(){
-                    if(view.s.k){
-                        view.s.getValue();
-                    }
-                    return view.s.v/view.s.mult;
+                    return ExpressionValue(view.s, 1 / view.s.mult);
                 }
             });
             Object.defineProperty(interfaceFunction, 'end', {
                 get: function(){
-                    if(view.e.k){
-                        view.e.getValue();
-                    }
-                    return view.e.v/view.e.mult;
+                    return ExpressionValue(view.e, 1 / view.e.mult);
                 }
             });
             Object.defineProperty(interfaceFunction, 'offset', {
                 get: function(){
-                    if(view.o.k){
-                        view.o.getValue();
-                    }
-                    return view.o.v;
+                    return ExpressionValue(view.o);
                 }
             });
             Object.defineProperty(interfaceFunction, '_name', {
@@ -392,61 +407,38 @@
             }
             Object.defineProperty(interfaceFunction, 'opacity', {
                 get: function(){
-                    if(view.transform.mProps.o.k){
-                        view.transform.mProps.o.getValue();
-                    }
-                    return view.transform.mProps.o.v/view.transform.mProps.o.mult;
+                    return ExpressionValue(view.transform.mProps.o, 1/view.transform.mProps.o.mult);
                 }
             });
             Object.defineProperty(interfaceFunction, 'position', {
                 get: function(){
-                    if(view.transform.mProps.p.k){
-                        view.transform.mProps.p.getValue();
-                    }
-                    return [view.transform.mProps.p.v[0],view.transform.mProps.p.v[1]];
+                    return ExpressionValue(view.transform.mProps.p);
                 }
             });
             Object.defineProperty(interfaceFunction, 'anchorPoint', {
                 get: function(){
-                    if(view.transform.mProps.a.k){
-                        view.transform.mProps.a.getValue();
-                    }
-                    return [view.transform.mProps.a.v[0],view.transform.mProps.a.v[1]];
+                    return ExpressionValue(view.transform.mProps.a);
                 }
             });
             var scaleArray = [];
             Object.defineProperty(interfaceFunction, 'scale', {
                 get: function(){
-                    if(view.transform.mProps.s.k){
-                        view.transform.mProps.s.getValue();
-                    }
-                    scaleArray[0] = view.transform.mProps.s.v[0]/view.transform.mProps.s.mult;
-                    scaleArray[1] = view.transform.mProps.s.v[1]/view.transform.mProps.s.mult;
-                    return scaleArray;
+                    return ExpressionValue(view.transform.mProps.s, 1 / view.transform.mProps.s.mult);
                 }
             });
             Object.defineProperty(interfaceFunction, 'rotation', {
                 get: function(){
-                    if(view.transform.mProps.r.k){
-                        view.transform.mProps.r.getValue();
-                    }
-                    return view.transform.mProps.r.v/view.transform.mProps.r.mult;
+                    return ExpressionValue(view.transform.mProps.r, 1 / view.transform.mProps.r.mult);
                 }
             });
             Object.defineProperty(interfaceFunction, 'skew', {
                 get: function(){
-                    if(view.transform.mProps.sk.k){
-                        view.transform.mProps.sk.getValue();
-                    }
-                    return view.transform.mProps.sk.v;
+                    return ExpressionValue(view.transform.mProps.sk);
                 }
             });
             Object.defineProperty(interfaceFunction, 'skewAxis', {
                 get: function(){
-                    if(view.transform.mProps.sa.k){
-                        view.transform.mProps.sa.getValue();
-                    }
-                    return view.transform.mProps.sa.v;
+                    return ExpressionValue(view.transform.mProps.sa);
                 }
             });
             Object.defineProperty(interfaceFunction, '_name', {
@@ -483,18 +475,12 @@
             }
             Object.defineProperty(interfaceFunction, 'size', {
                 get: function(){
-                    if(prop.s.k){
-                        prop.s.getValue();
-                    }
-                    return [prop.s.v[0],prop.s.v[1]];
+                    return ExpressionValue(prop.s);
                 }
             });
             Object.defineProperty(interfaceFunction, 'position', {
                 get: function(){
-                    if(prop.p.k){
-                        prop.p.getValue();
-                    }
-                    return [prop.p.v[0],prop.p.v[1]];
+                    return ExpressionValue(prop.p);
                 }
             });
             Object.defineProperty(interfaceFunction, '_name', {
@@ -554,42 +540,27 @@
             }
             Object.defineProperty(interfaceFunction, 'position', {
                 get: function(){
-                    if(prop.p.k){
-                        prop.p.getValue();
-                    }
-                    return prop.p.v;
+                    return ExpressionValue(prop.p);
                 }
             });
             Object.defineProperty(interfaceFunction, 'rotation', {
                 get: function(){
-                    if(prop.r.k){
-                        prop.r.getValue();
-                    }
-                    return prop.r.v/prop.r.mult;
+                    return ExpressionValue(prop.r, 1 / prop.r.mult);
                 }
             });
             Object.defineProperty(interfaceFunction, 'points', {
                 get: function(){
-                    if(prop.pt.k){
-                        prop.pt.getValue();
-                    }
-                    return prop.pt.v;
+                    return ExpressionValue(prop.pt);
                 }
             });
             Object.defineProperty(interfaceFunction, 'outerRadius', {
                 get: function(){
-                    if(prop.or.k){
-                        prop.or.getValue();
-                    }
-                    return prop.or.v;
+                    return ExpressionValue(prop.or);
                 }
             });
             Object.defineProperty(interfaceFunction, 'outerRoundness', {
                 get: function(){
-                    if(prop.os.k){
-                        prop.os.getValue();
-                    }
-                    return prop.os.v/prop.os.mult;
+                    return ExpressionValue(prop.os);
                 }
             });
             Object.defineProperty(interfaceFunction, 'innerRadius', {
@@ -597,10 +568,7 @@
                     if(!prop.ir){
                         return 0;
                     }
-                    if(prop.ir.k){
-                        prop.ir.getValue();
-                    }
-                    return prop.ir.v;
+                    return ExpressionValue(prop.ir);
                 }
             });
             Object.defineProperty(interfaceFunction, 'innerRoundness', {
@@ -608,10 +576,7 @@
                     if(!prop.is){
                         return 0;
                     }
-                    if(prop.is.k){
-                        prop.is.getValue();
-                    }
-                    return prop.is.v/prop.is.mult;
+                    return ExpressionValue(prop.is, 1 / prop.is.mult);
                 }
             });
             Object.defineProperty(interfaceFunction, '_name', {
@@ -665,26 +630,17 @@
             }
             Object.defineProperty(interfaceFunction, 'position', {
                 get: function(){
-                    if(prop.p.k){
-                        prop.p.getValue();
-                    }
-                    return prop.p.v;
+                    return ExpressionValue(prop.p);
                 }
             });
             Object.defineProperty(interfaceFunction, 'roundness', {
                 get: function(){
-                    if(prop.r.k){
-                        prop.r.getValue();
-                    }
-                    return prop.r.v;
+                    return ExpressionValue(prop.r);
                 }
             });
             Object.defineProperty(interfaceFunction, 'size', {
                 get: function(){
-                    if(prop.s.k){
-                        prop.s.getValue();
-                    }
-                    return prop.s.v;
+                    return ExpressionValue(prop.s);
                 }
             });
 
@@ -719,10 +675,7 @@
             }
             Object.defineProperty(interfaceFunction, 'radius', {
                 get: function(){
-                    if(prop.rd.k){
-                        prop.rd.getValue();
-                    }
-                    return prop.rd.v;
+                    return ExpressionValue(prop.rd);
                 }
             });
 
@@ -740,23 +693,31 @@
         return function(shape,view,propertyGroup){
             var prop = view.sh.ty === 'tm' ? view.sh.prop : view.sh;
             prop.setGroupProperty(propertyGroup);
-            var ob = {
-                get shape(){
-                    if(prop.k){
-                        prop.getValue();
-                    }
-                    return prop.v;
-                },
-                get path(){
-                    if(prop.k){
-                        prop.getValue();
-                    }
-                    return prop.v;
-                },
-                _name: shape.nm,
-                mn: shape.mn
+
+            function interfaceFunction(val){
+                if(val === 'Shape' || val === 'shape' || val === 'Path' || val === 'path'){
+                    return interfaceFunction.path;
+                }
             }
-            return ob;
+            Object.defineProperty(interfaceFunction, 'path', {
+                get: function(){
+                    if(prop.k){
+                        prop.getValue();
+                    }
+                    return shape_helper.clone(prop.v);
+                }
+            });
+            Object.defineProperty(interfaceFunction, 'shape', {
+                get: function(){
+                    if(prop.k){
+                        prop.getValue();
+                    }
+                    return shape_helper.clone(prop.v);
+                }
+            });
+            Object.defineProperty(interfaceFunction, '_name', { value: shape.nm });
+            Object.defineProperty(interfaceFunction, 'mn', { value: shape.mn });
+            return interfaceFunction;
         }
     }());
 
diff --git a/player/js/utils/expressions/TransformInterface.js b/player/js/utils/expressions/TransformInterface.js
index cf1aa9d..71c6e88 100644
--- a/player/js/utils/expressions/TransformInterface.js
+++ b/player/js/utils/expressions/TransformInterface.js
@@ -9,6 +9,7 @@
                 case "rotation":
                 case "Rotation":
                 case "ADBE Rotation":
+                case "ADBE Rotate Z":
                     return _thisFunction.rotation;
                 case "position":
                 case "Position":
@@ -16,6 +17,7 @@
                     return transform.position;
                 case "anchorPoint":
                 case "AnchorPoint":
+                case "Anchor Point":
                 case "ADBE AnchorPoint":
                     return _thisFunction.anchorPoint;
                 case "opacity":
@@ -31,13 +33,7 @@
         });
         Object.defineProperty(_thisFunction, "scale", {
             get: function () {
-                var s = transform.scale;
-                var i, len = s.length;
-                var transformedS = Array.apply(null,{length:len});
-                for(i=0;i<len;i+=1){
-                    transformedS[i] = s[i]*100;
-                }
-                return transformedS;
+                return transform.scale;
             }
         });
 
@@ -67,7 +63,7 @@
 
         Object.defineProperty(_thisFunction, "opacity", {
             get: function () {
-                return transform.opacity*100;
+                return transform.opacity;
             }
         });
 
diff --git a/player/js/utils/shapes/shape_helper.js b/player/js/utils/shapes/shape_helper.js
new file mode 100644
index 0000000..ac097f1
--- /dev/null
+++ b/player/js/utils/shapes/shape_helper.js
@@ -0,0 +1,23 @@
+var shape_helper = (function(){
+
+	function clone(shape){
+		var i, len = shape.v.length;
+		var cloned = {
+			c: shape.c,
+			i: Array.call({length:len}),
+			o: Array.call({length:len}),
+			v: Array.call({length:len})
+		}
+		for(i = 0; i < len; i += 1) {
+			cloned.v[i] = [shape.v[i][0],shape.v[i][1]]
+			cloned.o[i] = [shape.o[i][0],shape.o[i][1]]
+			cloned.i[i] = [shape.i[i][0],shape.i[i][1]]
+		}
+		return cloned
+
+	}
+
+	return {
+		clone: clone
+	}
+}())
\ No newline at end of file