added smooth expression support
diff --git a/player/js/utils/expressions/ExpressionManager.js b/player/js/utils/expressions/ExpressionManager.js
index 98c9422..36ae813 100644
--- a/player/js/utils/expressions/ExpressionManager.js
+++ b/player/js/utils/expressions/ExpressionManager.js
@@ -348,7 +348,7 @@
         var width = elem.data.sw ? elem.data.sw : 0;
         var height = elem.data.sh ? elem.data.sh : 0;
         var name = elem.data.nm;
-        var loopIn, loop_in, loopOut, loop_out;
+        var loopIn, loop_in, loopOut, loop_out, smooth;
         var toWorld,fromWorld,fromComp,toComp,fromCompToSurface, position, rotation, anchorPoint, scale, thisLayer,thisComp,mask,valueAtTime,velocityAtTime;
         var __expression_functions = [];
         if(data.xf) {
@@ -405,6 +405,10 @@
             loop_out = loopOut;
         }
 
+        if(thisProperty.smooth) {
+            smooth = thisProperty.smooth.bind(thisProperty);
+        }
+
         function loopInDuration(type,duration){
             return loopIn(type,duration,true);
         }
diff --git a/player/js/utils/expressions/ExpressionPropertyDecorator.js b/player/js/utils/expressions/ExpressionPropertyDecorator.js
index 5bf057d..5a0b4fb 100644
--- a/player/js/utils/expressions/ExpressionPropertyDecorator.js
+++ b/player/js/utils/expressions/ExpressionPropertyDecorator.js
@@ -130,6 +130,48 @@
         }
     }
 
+    function smooth(width, samples) {
+        if (!this.k){
+            return this.pv;
+        }
+        width = (width || 0.4) * 0.5;
+        samples = Math.floor(samples || 5);
+        if (samples <= 1) {
+            return this.pv;
+        }
+        var currentTime = this.comp.renderedFrame / this.comp.globalData.frameRate;
+        var initFrame = currentTime - width;
+        var endFrame = currentTime + width;
+        var sampleFrequency = samples > 1 ? (endFrame - initFrame) / (samples - 1) : 1;
+        var i = 0, j = 0;
+        var value;
+        if (this.pv.length) {
+            value = createTypedArray('float32', this.pv.length);
+        } else {
+            value = 0;
+        }
+        var sampleValue;
+        while (i < samples) {
+            sampleValue = this.getValueAtTime(initFrame + i * sampleFrequency);
+            if(this.pv.length) {
+                for (j = 0; j < this.pv.length; j += 1) {
+                    value[j] += sampleValue[j];
+                }
+            } else {
+                value += sampleValue;
+            }
+            i += 1;
+        }
+        if(this.pv.length) {
+            for (j = 0; j < this.pv.length; j += 1) {
+                value[j] /= samples;
+            }
+        } else {
+            value /= samples;
+        }
+        return value;
+    }
+
     function getValueAtTime(frameNum) {
         frameNum *= this.elem.globalData.frameRate;
         frameNum -= this.offsetTime;
@@ -260,6 +302,7 @@
         prop.setGroupProperty = setGroupProperty;
         prop.loopOut = loopOut;
         prop.loopIn = loopIn;
+        prop.smooth = smooth;
         prop.getVelocityAtTime = getVelocityAtTime.bind(prop);
         prop.getSpeedAtTime = getSpeedAtTime.bind(prop);
         prop.numKeys = data.a === 1 ? data.k.length : 0;