first elements
diff --git a/player/index.html b/player/index.html
index e62da68..a2f3fab 100644
--- a/player/index.html
+++ b/player/index.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
+    <meta charset="utf-8"/>
     <style>
         body, html{
             background-color:#ddd;
@@ -27,6 +28,7 @@
         }
 
     </style>
+     <script src="three.min.js"></script>
     <!-- build:js bodymovin.js -->
      <script src="js/main.js"></script>
     <script src="js/utils/common.js"></script>
@@ -39,6 +41,7 @@
     <script src="js/utils/bez.js"></script>
     <script src="js/utils/DataManager.js"></script>
     <script src="js/utils/FontManager.js"></script>
+    <script src="js/utils/TransformProperty.js"></script>
     <script src="js/utils/PropertyFactory.js"></script>
     <script src="js/utils/shapes/ShapePath.js"></script>
     <script src="js/utils/shapes/ShapeProperty.js"></script>
@@ -58,6 +61,7 @@
     <script src="js/renderers/SVGRenderer.js"></script>
     <script src="js/renderers/CanvasRenderer.js" data-light-skip="true"></script>
     <script src="js/renderers/HybridRenderer.js" data-light-skip="true"></script>
+    <script src="js/renderers/ThreejsRenderer.js" data-light-skip="true"></script>
     <script src="js/mask.js"></script>
     <script src="js/elements/BaseElement.js"></script>
     <script src="js/elements/svgElements/SVGBaseElement.js"></script>
@@ -88,6 +92,11 @@
     <script src="js/elements/htmlElements/HTextElement.js" data-light-skip="true"></script>
     <script src="js/elements/htmlElements/HImageElement.js" data-light-skip="true"></script>
     <script src="js/elements/htmlElements/HCameraElement.js" data-light-skip="true"></script>
+    <script src="js/elements/threejsElements/TBaseElement.js" data-light-skip="true"></script>
+    <script src="js/elements/threejsElements/TCameraElement.js" data-light-skip="true"></script>
+    <script src="js/elements/threejsElements/TSolidElement.js" data-light-skip="true"></script>
+    <script src="js/elements/threejsElements/TImageElement.js" data-light-skip="true"></script>
+    <script src="js/elements/threejsElements/TMaskElement.js" data-light-skip="true"></script>
     <script src="js/animation/AnimationManager.js"></script>
     <script src="js/animation/AnimationItem.js"></script>
     <!-- Expressions -->
@@ -119,8 +128,8 @@
     var elem = document.getElementById('bodymovin')
     var animData = {
         container: elem,
-        renderer: 'svg',
-        loop: true,
+        renderer: 'three',
+        loop: false,
         autoplay: true,
         rendererSettings: {
             progressiveLoad:false
diff --git a/player/js/animation/AnimationItem.js b/player/js/animation/AnimationItem.js
index 7df5f96..f5ec04d 100644
--- a/player/js/animation/AnimationItem.js
+++ b/player/js/animation/AnimationItem.js
@@ -48,6 +48,9 @@
         case 'svg':
             this.renderer = new SVGRenderer(this, params.rendererSettings);
             break;
+        case 'three':
+            this.renderer = new ThreejsRenderer(this, params.rendererSettings);
+            break;
         case 'hybrid':
         case 'html':
         default:
diff --git a/player/js/elements/BaseElement.js b/player/js/elements/BaseElement.js
index 833c499..3ca9ab6 100644
--- a/player/js/elements/BaseElement.js
+++ b/player/js/elements/BaseElement.js
@@ -186,7 +186,7 @@
     this.lastNum = -99999;
     if(this.data.ks){
         this.finalTransform = {
-            mProp: PropertyFactory.getProp(this,this.data.ks,2,null,this.dynamicProperties),
+            mProp: new TransformProperty(this,this.data.ks, this.dynamicProperties, this.elementType === 'three'),
             matMdf: false,
             opMdf: false,
             mat: new Matrix(),
diff --git a/player/js/elements/ShapeElement.js b/player/js/elements/ShapeElement.js
index 1c278ac..31e9051 100644
--- a/player/js/elements/ShapeElement.js
+++ b/player/js/elements/ShapeElement.js
@@ -184,7 +184,7 @@
             data[i] = {
                 transform : {
                     op: PropertyFactory.getProp(this,arr[i].o,0,0.01,dynamicProperties),
-                    mProps: PropertyFactory.getProp(this,arr[i],2,null,dynamicProperties)
+                    mProps: new TransformProperty(this,arr[i], dynamicProperties)
                 },
                 elements: []
             };
diff --git a/player/js/elements/ShapeItemElement.js b/player/js/elements/ShapeItemElement.js
index f6f8371..db1f60f 100644
--- a/player/js/elements/ShapeItemElement.js
+++ b/player/js/elements/ShapeItemElement.js
@@ -111,7 +111,7 @@
                     matMdf:false,
                     opMdf:false,
                     op: PropertyFactory.getProp(this.elemData,arr[i].o,0,0.01,dynamicProperties),
-                    mProps: PropertyFactory.getProp(this.elemData,arr[i],2,null,dynamicProperties)
+                    mProps: new TransformProperty(this.elemData,arr[i], dynamicProperties)
                 },
                 elements: []
             };
diff --git a/player/js/elements/canvasElements/CVShapeElement.js b/player/js/elements/canvasElements/CVShapeElement.js
index c09a6dd..b411906 100644
--- a/player/js/elements/canvasElements/CVShapeElement.js
+++ b/player/js/elements/canvasElements/CVShapeElement.js
@@ -86,7 +86,7 @@
                     matMdf:false,
                     opMdf:false,
                     op: PropertyFactory.getProp(this,arr[i].o,0,0.01,dynamicProperties),
-                    mProps: PropertyFactory.getProp(this,arr[i],2,null,dynamicProperties)
+                    mProps: new TransformProperty(this,arr[i], dynamicProperties)
                 },
                 elements: []
             };
diff --git a/player/js/elements/canvasElements/CVShapeItemElement.js b/player/js/elements/canvasElements/CVShapeItemElement.js
index 5069285..06b1101 100644
--- a/player/js/elements/canvasElements/CVShapeItemElement.js
+++ b/player/js/elements/canvasElements/CVShapeItemElement.js
@@ -72,7 +72,7 @@
                     matMdf:false,
                     opMdf:false,
                     op: PropertyFactory.getProp(this.elemData,arr[i].o,0,0.01,dynamicProperties),
