image sprite partial
diff --git a/extension/CSXS/manifest.xml b/extension/CSXS/manifest.xml
index f5eee37..56a8f2a 100644
--- a/extension/CSXS/manifest.xml
+++ b/extension/CSXS/manifest.xml
@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<ExtensionManifest Version="5.0" ExtensionBundleId="com.bodymovin.bodymovin" ExtensionBundleVersion="4.0.4"
+<ExtensionManifest Version="6.0" ExtensionBundleId="com.bodymovin.bodymovin" ExtensionBundleVersion="4.0.4"
 		ExtensionBundleName="bodymovin" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 	<ExtensionList>
 		<Extension Id="com.bodymovin.bodymovin" Version="4.0.4" />
 	</ExtensionList>
 	<ExecutionEnvironment>
 		<HostList>
-            <Host Name="AEFT" Version="[13.0,13.9]" />
-            <Host Name="AEFX" Version="[13.0,13.9]" />
+            <Host Name="AEFT" Version="13.0" />
+            <Host Name="AEFX" Version="13.0" />
 
             <!-- Illustrator -->
             <!-- <Host Name="ILST" Version="[18.0,18.9]" />-->
@@ -27,7 +27,7 @@
 			<Locale Code="All" />
 		</LocaleList>
 		<RequiredRuntimeList>
-			<RequiredRuntime Name="CSXS" Version="5.0" />
+			<RequiredRuntime Name="CSXS" Version="6.0" />
 		</RequiredRuntimeList>
 	</ExecutionEnvironment>
 	<DispatchInfoList>
@@ -36,6 +36,11 @@
 				<Resources>
 				<MainPath>./index.html</MainPath>
 				<ScriptPath>./jsx/hostscript.jsx</ScriptPath>
+                <CEFCommandLine>
+                    <Parameter>--enable-nodejs</Parameter>
+                    <Parameter>--mixed-context</Parameter>
+                    <Parameter>--enable-media-stream</Parameter>
+                </CEFCommandLine>
 				</Resources>
 				<Lifecycle>
 					<AutoVisible>true</AutoVisible>
diff --git a/extension/index.html b/extension/index.html
index c30d05f..00c4af9 100644
--- a/extension/index.html
+++ b/extension/index.html
@@ -186,6 +186,7 @@
     <script src="js/controllers/messageController.js"></script>
     <script src="js/controllers/InfoController.js"></script>
     <script src="js/utils/storage.js"></script>
+    <script src="js/utils/binpacking.js"></script>
     <script src="js/controllers/snapshotController.js"></script>
     <script src="js/main.js"></script>
     
diff --git a/extension/js/controllers/CompRenderController.js b/extension/js/controllers/CompRenderController.js
index e7e2cd1..b30e191 100644
--- a/extension/js/controllers/CompRenderController.js
+++ b/extension/js/controllers/CompRenderController.js
@@ -198,6 +198,17 @@
         });
     }
     