-                    mProps: PropertyFactory.getProp(this.elemData,arr[i],2,null,dynamicProperties)
+                    mProps: new TransformProperty(this.elemData,arr[i], dynamicProperties)
                 },
                 elements: []
             };
diff --git a/player/js/elements/threejsElements/TBaseElement.js b/player/js/elements/threejsElements/TBaseElement.js
new file mode 100644
index 0000000..c7a4976
--- /dev/null
+++ b/player/js/elements/threejsElements/TBaseElement.js
@@ -0,0 +1,147 @@
+function TBaseElement(data,parentContainer,globalData,comp, placeholder){
+    this.globalData = globalData;
+    this.elementType = 'three';
+    this.comp = comp;
+    this.data = data;
+    this.matteElement = null;
+    this.parentContainer = parentContainer;
+    this.layerId = placeholder ? placeholder.layerId : 'ly_'+randomString(10);
+    this.placeholder = placeholder;
+    this.init();
+};
+
+createElement(BaseElement, TBaseElement);
+TBaseElement.prototype.checkBlendMode = function(){
+
+};
+TBaseElement.prototype.setBlendMode = BaseElement.prototype.setBlendMode;
+
+
+TBaseElement.prototype.getBaseElement = function(){
+    return this.baseElement;
+};
+
+TBaseElement.prototype.createElements = function(){
+    if(this.data.hasMask){
+        this.layerElement = document.createElementNS(svgNS,'svg');
+        styleDiv(this.layerElement);
+        //this.appendNodeToParent(this.layerElement);
+        this.baseElement = this.layerElement;
+        this.maskedElement = this.layerElement;
+    }else{
+        this.layerElement = this.parentContainer;
+    }
+    this.transformedElement = this.layerElement;
+    if(this.data.ln && (this.data.ty === 4 || this.data.ty === 0)){
+        if(this.layerElement === this.parentContainer){
+            this.layerElement = document.createElementNS(svgNS,'g');
+            //this.appendNodeToParent(this.layerElement);
+            this.baseElement = this.layerElement;
+        }
+        this.layerElement.setAttribute('id',this.data.ln);
+    }
+    this.setBlendMode();
+    if(this.layerElement !== this.parentContainer){
+        this.placeholder = null;
+    }
+    this.checkParenting();
+};
+
+TBaseElement.prototype.renderFrame = function(parentTransform){
+    if(this.data.ty === 3){
+        return false;
+    }
+
+    if(this.currentFrameNum === this.lastNum || !this.isVisible){
+        return this.isVisible;
+    }
+    this.lastNum = this.currentFrameNum;
+
+    this.finalTransform.opMdf = this.finalTransform.op.mdf;
+    this.finalTransform.matMdf = this.finalTransform.mProp.mdf;
+    this.finalTransform.opacity = this.finalTransform.op.v;
+    if(this.firstFrame){
+        this.finalTransform.opMdf = true;
+        this.finalTransform.matMdf = true;
+    }
+
+    var mat;
+    var finalMat = this.finalTransform.mat;
+
+    if(this.hierarchy){
+        var i, len = this.hierarchy.length;
+
+        mat = this.finalTransform.mProp.v.props;
+        finalMat.cloneFromProps(mat);
+        for(i=0;i<len;i+=1){
+            this.finalTransform.matMdf = this.hierarchy[i].finalTransform.mProp.mdf ? true : this.finalTransform.matMdf;
+            mat = this.hierarchy[i].finalTransform.mProp.v.props;
+            finalMat.transform(mat[0],mat[1],mat[2],mat[3],mat[4],mat[5],mat[6],mat[7],mat[8],mat[9],mat[10],mat[11],mat[12],mat[13],mat[14],mat[15]);
+        }
+    }else{
+        if(this.isVisible && this.finalTransform.matMdf){
+            if(!parentTransform){
+                finalMat.cloneFromProps(this.finalTransform.mProp.v.props);
+            }else{
+                mat = this.finalTransform.mProp.v.props;
+                finalMat.cloneFromProps(mat);
+            }
+        }
+    }
+    if(this.data.hasMask){
+        this.maskManager.renderFrame(finalMat);
+    }
+
+    if(parentTransform){
+        mat = parentTransform.mat.props;
+        finalMat.cloneFromProps(mat);
+        this.finalTransform.opacity *= parentTransform.opacity;
+        this.finalTransform.opMdf = parentTransform.opMdf ? true : this.finalTransform.opMdf;
+        this.finalTransform.matMdf = parentTransform.matMdf ? true : this.finalTransform.matMdf
+    }
+
+    if(this.finalTransform.matMdf){
+        var threeFinalMat = new Matrix();
+        threeFinalMat.translate(-this.globalData.compSize.w/2,-this.globalData.compSize.h/2,0);
+        mat = finalMat.props;
+        threeFinalMat.transform(mat[0],mat[1],mat[2],mat[3],mat[4],mat[5],mat[6],mat[7],mat[8],mat[9],mat[10],mat[11],mat[12],mat[13],mat[14],mat[15]);
+        this.finalMat = finalMat;
+    }
+    if(this.finalTransform.opMdf){
+        //this.transformedElement.style.opacity = this.finalTransform.opacity;
+    }
+    return this.isVisible;
+};
+
+TBaseElement.prototype.destroy = function(){
+    this.layerElement = null;
+    this.transformedElement = null;
+    this.parentContainer = null;
+    if(this.matteElement) {
+        this.matteElement = null;
+    }
+    if(this.maskManager) {
+        this.maskManager.destroy();
+        this.maskManager = null;
+    }
+};
+
+TBaseElement.prototype.getDomElement = function(){
+    return this.layerElement;
+};
+TBaseElement.prototype.addMasks = function(data){
+    this.maskManager = new MaskElement(data,this,this.globalData);
+};
+
+TBaseElement.prototype.hide = function(){
+};
+
+TBaseElement.prototype.addMasks = function(data){
+    this.maskManager = new TMaskElement(data,this,this.globalData);
+};
+
+TBaseElement.prototype.setMatte = function(){
+
+}
+
+TBaseElement.prototype.buildElementParenting = ThreejsRenderer.prototype.buildElementParenting;
\ No newline at end of file
diff --git a/player/js/elements/threejsElements/TCameraElement.js b/player/js/elements/threejsElements/TCameraElement.js
new file mode 100644
index 0000000..6cfa87c
--- /dev/null
+++ b/player/js/elements/threejsElements/TCameraElement.js
@@ -0,0 +1,119 @@
+function TCameraElement(data,parentContainer,globalData,comp, placeholder){
+    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
+    this.pe = PropertyFactory.getProp(this,data.pe,0,0,this.dynamicProperties);
+    if(data.ks.p.s){
+        this.px = PropertyFactory.getProp(this,data.ks.p.x,1,0,this.dynamicProperties);
+        this.py = PropertyFactory.getProp(this,data.ks.p.y,1,0,this.dynamicProperties);
+        this.pz = PropertyFactory.getProp(this,data.ks.p.z,1,0,this.dynamicProperties);
+    }else{
+        this.p = PropertyFactory.getProp(this,data.ks.p,1,0,this.dynamicProperties);
+    }
+    if(data.ks.a){
+        this.a = PropertyFactory.getProp(this,data.ks.a,1,0,this.dynamicProperties);
+    }
+    if(data.ks.or.k.length && data.ks.or.k[0].to){
+        var i,len = data.ks.or.k.length;
+        for(i=0;i<len;i+=1){
+            data.ks.or.k[i].to = null;
+            data.ks.or.k[i].ti = null;
+        }
+    }
+    this.or = PropertyFactory.getProp(this,data.ks.or,1,degToRads,this.dynamicProperties);
+    this.or.sh = true;
+    this.rx = PropertyFactory.getProp(this,data.ks.rx,0,degToRads,this.dynamicProperties);
+    this.ry = PropertyFactory.getProp(this,data.ks.ry,0,degToRads,this.dynamicProperties);
+    this.rz = PropertyFactory.getProp(this,data.ks.rz,0,degToRads,this.dynamicProperties);
+    this.mat = new Matrix();
+
+    var vFOV = 2 * Math.atan( globalData.compSize.h / ( 2 * 1111 ) );
+    vFOV = vFOV * 180 / Math.PI;
+    //console.log('vFOV:', vFOV)
+    var camera = new THREE.PerspectiveCamera( vFOV, globalData.compSize.w / globalData.compSize.h, 1, 10000 );
+    camera.matrixAutoUpdate = false;
+    /*camera.position.x = 0;
+    camera.position.y = 0;*/
+    //camera.position.z = 1111;
+    this.threeCamera = camera;
+}
+createElement(TBaseElement, TCameraElement);
+
+TCameraElement.prototype.setup = function() {
+    var i, len = this.comp.threeDElements.length, comp;
+    for(i=0;i<len;i+=1){
+        //[perspectiveElem,container]
+        comp = this.comp.threeDElements[i];
+        comp.perspectiveElem.style.perspective = comp.perspectiveElem.style.webkitPerspective = this.pe.v+'px';
+        comp.container.style.transformOrigin = comp.container.style.mozTransformOrigin = comp.container.style.webkitTransformOrigin = "0px 0px 0px";
+        comp.perspectiveElem.style.transform = comp.perspectiveElem.style.webkitTransform = 'matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)';
+    }
+};
+
+TCameraElement.prototype.createElements = function(){
+};
+
+TCameraElement.prototype.hide = function(){
+};
+
+TCameraElement.prototype.renderFrame = function(){
+    var mdf = this.firstFrame;
+    var i, len;
+    if(this.hierarchy){
+        len = this.hierarchy.length;
+        for(i=0;i<len;i+=1){
+            mdf = this.hierarchy[i].finalTransform.mProp.mdf ? true : mdf;
+        }
+    }
+    if(mdf || (this.p && this.p.mdf) || (this.px && (this.px.mdf || this.py.mdf || this.pz.mdf)) || this.rx.mdf || this.ry.mdf || this.rz.mdf || this.or.mdf || (this.a && this.a.mdf)) {
+        this.mat.reset();
+        //this.mat.translate(-this.globalData.compSize.w/2,-this.globalData.compSize.h/2,0);
+
+        if(this.p){
+            this.mat.translate(this.p.v[0],-this.p.v[1],this.p.v[2]);
+        }else{
+            this.mat.translate(this.px.v,-this.py.v,this.pz.v);
+        }
+        if(this.a){
+            var diffVector = [this.p.v[0]-this.a.v[0],this.p.v[1]-this.a.v[1],this.p.v[2]-this.a.v[2]];
+            var mag = Math.sqrt(Math.pow(diffVector[0],2)+Math.pow(diffVector[1],2)+Math.pow(diffVector[2],2));
+            //var lookDir = getNormalizedPoint(getDiffVector(this.a.v,this.p.v));
+            var lookDir = [diffVector[0]/mag,diffVector[1]/mag,diffVector[2]/mag];
+            var lookLengthOnXZ = Math.sqrt( lookDir[2]*lookDir[2] + lookDir[0]*lookDir[0] );
+            var m_rotationX = (Math.atan2( lookDir[1], lookLengthOnXZ ));
+            var m_rotationY = (Math.atan2( lookDir[0], -lookDir[2]));
+            this.mat.rotateY(m_rotationY).rotateX(-m_rotationX);
+
+        }
+        this.mat.rotateX(-this.rx.v).rotateY(-this.ry.v).rotateZ(this.rz.v);
+        this.mat.rotateX(-this.or.v[0]).rotateY(-this.or.v[1]).rotateZ(this.or.v[2]);
+        if(this.hierarchy){
+            var mat;
+            len = this.hierarchy.length;
+            for(i=0;i<len;i+=1){
+                mat = this.hierarchy[i].finalTransform.mProp.iv.props;
+                this.mat.transform(mat[0],mat[1],mat[2],mat[3],mat[4],mat[5],mat[6],mat[7],mat[8],mat[9],mat[10],mat[11],-mat[12],-mat[13],mat[14],mat[15]);
+            }
+        }
+    }
+    var mat = this.mat.props;
+    //console.log(this.globalData.compSize.w);
+    //console.log(mat);
+    /*this.threeCamera.matrix.set(mat[0],mat[1],mat[2],mat[3]
+        ,mat[4],mat[5],mat[6],mat[7]
+        ,mat[8],mat[9],mat[10],mat[11]
+        ,mat[12],mat[13],mat[14],mat[15]);
+    this.threeCamera.updateMatrixWorld( true );*/
+    /*this.threeCamera.matrix.set(1,0,0,_count
+        ,0,1,0,0
+        ,0,0,1, 1111
+        ,0,0,0, 1);*/
+    //console.log('mat:', mat);
+    this.threeCamera.matrix.set(mat[0],mat[4],mat[8],mat[12]
+        ,mat[1],mat[5],mat[9],mat[13]
+        ,mat[2],mat[6],mat[10], -mat[14]
+        ,mat[3],mat[7],mat[11], mat[15]);
+    this.threeCamera.updateMatrixWorld( true );
+    this.firstFrame = false;
+};
+
+TCameraElement.prototype.destroy = function(){
+};
\ No newline at end of file
diff --git a/player/js/elements/threejsElements/TImageElement.js b/player/js/elements/threejsElements/TImageElement.js
new file mode 100644
index 0000000..9a5aa24
--- /dev/null
+++ b/player/js/elements/threejsElements/TImageElement.js
@@ -0,0 +1,66 @@
+function TImageElement(data,parentContainer,globalData,comp, placeholder){
+    this.threeMatrix = new THREE.Matrix4();
+    this.assetData = globalData.getAssetData(data.refId);
+    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
+}
+createElement(TBaseElement, TImageElement);
+
+TImageElement.prototype.createElements = function(){
+
+    var assetPath = this.globalData.getAssetsPath(this.assetData);
+    var img = new Image();
+    ////
+    var squareShape = new THREE.Shape();
+     squareShape.moveTo( 0,0 );
+     squareShape.lineTo( 0, 50 );
+     squareShape.lineTo( 20, 80 );
+     squareShape.lineTo( 50, 50 );
+     squareShape.lineTo( 0, 0 );
+     var geometry = new THREE.Geometry();
+    var shapePoints = squareShape.extractPoints();
+    var faces = THREE.ShapeUtils.triangulateShape(shapePoints.shape, shapePoints.holes);
+    for (var i = 0; i < shapePoints.shape.length; i++) {
+        geometry.vertices.push(new THREE.Vector3(shapePoints.shape[i].x, 0, shapePoints.shape[i].y));
+    }
+    for (var i = 0; i < faces.length ; i++) {
+        var a = faces[i][2] , b = faces[i][1] , c = faces[i][0] ;
+        var v1 = shapePoints.shape[a], v2 = shapePoints.shape[b], v3 = shapePoints.shape[c];
+
+        geometry.faces.push( new THREE.Face3(a, b, c) );    
+        geometry.faceVertexUvs[0].push(
+            [ new THREE.Vector2(v1.x ,v1.y ), new THREE.Vector2(v2.x, v2.y), new THREE.Vector2(v3.x, v3.y)]);
+    }
+    //geometry.computeCentroids();
+    //geometry.computeFaceNormals();
+    ////
+
+    //var geometry = new THREE.PlaneGeometry( this.assetData.w, this.assetData.h, 32 );
+    //this.threeMatrix.makeTranslation(this.assetData.w/2, -this.assetData.h/2,0);
+    //geometry.applyMatrix(this.threeMatrix);
+    //geometry.center();
+    var texture = THREE.ImageUtils.loadTexture(assetPath);
+    
+
+    b|SA":L|>nbzxbb======ju5//-var material = new THREE.MeshBasicMaterial({map: texture}); /n
+    var material = new THREE.MeshBasicMaterial( {color: '#ff0000', side: THREE.DoubleSide} );
+    var plane = new THREE.Mesh( geometry, material );
+    plane.matrixAutoUpdate = false;
+    this.layerElement = plane;
+    this.transformedElement = plane;
+    this.baseElement = plane;
+    this.innerElem = plane;
+    if(this.data.hasMask){
+        this.maskedElement = plane;
+    }
+
+    img.onload = function(){
+        console.log('loaded')
+    }
+    img.src = assetPath;
+    this.checkParenting();
+};
+
+TImageElement.prototype.renderTransformFrame = TSolidElement.prototype.renderTransformFrame;
+TImageElement.prototype.hide = TSolidElement.prototype.hide;
+TImageElement.prototype.renderFrame = TSolidElement.prototype.renderFrame;
+TImageElement.prototype.destroy = TSolidElement.prototype.destroy;
\ No newline at end of file
diff --git a/player/js/elements/threejsElements/TMaskElement.js b/player/js/elements/threejsElements/TMaskElement.js
new file mode 100644
index 0000000..0c3856b
--- /dev/null
+++ b/player/js/elements/threejsElements/TMaskElement.js
@@ -0,0 +1,81 @@
+
+function TMaskElement(data,element){
+    this.data = data;
+    this.element = element;
+    this.dynamicProperties = [];
+    this.masksProperties = this.data.masksProperties;
+    this.viewData = new Array(this.masksProperties.length);
+    var i, len = this.masksProperties.length;
+    for (i = 0; i < len; i++) {
+        this.viewData[i] = ShapePropertyFactory.getShapeProp(this.element,this.masksProperties[i],3,this.dynamicProperties,null);
+    }
+}
+
+TMaskElement.prototype.getMaskProperty = function(pos){
+    return this.viewData[pos];
+};
+
+TMaskElement.prototype.prepareFrame = function(num){
+    var i, len = this.dynamicProperties.length;
+    for(i=0;i<len;i+=1){
+        this.dynamicProperties[i].getValue(num);
+        if(this.dynamicProperties[i].mdf){
+            this.element.globalData.mdf = true;
+        }
+    }
+};
+
+TMaskElement.prototype.renderFrame = function (transform) {
+    /*var ctx = this.element.canvasContext;
+    var i, len = this.data.masksProperties.length;
+    var pt,pt2,pt3,data, hasMasks = false;
+    for (i = 0; i < len; i++) {
+        if(this.masksProperties[i].mode === 'n'){
+            continue;
+        }
+        if(hasMasks === false){
+            ctx.beginPath();
+            hasMasks = true;
+        }
+        if (this.masksProperties[i].inv) {
+            ctx.moveTo(0, 0);
+            ctx.lineTo(this.element.globalData.compWidth, 0);
+            ctx.lineTo(this.element.globalData.compWidth, this.element.globalData.compHeight);
+            ctx.lineTo(0, this.element.globalData.compHeight);
+            ctx.lineTo(0, 0);
+        }
+        data = this.viewData[i].v;
+        pt = transform ? transform.applyToPointArray(data.v[0][0],data.v[0][1],0):data.v[0];
+        ctx.moveTo(pt[0], pt[1]);
+        var j, jLen = data._length;
+        for (j = 1; j < jLen; j++) {
+            pt = transform ? transform.applyToPointArray(data.o[j - 1][0],data.o[j - 1][1],0) : data.o[j - 1];
+            pt2 = transform ? transform.applyToPointArray(data.i[j][0],data.i[j][1],0) : data.i[j];
+            pt3 = transform ? transform.applyToPointArray(data.v[j][0],data.v[j][1],0) : data.v[j];
+            ctx.bezierCurveTo(pt[0], pt[1], pt2[0], pt2[1], pt3[0], pt3[1]);
+        }
+        pt = transform ? transform.applyToPointArray(data.o[j - 1][0],data.o[j - 1][1],0) : data.o[j - 1];
+        pt2 = transform ? transform.applyToPointArray(data.i[0][0],data.i[0][1],0) : data.i[0];
+        pt3 = transform ? transform.applyToPointArray(data.v[0][0],data.v[0][1],0) : data.v[0];
+        ctx.bezierCurveTo(pt[0], pt[1], pt2[0], pt2[1], pt3[0], pt3[1]);
+    }
+    if(hasMasks){
+        ctx.clip();
+    }*/
+};
+
+TMaskElement.prototype.getMask = function(nm){
+    var i = 0, len = this.masksProperties.length;
+    while(i<len){
+        if(this.masksProperties[i].nm === nm){
+            return {
+                maskPath: this.viewData[i].pv
+            }
+        }
+        i += 1;
+    }
+};
+
+TMaskElement.prototype.destroy = function(){
+    this.element = null;
+};
\ No newline at end of file
diff --git a/player/js/elements/threejsElements/TSolidElement.js b/player/js/elements/threejsElements/TSolidElement.js
new file mode 100644
index 0000000..8f68b9e
--- /dev/null
+++ b/player/js/elements/threejsElements/TSolidElement.js
@@ -0,0 +1,55 @@
+function TSolidElement(data,parentContainer,globalData,comp, placeholder){
+    this.threeMatrix = new THREE.Matrix4();
+    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
+}
+createElement(TBaseElement, TSolidElement);
+
+TSolidElement.prototype.createElements = function(){
+
+    var geometry = new THREE.PlaneGeometry( this.data.sw, this.data.sh, 32 );
+    this.threeMatrix.makeTranslation(this.data.sw/2, -this.data.sh/2,0);
+    geometry.applyMatrix(this.threeMatrix);
+    //geometry.center();
+    var material = new THREE.MeshBasicMaterial( {color: this.data.sc, side: THREE.DoubleSide} );
+    var plane = new THREE.Mesh( geometry, material );
+    plane.matrixAutoUpdate = false;
+    
+    this.layerElement = plane;
+    this.transformedElement = plane;
+    //this.appendNodeToParent(parent);
+    this.baseElement = plane;
+    this.innerElem = plane;
+    if(this.data.bm !== 0){
+        this.setBlendMode();
+    }
+    if(this.data.hasMask){
+        this.maskedElement = plane;
+    }
+    this.checkParenting();
+};
+
+TSolidElement.prototype.renderTransformFrame = TBaseElement.prototype.renderFrame;
+
+TSolidElement.prototype.renderFrame = function() {
+    this.renderTransformFrame();
+    //console.log(this.finalMat);
+    //console.log(this.layerElement.geometry);
+    var props = this.finalMat.props;
+    //console.log(props);
+    /*this.threeMatrix.set(props[0],props[1],props[2],props[3],
+        props[4],props[5],props[6],props[7],
+        props[8],props[9],props[10],props[11],
+        0.1,0,0,props[15])*/
+    //this.threeMatrix.identity();
+    this.layerElement.matrix.set(props[0],props[4],props[8],props[12],
+                        props[1],props[5],props[9],props[13],
+                        props[2],props[6],props[10],props[14],
+                        props[3],props[7],props[11],props[15]);
+
+    this.layerElement.updateMatrixWorld( true );
+}
+
+
+
+TSolidElement.prototype.hide = IImageElement.prototype.hide;
+TSolidElement.prototype.destroy = IImageElement.prototype.destroy;
\ No newline at end of file
diff --git a/player/js/renderers/ThreejsRenderer.js b/player/js/renderers/ThreejsRenderer.js
new file mode 100644
index 0000000..1c60595
--- /dev/null
+++ b/player/js/renderers/ThreejsRenderer.js
@@ -0,0 +1,119 @@
+function ThreejsRenderer(animationItem, config){
+    this.animationItem = animationItem;
+    this.layers = null;
+    this.renderedFrame = -1;
+    this.globalData = {
+        frameNum: -1
+    };
+    this.pendingElements = [];
+    this.elements = [];
+    this.threeDElements = [];
+    this.destroyed = false;
+    this.camera = null;
+    this.supports3d = true;
+}
+
+extendPrototype(BaseRenderer,ThreejsRenderer);
+ThreejsRenderer.prototype.buildItem = SVGRenderer.prototype.buildItem;
+
+ThreejsRenderer.prototype.checkPendingElements  = function(){
+    while(this.pendingElements.length){
+        var element = this.pendingElements.pop();
+        element.checkParenting();
+    }
+};
+
+ThreejsRenderer.prototype.appendElementInPos = function(element, pos){
+    var newElement = element.getBaseElement();
+    if(!newElement){
+        return;
+    }
+    var layer = this.layers[pos];
+    if(!layer.ddd || !this.supports3d){
+        var i = 0;
+        var nextElement;
+        while(i<pos){
+            if(this.elements[i] && this.elements[i]!== true && this.elements[i].getBaseElement){
+                nextElement = this.elements[i].getBaseElement();
+            }
+            i += 1;
+        }
+        if(nextElement){
+            if(!layer.ddd || !this.supports3d){
+                this.layerElement.insertBefore(newElement, nextElement);
+            }
+        } else {
+            if(!layer.ddd || !this.supports3d){
+                this.layerElement.appendChild(newElement);
+            }
+        }
+    } else {
+        this.scene.add( newElement );
+    }
+};
+
+ThreejsRenderer.prototype.createSolid = function (data) {
+    return new TSolidElement(data, this.layerElement,this.globalData,this);
+};
+
+ThreejsRenderer.prototype.createImage = function (data) {
+    return new TImageElement(data, this.layerElement,this.globalData,this);
+};
+
+ThreejsRenderer.prototype.createCamera = function (data) {
+    this.camera = new TCameraElement(data, this.layerElement,this.globalData,this);
+    return this.camera;
+};
+
+ThreejsRenderer.prototype.configAnimation = function(animData){
+    var wrapper = this.animationItem.wrapper;
+    var scene = new THREE.Scene();
+    var renderer = new THREE.WebGLRenderer();
+    renderer.setSize( animData.w, animData.h );
+    wrapper.appendChild( renderer.domElement );
+
+    var svg = document.createElementNS(svgNS,'svg');
+    svg.setAttribute('width','1');
+    svg.setAttribute('height','1');
+    styleDiv(svg);
+    wrapper.appendChild(svg);
+    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);
+    this.globalData.elementLoaded = this.animationItem.elementLoaded.bind(this.animationItem);
+    this.globalData.frameId = 0;
+    this.globalData.compSize = {
+        w: animData.w,
+        h: animData.h
+    };
+    this.globalData.frameRate = animData.fr;
+    this.layers = animData.layers;
+    this.globalData.fontManager = new FontManager();
+    this.globalData.fontManager.addChars(animData.chars);
+    this.globalData.fontManager.addFonts(animData.fonts,svg);
+    this.scene = scene;
+    this.renderer = renderer;
+};
+
+ThreejsRenderer.prototype._renderLayersFrame = SVGRenderer.prototype.renderFrame;
+ThreejsRenderer.prototype.renderFrame = function(num) {
+    this._renderLayersFrame(num);
+    //this.scene.updateMatrixWorld( true );
+    this.renderer.render(this.scene, this.camera.threeCamera);
+}
+
+ThreejsRenderer.prototype.searchExtraCompositions = function(assets){
+    var i, len = assets.length;
+    var floatingContainer = document.createElement('div');
+    for(i=0;i<len;i+=1){
+        if(assets[i].xt){
+            var comp = this.createComp(assets[i],floatingContainer,this.globalData.comp,null);
+            comp.initExpressions();
+            this.globalData.projectInterface.registerComposition(comp);
+        }
+    }
+};
\ No newline at end of file
diff --git a/player/js/utils/FontManager.js b/player/js/utils/FontManager.js
index 21fa53e..53503eb 100644
--- a/player/js/utils/FontManager.js
+++ b/player/js/utils/FontManager.js
@@ -96,7 +96,6 @@
         var tCanvasHelper = document.createElement('canvas').getContext('2d');
         tCanvasHelper.font = '100px '+ fontData.fFamily;
         return tCanvasHelper;