+    function renderAtlasHandler(ev) {
+        var messageData = ev.data;
+        bm_binpacker.reset();
+        bm_binpacker.addBlocks(messageData.images);
+        var atlasPack = bm_binpacker.getPack();
+        var atlasDataString = JSON.stringify(atlasPack);
+        var eScript = 'bm_renderManager.setAtlasData(' + atlasDataString + ')';
+        csInterface.evalScript(eScript);
+        
+    }
+    
     function renderCharsHandler(ev) {
         var messageData = ev.data;
         var chars;
@@ -272,6 +283,7 @@
         csInterface.addEventListener('bm:render:complete', renderCompleteHandler);
         csInterface.addEventListener('bm:render:fonts', renderFontsHandler);
         csInterface.addEventListener('bm:render:chars', renderCharsHandler);
+        csInterface.addEventListener('bm:render:atlas', renderAtlasHandler);
         
         cancelButton = view.find('.cancel');
         returnButton = view.find('.return');
diff --git a/extension/js/main.js b/extension/js/main.js
index c653953..8e4f766 100644
--- a/extension/js/main.js
+++ b/extension/js/main.js
@@ -8,10 +8,6 @@
     var csInterface = new CSInterface();
     var mainViews = [];
     
-    
-    var gulp = require('gulp');
-    var gzip = require('gulp-gzip');
-    
     function showView(view) {
         var i, len = mainViews.length;
         for (i = 0; i < len; i += 1) {
diff --git a/extension/js/utils/binpacking.js b/extension/js/utils/binpacking.js
new file mode 100644
index 0000000..3abfcf3
--- /dev/null
+++ b/extension/js/utils/binpacking.js
@@ -0,0 +1,43 @@
+/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
+/*global console, require*/
+
+var bm_binpacker = (function () {
+    'use strict';
+    var ob = {}, blocks = [], packer, binpacking, GrowingPacker;
+    if (typeof require === 'function') {
+        ob.enabled = true;
+        binpacking = require('binpacking');
+        GrowingPacker = binpacking.GrowingPacker;
+    }
+    
+    function addBlocks(blocks) {
+        console.log(blocks);
+        var i, len = blocks.length;
+        for(i = 0; i < len; i += 1) {
+            addBlock(blocks[i]);
+        }
+    }
+    
+    function addBlock(block) {
+        blocks.push(block);
+    }
+    
+    function getPack() {
+        var packer = new GrowingPacker();
+        blocks.sort(function(a, b) { return (b.h > a.h); });
+        packer.fit(blocks);
+        console.log(blocks);
+        return blocks;
+    }
+    
+    function reset() {
+        blocks.length = 0;
+    }
+    
+    ob.addBlock = addBlock;
+    ob.addBlocks = addBlocks;
+    ob.reset = reset;
+    ob.getPack = getPack;
+    
+    return ob;
+}());
\ No newline at end of file
diff --git a/extension/jsx/renderManager.jsx b/extension/jsx/renderManager.jsx
index e033ba2..aebd618 100644
--- a/extension/jsx/renderManager.jsx
+++ b/extension/jsx/renderManager.jsx
@@ -107,6 +107,7 @@
     function reset() {
         pendingLayers.length = 0;
         pendingComps.length = 0;
+        ob.renderData.exportData.assets.length = 0;
         currentCompSettings = null;
     }
     
@@ -215,7 +216,10 @@
         saveData();
     }
     
-    function imagesReady() {
+    function imagesReady(assetsArray) {
+        if(assetsArray) {
+            ob.renderData.exportData.assets = assetsArray;
+        }
         checkFonts();
     }
     
@@ -238,6 +242,7 @@
     ob.setChars = setChars;
     ob.imagesReady = imagesReady;
     ob.setFontData = setFontData;
+    ob.setAtlasData = bm_sourceHelper.setAtlasData;
     ob.setCharsData = setCharsData;
     ob.hasExpressions = hasExpressions;
     
diff --git a/extension/jsx/utils/sourceHelper.jsx b/extension/jsx/utils/sourceHelper.jsx
index 3d98203..08193cc 100644
--- a/extension/jsx/utils/sourceHelper.jsx
+++ b/extension/jsx/utils/sourceHelper.jsx
@@ -3,6 +3,7 @@
 var bm_sourceHelper = (function () {
     'use strict';
     var compSources = [], imageSources = [], fonts = [], currentExportingImage, destinationPath, assetsArray, folder, helperComp, currentCompID, imageCount = 0;
+    var ob = {};
 
     function checkCompSource(item) {
         var arr = compSources;
@@ -79,6 +80,72 @@
         saveNextImage();
     }
     
+    function createAtlas() {
+        var i, len = imageSources.length;
+        var imagesList = [];
+        for (i = 0; i < len; i += 1) {
+            imagesList.push({
+                w: imageSources[i].width + 4,
+                h: imageSources[i].height + 4,
+                id: imageSources[i].id
+            });
+        }
+        bm_eventDispatcher.sendEvent('bm:render:atlas', {images: imagesList});
+    }
+    
+    function getSourceDataById(id) {
+        var i = 0, len = imageSources.length;
+        while( i < len) {
+            if(imageSources[i].id === id) {
+                return imageSources[i];
+            }
+            i += 1;
+        }
+    }
+    
+    function setAtlasData(blocks) {
+        if (bm_compsManager.cancelled) {
+            return;
+        }
+        var compWidth = 0;
+        var compHeight = 0;
+        var i, len = blocks.length;
+        for (i = 0; i < len; i += 1) {
+            compWidth = Math.max(blocks[i].fit.w + blocks[i].fit.x, compWidth);
+            compHeight = Math.max(blocks[i].fit.h + blocks[i].fit.y, compHeight);
+        }
+        var helperComp = app.project.items.addComp('atlasConverterComp', Math.max(4, compWidth), Math.max(4, compHeight), 1, 1, 1);
+        var source, sourceData, layer;
+        for (i = 0; i < len; i += 1) {
+            sourceData = getSourceDataById(blocks[i].id);
+            source = sourceData.source;
+            layer = helperComp.layers.add(source);
+            layer.transform['Anchor Point'].setValue([0, 0]);
+            layer.transform['Position'].setValue([blocks[i].fit.x + 2, blocks[i].fit.y + 2]);
+            assetsArray.push({
+                id: blocks[i].id,
+                w: blocks[i].w,
+                h: blocks[i].h,
+                x: blocks[i].fit.x + 2,
+                y: blocks[i].fit.y + 2,
+                p: 'images/atlas_' + '0' + '.png'
+            });
+        }
+        bm_eventDispatcher.log('assetsArray len: ' + assetsArray.length);
+        bm_renderManager.imagesReady(assetsArray);
+        var file = new File(folder.absoluteURI + '/atlas_' + '0' + '.png');
+        helperComp.saveFrameToPng(0, file);
+        helperComp.remove();
+    }
+    
+    function saveImages() {
+        if (ob.atlas) {
+            createAtlas();
+        } else {
+            saveNextImage();
+        }
+    }
+    
     function exportImages(path, assets, compId) {
         if (imageSources.length === 0) {
             bm_renderManager.imagesReady();
@@ -93,12 +160,12 @@
         assetsArray = assets;
         if (!folder.exists) {
             if (folder.create()) {
-                saveNextImage();
+                saveImages();
             } else {
                 bm_eventDispatcher.sendEvent('alert', 'folder failed to be created at: ' + folder.fsName);
             }
         } else {
-            saveNextImage();
+            saveImages();
         }
     }
     
@@ -127,16 +194,21 @@
         imageSources.length = 0;
         fonts.length = 0;
         imageCount = 0;
+        assetsArray = null;
     }
     
-    return {
+    ob = {
         checkCompSource: checkCompSource,
         checkImageSource: checkImageSource,
         setCompSourceId: setCompSourceId,
+        setAtlasData: setAtlasData,
         exportImages : exportImages,
         addFont : addFont,
         getFonts : getFonts,
+        atlas: true,
         reset: reset
     };
     
+    return ob;
+    
 }());
\ No newline at end of file
diff --git a/player/index.html b/player/index.html
index 137879b..26f0c17 100644
--- a/player/index.html
+++ b/player/index.html
@@ -40,6 +40,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/ImageManager.js"></script>
     <script src="js/utils/expressions/ExpressionManager.js"></script>
     <script src="js/utils/expressions/ExpressionComp.js"></script>
     <script src="js/utils/expressions/ShapeInterface.js"></script>
diff --git a/player/js/elements/ImageElement.js b/player/js/elements/ImageElement.js
index 8ffadea..3fd27a3 100644
--- a/player/js/elements/ImageElement.js
+++ b/player/js/elements/ImageElement.js
@@ -10,15 +10,26 @@
     var self = this;
 
     var imageLoaded = function(){
-        self.innerElem.setAttributeNS('http://www.w3.org/1999/xlink','href',self.path+self.assetData.p);
+        var cv = document.createElement('canvas');
+        cv.width = self.assetData.w;
+        cv.height = self.assetData.h;
+        var ctx = cv.getContext('2d');
+        ctx.drawImage(img,self.assetData.x,self.assetData.y,self.assetData.w,self.assetData.h,0,0,self.assetData.w,self.assetData.h);
+        var dataUri = cv.toDataURL();
+        self.innerElem.setAttributeNS('http://www.w3.org/1999/xlink','href',dataUri);
+        //self.innerElem.setAttributeNS('http://www.w3.org/1999/xlink','href',self.path+self.assetData.p);
         self.maskedElement = self.innerElem;
+        ImageManager.unregisterImage(imgLoader);
     };
 
-    var img = new Image();
-    img.addEventListener('load', imageLoaded, false);
-    img.addEventListener('error', imageLoaded, false);
-
-    img.src = this.path+this.assetData.p;
+    var imgLoader = ImageManager.getImage(this.path+this.assetData.p);
+    var img = imgLoader.elem;
+    if(imgLoader.loaded) {
+        imageLoaded();
+    } else {
+        img.addEventListener('load', imageLoaded, false);
+        img.addEventListener('error', imageLoaded, false);
+    }
 
     this.parent.createElements.call(this);
 
diff --git a/player/js/utils/ImageManager.js b/player/js/utils/ImageManager.js
new file mode 100644
index 0000000..12cd903
--- /dev/null
+++ b/player/js/utils/ImageManager.js
@@ -0,0 +1,48 @@
+var ImageManager = (function(){
+
+    var images = [];
+    var ob = {};
+
+    function getImage(path){
+        var i = 0, len = images.length;
+        while(i<len) {
+            if(images[i].path === path){
+                images[i].count += 1;
+                return images[i];
+            }
+            i += 1;
+        }
+
+        function imageLoaded(){
+            imageOb.loaded = true;
+        }
+
+        var img = document.createElement('img');
+        img.addEventListener('load', imageLoaded, false);
+        img.addEventListener('error', imageLoaded, false);
+
+        var imageOb = {
+            elem: img,
+            path: path,
+            loaded: false,
+            count: 1
+        };
+        img.src = path;
+        images.push(imageOb);
+        return imageOb;
+    }
+
+    function unregisterImage(ob){
+        ob.count -= 1;
+        if(ob.count === 0) {
+            var ind = images.indexOf(ob);
+            images.splice(ind, 1);
+            ob.elem = null;
+        }
+    }
+
+    ob.getImage = getImage;
+    ob.unregisterImage = unregisterImage;
+
+    return ob;
+}());
\ No newline at end of file