-        return tHelper;
     }
 
     function addFonts(fontData, defs){
diff --git a/player/js/utils/PropertyFactory.js b/player/js/utils/PropertyFactory.js
index 40ba8fa..d6a1f0e 100644
--- a/player/js/utils/PropertyFactory.js
+++ b/player/js/utils/PropertyFactory.js
@@ -263,238 +263,7 @@
         this.lastFrame = initFrame;
     }
 
-    var TransformProperty = (function() {
-        function positionGetter() {
-            return ExpressionValue(this.p);
-        }
-        function xPositionGetter() {
-            return ExpressionValue(this.px);
-        }
-        function yPositionGetter() {
-            return ExpressionValue(this.py);
-        }
-        function zPositionGetter() {
-            return ExpressionValue(this.pz);
-        }
-        function anchorGetter() {
-            return ExpressionValue(this.a);
-        }
-        function orientationGetter() {
-            return ExpressionValue(this.or);
-        }
-        function rotationGetter() {
-            return ExpressionValue(this.r, 1/degToRads);
-        }
-        function scaleGetter() {
-            return ExpressionValue(this.s, 100);
-        }
-        function opacityGetter() {
-            return ExpressionValue(this.o, 100);
-        }
-        function skewGetter() {
-            return ExpressionValue(this.sk);
-        }
-        function skewAxisGetter() {
-            return ExpressionValue(this.sa);
-        }
-        function applyToMatrix(mat) {
-            var i, len = this.dynamicProperties.length;
-            for(i = 0; i < len; i += 1) {
-                this.dynamicProperties[i].getValue();
-                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.s) {
-                mat.scale(this.s.v[0], this.s.v[1], this.s.v[2]);
-            }
-            if (this.r) {
-                mat.rotate(-this.r.v);
-            } 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) {
-                    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]);
-            }
-        }
-        function processKeys(){
-            if (this.elem.globalData.frameId === this.frameId) {
-                return;
-            }
-
-            this.mdf = false;
-            var i, len = this.dynamicProperties.length;
-
-            for(i = 0; i < len; i += 1) {
-                this.dynamicProperties[i].getValue();
-                if (this.dynamicProperties[i].mdf) {
-                    this.mdf = true;
-                }
-            }
-            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.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.r) {
-                    this.v.rotate(-this.r.v);
-                } 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) {
-                    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) / 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.elem.globalData.frameRate, this.p.offsetTime);
-                    }
-                    this.v.rotate(-Math.atan2(v1[1] - v2[1], v1[0] - v2[0]));
-                }
-                if(this.data.p.s){
-                    if(this.data.p.z) {
-                        this.v.translate(this.px.v, this.py.v, -this.pz.v);
-                    } else {
-                        this.v.translate(this.px.v, this.py.v, 0);
-                    }
-                }else{
-                    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;
-        }
-
-        function setInverted(){
-            this.inverted = true;
-            this.iv = new Matrix();
-            if(!this.k){
-                if(this.data.p.s){
-                    this.iv.translate(this.px.v,this.py.v,-this.pz.v);
-                }else{
-                    this.iv.translate(this.p.v[0],this.p.v[1],-this.p.v[2]);
-                }
-                if(this.r){
-                    this.iv.rotate(-this.r.v);
-                }else{
-                    this.iv.rotateX(-this.rx.v).rotateY(-this.ry.v).rotateZ(this.rz.v);
-                }
-                if(this.s){
-                    this.iv.scale(this.s.v[0],this.s.v[1],1);
-                }
-                if(this.a){
-                    this.iv.translate(-this.a.v[0],-this.a.v[1],this.a.v[2]);
-                }
-            }
-        }
-
-        function autoOrient(){
-            //
-            //var prevP = this.getValueAtTime();
-        }
-
-        return function TransformProperty(elem,data,arr){
-            this.elem = elem;
-            this.frameId = -1;
-            this.type = 'transform';
-            this.dynamicProperties = [];
-            this.mdf = false;
-            this.data = data;
-            this.getValue = processKeys;
-            this.applyToMatrix = applyToMatrix;
-            this.setInverted = setInverted;
-            this.autoOrient = autoOrient;
-            this.v = new Matrix();
-            if(data.p.s){
-                this.px = PropertyFactory.getProp(elem,data.p.x,0,0,this.dynamicProperties);
-                this.py = PropertyFactory.getProp(elem,data.p.y,0,0,this.dynamicProperties);
-                if(data.p.z){
-                    this.pz = PropertyFactory.getProp(elem,data.p.z,0,0,this.dynamicProperties);
-                }
-            }else{
-                this.p = PropertyFactory.getProp(elem,data.p,1,0,this.dynamicProperties);
-            }
-            if(data.r) {
-                this.r = PropertyFactory.getProp(elem, data.r, 0, degToRads, this.dynamicProperties);
-            } else if(data.rx) {
-                this.rx = PropertyFactory.getProp(elem, data.rx, 0, degToRads, this.dynamicProperties);
-                this.ry = PropertyFactory.getProp(elem, data.ry, 0, degToRads, this.dynamicProperties);
-                this.rz = PropertyFactory.getProp(elem, data.rz, 0, degToRads, this.dynamicProperties);
-                this.or = PropertyFactory.getProp(elem, data.or, 1, degToRads, this.dynamicProperties);
-            }
-            if(data.sk){
-                this.sk = PropertyFactory.getProp(elem, data.sk, 0, degToRads, this.dynamicProperties);
-                this.sa = PropertyFactory.getProp(elem, data.sa, 0, degToRads, this.dynamicProperties);
-            }
-            if(data.a) {
-                this.a = PropertyFactory.getProp(elem,data.a,1,0,this.dynamicProperties);
-            }
-            if(data.s) {
-                this.s = PropertyFactory.getProp(elem,data.s,1,0.01,this.dynamicProperties);
-            }
-            if(data.o){
-                this.o = PropertyFactory.getProp(elem,data.o,0,0.01,arr);
-            } else {
-                this.o = {mdf:false,v:1};
-            }
-            if(this.dynamicProperties.length){
-                arr.push(this);
-            }else{
-                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.sk){
-                    this.v.skewFromAxis(-this.sk.v,this.sa.v);
-                }
-                if(this.r){
-                    this.v.rotate(-this.r.v);
-                }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.data.p.s){
-                    if(data.p.z) {
-                        this.v.translate(this.px.v, this.py.v, -this.pz.v);
-                    } else {
-                        this.v.translate(this.px.v, this.py.v, 0);
-                    }
-                }else{
-                    this.v.translate(this.p.v[0],this.p.v[1],-this.p.v[2]);
-                }
-            }
-            Object.defineProperty(this, "position", { get: positionGetter});
-            Object.defineProperty(this, "xPosition", { get: xPositionGetter});
-            Object.defineProperty(this, "yPosition", { get: yPositionGetter});
-            Object.defineProperty(this, "orientation", { get: orientationGetter});
-            Object.defineProperty(this, "anchorPoint", { get: anchorGetter});
-            Object.defineProperty(this, "rotation", { get: rotationGetter});
-            Object.defineProperty(this, "scale", { get: scaleGetter});
-            Object.defineProperty(this, "opacity", { get: opacityGetter});
-            Object.defineProperty(this, "skew", { get: skewGetter});
-            Object.defineProperty(this, "skewAxis", { get: skewAxisGetter});
-        }
-    }());
+    
 
     function getProp(elem,data,type, mult, arr) {
         var p;
diff --git a/player/js/utils/TransformProperty.js b/player/js/utils/TransformProperty.js
new file mode 100644
index 0000000..deaac36
--- /dev/null
+++ b/player/js/utils/TransformProperty.js
@@ -0,0 +1,233 @@
+var TransformProperty = (function() {
+    function positionGetter() {
+        return ExpressionValue(this.p);
+    }
+    function xPositionGetter() {
+        return ExpressionValue(this.px);
+    }
+    function yPositionGetter() {
+        return ExpressionValue(this.py);
+    }
+    function zPositionGetter() {
+        return ExpressionValue(this.pz);
+    }
+    function anchorGetter() {
+        return ExpressionValue(this.a);
+    }
+    function orientationGetter() {
+        return ExpressionValue(this.or);
+    }
+    function rotationGetter() {
+        return ExpressionValue(this.r, 1/degToRads);
+    }
+    function scaleGetter() {
+        return ExpressionValue(this.s, 100);
+    }
+    function opacityGetter() {
+        return ExpressionValue(this.o, 100);
+    }
+    function skewGetter() {
+        return ExpressionValue(this.sk);
+    }
+    function skewAxisGetter() {
+        return ExpressionValue(this.sa);
+    }
+    function applyToMatrix(mat) {
+        var i, len = this.dynamicProperties.length;
+        for(i = 0; i < len; i += 1) {
+            this.dynamicProperties[i].getValue();
+            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.s) {
+            mat.scale(this.s.v[0], this.s.v[1], this.s.v[2]);
+        }
+        if (this.r) {
+            mat.rotate(-this.r.v);
+        } 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) {
+                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]);
+        }
+    }
+    function processKeys(){
+        if (this.elem.globalData.frameId === this.frameId) {
+            return;
+        }
+
+        this.mdf = false;
+        var i, len = this.dynamicProperties.length;
+
+        for(i = 0; i < len; i += 1) {
+            this.dynamicProperties[i].getValue();
+            if (this.dynamicProperties[i].mdf) {
+                this.mdf = true;
+            }
+        }
+        if (this.mdf) {
+            this.v.reset();
+            if (this.a) {
+                if(this.inverted){
+                    this.v.translate(-this.a.v[0], this.a.v[1], this.a.v[2]);
+                } else {
+                    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.sk) {
+                this.v.skewFromAxis(-this.sk.v, this.sa.v);
+            }
+            if (this.r) {
+                this.v.rotate(-this.r.v);
+            } else {
+                if(this.inverted){
+                    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]);
+                } 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) {
+                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) / 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.elem.globalData.frameRate, this.p.offsetTime);
+                }
+                this.v.rotate(-Math.atan2(v1[1] - v2[1], v1[0] - v2[0]));
+            }
+            if(this.data.p.s){
+                if(this.data.p.z) {
+                    this.v.translate(this.px.v, this.py.v, -this.pz.v);
+                } else {
+                    this.v.translate(this.px.v, this.py.v, 0);
+                }
+            }else{
+                if(this.inverted){
+                    this.v.translate(this.p.v[0],-this.p.v[1],-this.p.v[2]);
+                } else {
+                    this.v.translate(this.p.v[0],this.p.v[1],-this.p.v[2]);
+                }
+                
+            }
+        }
+        this.frameId = this.elem.globalData.frameId;
+    }
+
+    function autoOrient(){
+        //
+        //var prevP = this.getValueAtTime();
+    }
+
+    return function TransformProperty(elem,data,arr,inverted){
+        this.elem = elem;
+        this.inverted = inverted || false;
+        this.frameId = -1;
+        this.type = 'transform';
+        this.dynamicProperties = [];
+        this.mdf = false;
+        this.data = data;
+        this.getValue = processKeys;
+        this.applyToMatrix = applyToMatrix;
+        this.autoOrient = autoOrient;
+        this.v = new Matrix();
+        if(data.p.s){
+            this.px = PropertyFactory.getProp(elem,data.p.x,0,0,this.dynamicProperties);
+            this.py = PropertyFactory.getProp(elem,data.p.y,0,0,this.dynamicProperties);
+            if(data.p.z){
+                this.pz = PropertyFactory.getProp(elem,data.p.z,0,0,this.dynamicProperties);
+            }
+        }else{
+            this.p = PropertyFactory.getProp(elem,data.p,1,0,this.dynamicProperties);
+        }
+        if(data.r) {
+            this.r = PropertyFactory.getProp(elem, data.r, 0, degToRads, this.dynamicProperties);
+        } else if(data.rx) {
+            this.rx = PropertyFactory.getProp(elem, data.rx, 0, degToRads, this.dynamicProperties);
+            this.ry = PropertyFactory.getProp(elem, data.ry, 0, degToRads, this.dynamicProperties);
+            this.rz = PropertyFactory.getProp(elem, data.rz, 0, degToRads, this.dynamicProperties);
+            this.or = PropertyFactory.getProp(elem, data.or, 1, degToRads, this.dynamicProperties);
+        }
+        if(data.sk){
+            this.sk = PropertyFactory.getProp(elem, data.sk, 0, degToRads, this.dynamicProperties);
+            this.sa = PropertyFactory.getProp(elem, data.sa, 0, degToRads, this.dynamicProperties);
+        }
+        if(data.a) {
+            this.a = PropertyFactory.getProp(elem,data.a,1,0,this.dynamicProperties);
+        }
+        if(data.s) {
+            this.s = PropertyFactory.getProp(elem,data.s,1,0.01,this.dynamicProperties);
+        }
+        if(data.o){
+            this.o = PropertyFactory.getProp(elem,data.o,0,0.01,arr);
+        } else {
+            this.o = {mdf:false,v:1};
+        }
+        if(this.dynamicProperties.length){
+            arr.push(this);
+        }else{
+            if(this.a){
+                if(this.inverted){
+                    this.v.translate(-this.a.v[0], this.a.v[1], this.a.v[2]);
+                } else {
+                    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.sk){
+                this.v.skewFromAxis(-this.sk.v,this.sa.v);
+            }
+            if(this.r){
+                this.v.rotate(-this.r.v);
+            }else{
+                if(this.inverted){
+                    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]);
+                } 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.data.p.s){
+                if(data.p.z) {
+                    this.v.translate(this.px.v, this.py.v, -this.pz.v);
+                } else {
+                    this.v.translate(this.px.v, this.py.v, 0);
+                }
+            }else{
+                if(this.inverted){
+                    this.v.translate(this.p.v[0],-this.p.v[1],-this.p.v[2]);
+                } else {
+                    this.v.translate(this.p.v[0],this.p.v[1],-this.p.v[2]);
+                }
+            }
+        }
+        Object.defineProperty(this, "position", { get: positionGetter});
+        Object.defineProperty(this, "xPosition", { get: xPositionGetter});
+        Object.defineProperty(this, "yPosition", { get: yPositionGetter});
+        Object.defineProperty(this, "orientation", { get: orientationGetter});
+        Object.defineProperty(this, "anchorPoint", { get: anchorGetter});
+        Object.defineProperty(this, "rotation", { get: rotationGetter});
+        Object.defineProperty(this, "scale", { get: scaleGetter});
+        Object.defineProperty(this, "opacity", { get: opacityGetter});
+        Object.defineProperty(this, "skew", { get: skewGetter});
+        Object.defineProperty(this, "skewAxis", { get: skewAxisGetter});
+    }
+}());
\ No newline at end of file
diff --git a/player/js/utils/common.js b/player/js/utils/common.js
index 05a3632..a5452f0 100644
--- a/player/js/utils/common.js
+++ b/player/js/utils/common.js
@@ -1,4 +1,4 @@
-var subframeEnabled = true;
+var subframeEnabled = false;
 var expressionsPlugin;
 var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
 var cachedColors = {};
diff --git a/player/js/utils/shapes/RepeaterModifier.js b/player/js/utils/shapes/RepeaterModifier.js
index 87cb7cc..37582f9 100644
--- a/player/js/utils/shapes/RepeaterModifier.js
+++ b/player/js/utils/shapes/RepeaterModifier.js
@@ -19,7 +19,7 @@
     this.getValue = this.processKeys;
     this.c = PropertyFactory.getProp(elem,data.c,0,null,this.dynamicProperties);
     this.o = PropertyFactory.getProp(elem,data.o,0,null,this.dynamicProperties);
-    this.tr = PropertyFactory.getProp(elem,data.tr,2,null,this.dynamicProperties);
+    this.tr = new TransformProperty(elem,data.tr, this.dynamicProperties);
     if(!this.dynamicProperties.length){
         this.getValue(true);
     }