diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/README.md b/README.md
index 28df2da..10064f8 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,10 @@
-# SLAcer.js ([demo](http://lautr3k.github.io/SLAcer.js/))
+# SLAcer.js for SparkMaker ([demo](https://n0sr3v.github.io/SLAcer.js/))
 ![Screenshot](/screenshot.png?raw=true)
 
-# Main features
+# Work in Progress
+- currently working on an option to slice .wow files
+
+# Default main features
 - Browse or drag/drop STL file.
 - Mesh information: size, volume, cost, etc...
 - Mesh transformation: scale, rotate, translate, mirror.
diff --git a/css/main.css b/css/main.css
index ee1457a..9e65683 100644
--- a/css/main.css
+++ b/css/main.css
@@ -54,7 +54,8 @@
 }
 
 #sidebar .info-value,
-#sidebar .form-control {
+#sidebar .form-control,
+#sidebar .btn-reset {
     width: 40%;
     float: left;
 }
diff --git a/favicon.ico b/favicon.ico
new file mode 100644
index 0000000..6ca7273
Binary files /dev/null and b/favicon.ico differ
diff --git a/index.html b/index.html
index 76c8219..393c98f 100644
--- a/index.html
+++ b/index.html
@@ -4,12 +4,15 @@
         <meta charset="utf-8" />
         <meta http-equiv="X-UA-Compatible" content="IE=edge" />
         <meta name="viewport" content="width=device-width, initial-scale=1" />
-        <title>SLAcer.js (bêta)</title>
+        <title>SLAcer.js for SparkMaker (bêta)</title>
+        <link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
         <link rel="stylesheet" type="text/css" href="vendor/jquery-ui/jquery-ui.min.css" />
         <link rel="stylesheet" type="text/css" href="vendor/bootstrap/css/bootstrap.min.css" />
         <link rel="stylesheet" type="text/css" href="vendor/bootstrap-slider/css/bootstrap-slider.min.css" />
         <link rel="stylesheet" type="text/css" href="vendor/bootstrap-colorpicker/css/bootstrap-colorpicker.min.css" />
         <link rel="stylesheet" type="text/css" href="css/main.css" />
+        <link rel="manifest" href="./manifest.json">
+
     </head>
     <body>
         <nav class="navbar navbar-inverse navbar-fixed-top">
@@ -21,12 +24,14 @@
                         <span class="icon-bar"></span>
                         <span class="icon-bar"></span>
                     </button>
-                    <a class="navbar-brand" href="#">SLAcer.js (bêta)</a>
+                    <a class="navbar-brand" href="#">SLAcer.js for SparkMaker (beta)</a>
                 </div>
                 <div id="navbar" class="navbar-collapse collapse">
                     <ul class="nav navbar-nav navbar-right">
                         <li><a href="#">About</a></li>
-                        <li><a href="https://github.com/lautr3k/SLAcer.js">GitHub</a></li>
+                        <li><a href="https://www.thingiverse.com/groups/sparkmaker/forums/gadgets/topic:28168">Thingiverse</a></li>
+                        <li><a href="https://github.com/n0sr3v/SLAcer.js">GitHub (Fork)</a></li>
+                        <li><a href="https://github.com/lautr3k/SLAcer.js">GitHub (↪thank you to lautr3k)</a></li>
                     </ul>
                 </div>
             </div>
@@ -103,7 +108,15 @@ <h3 class="panel-title">File</h3>
                             <span class="btn btn-default btn-file btn-xs">
                                 Browse <input type="file" name="file" id="file-input" accept=".stl" />
                             </span>
-                            <small>Or drop an STL file anywhere.</small>
+                            <small>Or drop an STL file anywhere.<br>In case of error check your model <a href="https://service.netfabb.com/service.php">here</a>!</small>
+                        </div>
+                        <div class="form-group">
+                            <label for="printer-type" style="width: 25%;">Printer</label>
+                            <select id="printer-type" class="form-control input-sm" style="width: 75%;">
+                                <option>Sparkmaker</option>
+                                <option>Sparkmaker FHD</option>
+                                <option>Custom</option>
+                            </select>
                         </div>
                     </div>
                 </div><!-- #file -->
@@ -162,6 +175,10 @@ <h3 class="panel-title">Slicer</h3>
                                 <span id="slicer-layer-value">0</span> / <span id="slicer-layers-value">0</span>
                             </span>
                         </div>
+                        <div class="info">
+                            <span class="info-label">Print Time <small>(h:m:s.ms)</small></span>
+                            <span class="info-value" id="print-time">0</span>
+                        </div>
 
                         <hr />
 
@@ -171,24 +188,43 @@ <h3 class="panel-title">Slicer</h3>
                         </div>
                         <div class="form-group">
                             <label for="slicer-light-on">Exposure time <small>(ms)</small></label>
-                            <input type="number" id="slicer-light-on" class="form-control input-sm" placeholder="1000" min="1" />
+                            <input type="number" id="slicer-light-on" class="form-control input-sm" placeholder="10000" min="1" />
+                        </div>
+                        <!-- new -->
+                        <div class="form-group">
+                            <label for="slicer-light-strength">Exposure Strength Grade <small>(bit)</small></label>
+                            <input type="number" id="slicer-light-strength" class="form-control input-sm" placeholder="225" min="1" max="255" />
+                        </div>
+                        <!-- new -->
+                        <div class="form-group">
+                            <label for="slicer-light-bottom">Bottom Layers Exposure Time <small>(ms)</small></label>
+                            <input type="number" id="slicer-light-bottom" class="form-control input-sm" placeholder="60000" min="1" />
                         </div>
 
                         <div class="form-group clearfix">
                             <label for="slicer-lifting-height">Lifting height <small>(mm)</small></label>
-                            <input type="number" id="slicer-lifting-height" class="form-control input-sm" placeholder="3" min="1" />
+                            <input type="number" id="slicer-lifting-height" class="form-control input-sm" placeholder="5" min="1" />
                         </div>
                         <div class="form-group clearfix">
                             <label for="slicer-lifting-speed">Lifting speed <small>(mm/min)</small></label>
-                            <input type="number" id="slicer-lifting-speed" class="form-control input-sm" placeholder="50" min="1" />
+                            <input type="number" id="slicer-lifting-speed" class="form-control input-sm" placeholder="30" min="1" />
+                        </div>
+                        <!-- new -->
+                        <div class="form-group clearfix">
+                            <label for="slicer-decline-speed">Decline speed <small>(mm/min)</small></label>
+                            <input type="number" id="slicer-decline-speed" class="form-control input-sm" placeholder="100" min="1" />
                         </div>
 
                         <hr />
 
                         <div class="form-group">
-                            <label for="slicer-image-extension">Output type</label>
-                            <input type="radio" name="slicer-image-extension" id="slicer-image-extension-png" value="png" checked="checked" /> png
-                            <input type="radio" name="slicer-image-extension" id="slicer-image-extension-svg" value="svg" /> svg
+                            <label for="output-type">Output type</label>
+                            <select id="output-type" class="form-control input-sm">
+                                <option>png</option>
+                                <option>svg</option>
+                                <option>wow</option>
+                                <option>fhd</option>
+                            </select>
                         </div>
 
                         <hr />
@@ -200,17 +236,22 @@ <h3 class="panel-title">Slicer</h3>
 
                         <div class="form-group">
                             <label for="slicer-make-zip">Make ZIP file</label>
-                            <input type="radio" name="slicer-make-zip" id="slicer-make-zip-yes" value="yes" /> yes
-                            <input type="radio" name="slicer-make-zip" id="slicer-make-zip-no" value="no" checked="checked" /> no
+                            <input type="radio" name="slicer-make-zip" id="slicer-make-zip-yes" value="yes" checked="checked" /> yes
+                            <input type="radio" name="slicer-make-zip" id="slicer-make-zip-no" value="no"  /> no
                         </div>
                         <div class="form-group">
-                            <label for="slicer-speed">Speed mode</label>
-                            <input type="radio" name="slicer-speed" id="slicer-speed-yes" value="yes" /> yes
-                            <input type="radio" name="slicer-speed" id="slicer-speed-no" value="no" checked="checked" /> no
+                            <label for="slicer-make-folder">Make layer-folder</label>
+                            <input type="radio" name="slicer-make-folder" id="slicer-make-folder-yes" value="yes" /> yes
+                            <input type="radio" name="slicer-make-folder" id="slicer-make-folder-no" value="no"  checked="checked" /> no
                         </div>
                         <div class="form-group">
-                            <label for="slicer-speed-delay">Speed mode<br />delay <small>(ms)</small></label>
-                            <input type="number" id="slicer-speed-delay" class="form-control input-sm" placeholder="100" min="1" />
+                            <label for="slicer-speed">Slicing mode</label>
+                            <input type="radio" name="slicer-speed" id="slicer-speed-yes" value="yes" checked="checked" /> yes
+                            <input type="radio" name="slicer-speed" id="slicer-speed-no" value="no"  /> no
+                        </div>
+                        <div class="form-group">
+                            <label for="slicer-speed-delay">Slicing delay<br />delay <small>(ms)</small></label>
+                            <input type="number" id="slicer-speed-delay" class="form-control input-sm" placeholder="10" min="1" />
                         </div>
                     </div>
                 </div><!-- #slicer -->
@@ -225,15 +266,15 @@ <h3 class="panel-title">Build volume</h3>
                     <div id="build-volume-body" class="panel-body collapse in">
                         <div class="form-group">
                             <label for="build-volume-x">X <small>(width)</small></label>
-                            <input type="number" id="build-volume-x" class="form-control input-sm" placeholder="100" min="0" />
+                            <input type="number" id="build-volume-x" class="form-control input-sm" placeholder="102" min="0" />
                         </div>
                         <div class="form-group">
                             <label for="build-volume-y">Y <small>(depth)</small></label>
-                            <input type="number" id="build-volume-y" class="form-control input-sm" placeholder="100" min="0" />
+                            <input type="number" id="build-volume-y" class="form-control input-sm" placeholder="56" min="0" />
                         </div>
                         <div class="form-group">
                             <label for="build-volume-z">Z <small>(height)</small></label>
-                            <input type="number" id="build-volume-z" class="form-control input-sm" placeholder="100" min="0" />
+                            <input type="number" id="build-volume-z" class="form-control input-sm" placeholder="125" min="0" />
                         </div>
                         <div class="form-group">
                             <label for="build-volume-unit">unit</label>
@@ -257,7 +298,7 @@ <h3 class="panel-title">Resin</h3>
                         </div>
                         <div class="form-group">
                             <label for="resin-price">Price <small>($ / l)</small></label>
-                            <input type="number" id="resin-price" class="form-control input-sm" placeholder="50" min="0" />
+                            <input type="number" id="resin-price" class="form-control input-sm" placeholder="60" min="0" />
                         </div>
                     </div>
                 </div><!-- #resin -->
@@ -276,15 +317,15 @@ <h3 class="panel-title">Screen</h3>
                         </div>
                         <div class="form-group">
                             <label for="screen-width">Width <small>(px)</small></label>
-                            <input type="number" id="screen-width" class="form-control input-sm" placeholder="1680" min="0" />
+                            <input type="number" id="screen-width" class="form-control input-sm" placeholder="854" min="0" />
                         </div>
                         <div class="form-group">
                             <label for="screen-height">Height <small>(px)</small></label>
-                            <input type="number" id="screen-height" class="form-control input-sm" placeholder="1050" min="0" />
+                            <input type="number" id="screen-height" class="form-control input-sm" placeholder="480" min="0" />
                         </div>
                         <div class="form-group">
                             <label for="screen-diagonal-size">Diagonal size</label>
-                            <input type="number" id="screen-diagonal-size" class="form-control input-sm" placeholder="22" min="0" />
+                            <input type="number" id="screen-diagonal-size" class="form-control input-sm" placeholder="4.6" min="0" />
                         </div>
                         <div class="form-group">
                             <label for="screen-diagonal-unit">Diagonal unit</label>
@@ -313,6 +354,27 @@ <h3 class="panel-title">Colors</h3>
                     </div>
                 </div><!-- #colors -->
 
+                <div id="gcode" class="panel panel-default">
+                    <div class="panel-heading">
+                        <button class="panel-toggle btn btn-default btn-xs pull-right" type="button" data-toggle="collapse" data-target="#gcode-body">
+                            <span class="glyphicon glyphicon-menu-down"></span>
+                        </button>
+                        <h3 class="panel-title">GCode</h3>
+                    </div>
+                    <div id="gcode-body" class="panel-body collapse">
+                        <div class="form-group">
+                            <label for="resetStart" >Start</label>
+                            <span class="btn btn-default btn-xs btn-reset" id="resetStart" title="Reset to default Start GCode" >Reset</span>
+                            <textarea id="start" class="form-control" rows="5" style="width: 100%; float: none;" ></textarea>
+                        </div>
+                        <div class="form-group">
+                            <label for="resetEnd" >End</label>
+                            <span class="btn btn-default btn-xs btn-reset" id="resetEnd" title="Reset to default End GCode" >Reset</span>
+                            <textarea id="end" class="form-control" rows="5" style="width: 100%; float: none;" ></textarea>
+                        </div>
+                    </div>
+                </div><!-- #gcode -->
+
             </div><!-- #sidebar -->
 
             <div id="main">
@@ -338,7 +400,22 @@ <h3 class="panel-title">Colors</h3>
             <!-- <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button> -->
             <p class="message">Alert message empty...</p>
         </div>
-
+      
+        <!-- from dev -->
+        <div id="dialog-confirm"></div>
+      
+        <script type="text/javascript">
+            if (navigator.serviceWorker) {
+                navigator.serviceWorker.register('sw.js', {scope: '/'}).then(function(reg) {
+                    // registration worked
+                    console.log('Registration succeeded. Scope is ' + reg.scope);
+                }).catch(function(error) {
+                    // registration failed
+                    console.log('Registration failed with ' + error);
+                });
+            }
+        </script>
+        <!-- from gh-pages
         <script src="vendor/jquery-2.1.4.min.js" type="text/javascript"></script>
         <script src="vendor/jquery-ui/jquery-ui.min.js" type="text/javascript"></script>
         <script src="vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
@@ -359,6 +436,7 @@ <h3 class="panel-title">Colors</h3>
         <script src="js/loader/stl.js" type="text/javascript"></script>
         <script src="vendor/FileSaver.min.js" type="text/javascript"></script>
         <script src="vendor/jszip.min.js" type="text/javascript"></script>
-        <script src="js/main.js" type="text/javascript"></script>
+        <script src="js/main.js" type="text/javascript" charset="utf-8"></script>
+         -->
     </body>
 </html>
diff --git a/js/main.js b/js/main.js
index 416f74f..76e356d 100644
--- a/js/main.js
+++ b/js/main.js
@@ -7,28 +7,33 @@ var settings = new SLAcer.Settings({
         panel: {
             collapsed: false,
             position : 0
-        }
+        },
+        printer: 'Custom'
     },
     slicer: {
         layers: {
-            height: 100 // μm
+            height: 100, // μm
+            bottom: 3
         },
         light: {
-            on : 1000,
-            off: 500
+            on : 12000,
+            bottom: 60000,
+            off: 500,
+            strength: 225
         },
         zip: true,
-        svg: false,
-        png: true,
-        speed: false,
+        folder: false,
+        output: 'wow',
+        speed: true,
         speedDelay: 10, // ms
         panel: {
             collapsed: false,
             position : 1
         },
         lifting: {
-            speed : 50, // mm/min
-            height: 3,  // mm
+            speed : 30, // mm/min
+            decline: 100, // mm/min
+            height: 5,  // mm
         }
     },
     mesh: {
@@ -45,7 +50,7 @@ var settings = new SLAcer.Settings({
         mirror: false
     },
     buildVolume: {
-        size     : { x: 100,  y: 100,  z: 100 }, // mm
+        size     : { x: 102,  y: 56,  z: 125 }, // mm
         unit     : 'mm',                         // mm or in
         color    : 0xcccccc,
         opacity  : 0.1,
@@ -56,16 +61,16 @@ var settings = new SLAcer.Settings({
     },
     resin: {
         density  : 1.1, // g/cm3
-        price    : 50,   // $
+        price    : 60,   // $
         panel    : {
             collapsed: false,
             position : 5
         }
     },
     screen: {
-        width    : window.screen.width,
-        height   : window.screen.height,
-        diagonal : { size: 22, unit: 'in' },
+        width    : 854,//window.screen.width,
+        height   : 480,//window.screen.height,
+        diagonal : { size: 4.6, unit: 'in' },
         panel    : {
             collapsed: false,
             position : 6
@@ -79,6 +84,14 @@ var settings = new SLAcer.Settings({
             position : 7
         }
     },
+    gcode: {
+        start : getDefaultGcodeStart(),
+        end: getDefaultGcodeEnd(),
+        panel: {
+            collapsed: true,
+            position : 8
+        }
+    },
     viewer3d: {
         color: 0xffffff
     }
@@ -128,15 +141,20 @@ function getSlice(layerNumber) {
     removeSlices();
     removeShapes();
 
+    // debug
+    // console.log("layerNumber", layerNumber)
+
     // ...
     $slicerLayerValue.html(layerNumber);
 
+
     if (layerNumber < 1) {
         viewer2d.render();
         viewer3d.render();
         return;
     }
 
+
     if (transformations.update) {
         throw 'transformations not applyed...';
     }
@@ -186,7 +204,88 @@ function getSlice(layerNumber) {
         if (PNGExport) {
             var fileName = layerNumber + '.png';
             var imgData  = dataURL.substr(dataURL.indexOf(',') + 1);
-            zipFolder.file(fileName, imgData, { base64: true });
+            if (settings.get('slicer.folder')) {
+                zipFolder.file(fileName, imgData, {base64: true});
+            }
+        } else if (FHDExport) {
+            // image file
+            var fileName = 'slice (' + layerNumber + ').png';
+            var imgData  = dataURL.substr(dataURL.indexOf(',') + 1);
+            zipFolder.file(fileName, imgData, {base64: true});
+
+            // gcode
+            wowFile += "M106 S0;\n"; // UV lights off
+            wowFile += "G1 Z" + settings.get('slicer.lifting.height') + " F" + settings.get('slicer.lifting.speed') + ";\n"; // raise bed up specified height and speed
+            wowFile += "G1 Z-" + (settings.get('slicer.lifting.height') - settings.get('slicer.layers.height') / 1000) + " F" + settings.get('slicer.lifting.decline') + ";\n"; // lower bed down specified height and speed
+
+            //bottom layer
+            var exposure_time;
+            if(layerNumber<=settings.get('slicer.layers.bottom')){
+                exposure_time = settings.get('slicer.light.bottom');
+            }else{
+                exposure_time = settings.get('slicer.light.on');
+            }
+
+            wowFile += "{" + fileName + "};\n"; // link to layer image
+            wowFile += "M106 S"+settings.get('slicer.light.strength')+";\n"; // UV lights on specified strength
+            wowFile += "G4 S" + exposure_time / 1000 + ";\n"; // wait specified layer cure time
+        }else if (WOWExport) {
+            //console.log('layer number:', layerNumber);
+            //console.log('z position :', zPosition);
+
+            convertURIToImageData(dataURL).then(function(imageData) {
+                // Here you can use imageData
+                /*
+                 var red = data[i];
+                 var green = data[i+1];
+                 var blue = data[i+2];
+                 var alpha = data[i+3];
+                 2 Options:
+                 Black red=0, green=0, blue=0, alpha=255;
+                 White red=255, green=255, blue=255, alpha=255;
+                 */
+                var width = settings.get('screen.width');
+                var height = settings.get('screen.height');
+                var pixel = 0;
+                var array = new Uint8Array(width*height/8);
+                var data = imageData.data;
+
+                for(var w=0; w<data.length/height*4; w+=4) {
+                    for(var h=w; h<width*height*4; h+=(4*width)) {
+                        if(data[h]!==0){
+                            array[~~(pixel/8)] += Math.pow(2,(pixel%8))
+                        }
+                        pixel++;
+                    }
+                }
+
+                if(WOWExport) {// GCode logic
+                    wowFile += ";L:" + layerNumber + ";\nM106 S0;\nG1 Z" + settings.get('slicer.lifting.height') +
+                        " F" + settings.get('slicer.lifting.speed') +
+                        ";\nG1 Z-" + (settings.get('slicer.lifting.height') - settings.get('slicer.layers.height') / 1000) +
+                        " F" + settings.get('slicer.lifting.decline') + ";\n{{\n"
+
+                    //var binary_layer = (new TextDecoder("utf-8")).decode(array)
+                    wowFile += bin2string(array);
+                    //wowFile += array.map(intBytetoHexBin);
+                    wowFile += "\n";
+
+                    if (settings.get('slicer.folder')) {
+                        // Backup text file
+                        zipFolder.file(layerNumber + ".txt", array);
+                    }
+
+                    //bottom layer
+                    var exposure_time;
+                    if(layerNumber<=settings.get('slicer.layers.bottom')){
+                        exposure_time = settings.get('slicer.light.bottom');
+                    }else{
+                        exposure_time = settings.get('slicer.light.on');
+                    }
+                    wowFile += "}}\nM106 S"+settings.get('slicer.light.strength')+";\nG4 S" + exposure_time / 1000 + ";\n"
+                }
+            });
+
         }
     });
 
@@ -267,9 +366,79 @@ function getSlice(layerNumber) {
         svg += '</g>';
         svg += '</svg>';
 
-        // add svg file to zip
-        zipFolder.file(layerNumber + '.svg', svg);
+        if (settings.get('slicer.folder')) {
+            // add svg file to zip
+            zipFolder.file(layerNumber + '.svg', svg);
+        }
+    }
+
+}
+
+function convertURIToImageData(URI) {
+    return new Promise(function(resolve, reject) {
+        if (URI == null) return reject();
+        var canvas = document.createElement('canvas'),
+            context = canvas.getContext('2d'),
+            image = new Image();
+        image.addEventListener('load', function() {
+            canvas.width = image.width;
+            canvas.height = image.height;
+            context.drawImage(image, 0, 0, canvas.width, canvas.height);
+            resolve(context.getImageData(0, 0, canvas.width, canvas.height));
+        }, false);
+        image.src = URI;
+    });
+}
+
+function bin2string(array){
+    var result = "";
+    for(var i = 0; i < array.length; ++i){
+        result+= (String.fromCharCode(array[i]));
+        //result+= intBytetoHexBin(array[i]);
     }
+    return result;
+}
+// array.map(intBytetoHexBin);
+function intBytetoHexBin(value){
+    //var hex_array = ["\x00","\x01","\x02","\x03","\x04","\x05","\x06","\x07","\x08","\x09","\x0A","\x0B","\x0C","\x0D","\x0E","\x0F","\x10","\x11","\x12","\x13","\x14","\x15","\x16","\x17","\x18","\x19","\x1A","\x1B","\x1C","\x1D","\x1E","\x1F","\x20","\x21","\x22","\x23","\x24","\x25","\x26","\x27","\x28","\x29","\x2A","\x2B","\x2C","\x2D","\x2E","\x2F","\x30","\x31","\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39","\x3A","\x3B","\x3C","\x3D","\x3E","\x3F","\x40","\x41","\x42","\x43","\x44","\x45","\x46","\x47","\x48","\x49","\x4A","\x4B","\x4C","\x4D","\x4E","\x4F","\x50","\x51","\x52","\x53","\x54","\x55","\x56","\x57","\x58","\x59","\x5A","\x5B","\x5C","\x5D","\x5E","\x5F","\x60","\x61","\x62","\x63","\x64","\x65","\x66","\x67","\x68","\x69","\x6A","\x6B","\x6C","\x6D","\x6E","\x6F","\x70","\x71","\x72","\x73","\x74","\x75","\x76","\x77","\x78","\x79","\x7A","\x7B","\x7C","\x7D","\x7E","\x7F","\x80","\x81","\x82","\x83","\x84","\x85","\x86","\x87","\x88","\x89","\x8A","\x8B","\x8C","\x8D","\x8E","\x8F","\x90","\x91","\x92","\x93","\x94","\x95","\x96","\x97","\x98","\x99","\x9A","\x9B","\x9C","\x9D","\x9E","\x9F","\xA0","\xA1","\xA2","\xA3","\xA4","\xA5","\xA6","\xA7","\xA8","\xA9","\xAA","\xAB","\xAC","\xAD","\xAE","\xAF","\xB0","\xB1","\xB2","\xB3","\xB4","\xB5","\xB6","\xB7","\xB8","\xB9","\xBA","\xBB","\xBC","\xBD","\xBE","\xBF","\xC0","\xC1","\xC2","\xC3","\xC4","\xC5","\xC6","\xC7","\xC8","\xC9","\xCA","\xCB","\xCC","\xCD","\xCE","\xCF","\xD0","\xD1","\xD2","\xD3","\xD4","\xD5","\xD6","\xD7","\xD8","\xD9","\xDA","\xDB","\xDC","\xDD","\xDE","\xDF","\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE6","\xE7","\xE8","\xE9","\xEA","\xEB","\xEC","\xED","\xEE","\xEF","\xF0","\xF1","\xF2","\xF3","\xF4","\xF5","\xF6","\xF7","\xF8","\xF9","\xFA","\xFB","\xFC","\xFD","\xFE","\xFF"];
+    //return hex_array[value];
+    return ["\x00","\x01","\x02","\x03","\x04","\x05","\x06","\x07","\x08","\x09","\x0A","\x0B","\x0C","\x0D","\x0E","\x0F","\x10","\x11","\x12","\x13","\x14","\x15","\x16","\x17","\x18","\x19","\x1A","\x1B","\x1C","\x1D","\x1E","\x1F","\x20","\x21","\x22","\x23","\x24","\x25","\x26","\x27","\x28","\x29","\x2A","\x2B","\x2C","\x2D","\x2E","\x2F","\x30","\x31","\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39","\x3A","\x3B","\x3C","\x3D","\x3E","\x3F","\x40","\x41","\x42","\x43","\x44","\x45","\x46","\x47","\x48","\x49","\x4A","\x4B","\x4C","\x4D","\x4E","\x4F","\x50","\x51","\x52","\x53","\x54","\x55","\x56","\x57","\x58","\x59","\x5A","\x5B","\x5C","\x5D","\x5E","\x5F","\x60","\x61","\x62","\x63","\x64","\x65","\x66","\x67","\x68","\x69","\x6A","\x6B","\x6C","\x6D","\x6E","\x6F","\x70","\x71","\x72","\x73","\x74","\x75","\x76","\x77","\x78","\x79","\x7A","\x7B","\x7C","\x7D","\x7E","\x7F","\x80","\x81","\x82","\x83","\x84","\x85","\x86","\x87","\x88","\x89","\x8A","\x8B","\x8C","\x8D","\x8E","\x8F","\x90","\x91","\x92","\x93","\x94","\x95","\x96","\x97","\x98","\x99","\x9A","\x9B","\x9C","\x9D","\x9E","\x9F","\xA0","\xA1","\xA2","\xA3","\xA4","\xA5","\xA6","\xA7","\xA8","\xA9","\xAA","\xAB","\xAC","\xAD","\xAE","\xAF","\xB0","\xB1","\xB2","\xB3","\xB4","\xB5","\xB6","\xB7","\xB8","\xB9","\xBA","\xBB","\xBC","\xBD","\xBE","\xBF","\xC0","\xC1","\xC2","\xC3","\xC4","\xC5","\xC6","\xC7","\xC8","\xC9","\xCA","\xCB","\xCC","\xCD","\xCE","\xCF","\xD0","\xD1","\xD2","\xD3","\xD4","\xD5","\xD6","\xD7","\xD8","\xD9","\xDA","\xDB","\xDC","\xDD","\xDE","\xDF","\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE6","\xE7","\xE8","\xE9","\xEA","\xEB","\xEC","\xED","\xEE","\xEF","\xF0","\xF1","\xF2","\xF3","\xF4","\xF5","\xF6","\xF7","\xF8","\xF9","\xFA","\xFB","\xFC","\xFD","\xFE","\xFF"][value];
+}
+
+function BinToText(input) {
+    return parseInt(input,2).toString(10);
+}
+
+function uintToString(buffer) {
+    var encodedString = String.fromCharCode.apply(null, buffer),
+        decodedString = decodeURIComponent(escape(encodedString));
+    return decodedString;
+}
+
+function convertHexToString(input) {
+
+    // split input into groups of two
+    var hex = input.match(/[\s\S]{2}/g) || [];
+    var output = '';
+
+    // build a hex-encoded representation of your string
+    for (var i = 0, j = hex.length; i < j; i++) {
+        output += '%' + ('0' + hex[i]).slice(-2);
+    }
+
+    // decode it using this trick
+    output = decodeURIComponent(output);
+
+    return output;
+}
+
+function arrayToHEXString(input) {
+
+    var result = "";
+    for(var i = 0; i < input.length; ++i){
+        result+= "\X"+input[i].toString(16);
+    }
+    return result;
 }
 
 // -----------------------------------------------------------------------------
@@ -344,9 +513,47 @@ function updateSliderUI() {
     var layersHeight = settings.get('slicer.layers.height') / 1000;
     var layersNumber = Math.floor(slicer.mesh.getSize().z / layersHeight);
 
+    // console.log("layersHeight", layersHeight);
+    // console.log("layersNumber", layersNumber);
+
     $sliderInput.slider('setAttribute', 'max', layersNumber);
     $sliderMaxValue.html(layersNumber);
     $slicerLayersValue.html(layersNumber);
+
+    $printTimeValue.html(msToTime(calcPrintTime(layersHeight, layersNumber)));
+}
+function calcPrintTime(layersHeight, layersNumber){
+    // ([object height]/[layer height])([exposure time]+[uplift time]+[downlift time])+3([ground exposure time]-[exposure time])
+    var result = 0;
+    var uplift_time = settings.get('slicer.lifting.height')/settings.get('slicer.lifting.speed')*60*1000
+    var downlift_time = (settings.get('slicer.lifting.height')-layersHeight)/settings.get('slicer.lifting.decline')*60*1000
+    result = layersNumber*(parseInt(settings.get('slicer.light.on'))+uplift_time+downlift_time)+
+        settings.get('slicer.layers.bottom')*(settings.get('slicer.light.bottom')-settings.get('slicer.light.on'))
+    /*
+    console.log("slicer.light.on (ms)", settings.get('slicer.light.on'));
+    console.log("slicer.layers.bottom)", settings.get('slicer.layers.bottom'));
+    console.log("slicer.light.bottom)", settings.get('slicer.light.bottom'));
+    console.log("downlift_time (ms)", downlift_time);
+    console.log("uplift_time (ms)", uplift_time);
+    console.log("tmp 0 (ms)", parseInt(settings.get('slicer.light.on')) + uplift_time );
+    console.log("tmp 1 (ms)", layersNumber*(parseInt(settings.get('slicer.light.on'))+uplift_time+downlift_time));
+    console.log("tmp 2 (ms)", settings.get('slicer.layers.bottom')*(settings.get('slicer.light.bottom')-settings.get('slicer.light.on')));
+    console.log("result (ms)", result);
+    */
+
+    return result;
+}
+function msToTime(duration) {
+    var milliseconds = parseInt((duration%1000)/100)
+        , seconds = parseInt((duration/1000)%60)
+        , minutes = parseInt((duration/(1000*60))%60)
+        , hours = parseInt((duration/(1000*60*60))%24);
+
+    hours = (hours < 10) ? "0" + hours : hours;
+    minutes = (minutes < 10) ? "0" + minutes : minutes;
+    seconds = (seconds < 10) ? "0" + seconds : seconds;
+
+    return hours + ":" + minutes + ":" + seconds + "." + milliseconds;
 }
 
 // Sidebar
@@ -409,6 +616,7 @@ function parseUnit(value, unit) {
 // File panel
 var $fileBody  = initPanel('file');
 var $fileInput = $fileBody.find('#file-input');
+var $printerType = $fileBody.find('#printer-type');
 var loadedFile = null;
 
 $fileInput.on('change', function(e) {
@@ -417,6 +625,117 @@ $fileInput.on('change', function(e) {
     loader.loadFile(loadedFile);
 });
 
+$printerType.on('change', function(e) {
+    newPrinterType = $printerType.val();
+
+    if (newPrinterType == 'Custom') {
+        // update printerType setting only
+        settings.set('file.printer', newPrinterType);
+    }
+    else {
+        // TODO: need to fix slider errors when using jquery-ui full (as opposed to .min). Then we can use this confirm dialog
+//        // make sure user is willing to update screen, build volume, and outputType settings
+//        $("#dialog-confirm").html("Are you sure you want to replace screen, build volume, gcode, and outputType settings with \"" + newPrinterType + "\" defaults?");
+//        $("#dialog-confirm").dialog({
+//            resizable: false,
+//            modal: true,
+//            title: "Update Settings?",
+//            height: 250,
+//            width: 400,
+//            buttons: {
+//                "Yes": function () {
+//                    $(this).dialog('close');
+                    // update settings
+                    settings.set('file.printer', newPrinterType);
+                    printerDefaults(newPrinterType);
+//                },
+//                "No": function () {
+//                    $(this).dialog('close');
+//                    // revert printerType input to the old printer-type value from settings
+//                    $printerType.val(settings.get('file.printer'));
+//                }
+//            }
+//        });
+    }
+});
+
+$printerType.val(settings.get('file.printer'));
+
+function printerDefaults(printerType) {
+    // update settings and UI
+    if (printerType == 'Sparkmaker') {
+        // screen
+        settings.set('screen', {
+            width   : 854,
+            height  : 480,
+            diagonal: {
+                size: 4.6,
+                unit: 'in'
+            }
+        });
+        $('#screen-diagonal-unit-' + settings.get('screen.diagonal.unit')).prop('checked', true);
+        updateScreenUI();
+
+        // build volume x,y,z,unit
+        settings.set('buildVolume', {
+            size: {
+                x: 102,
+                y: 56,
+                z: 125
+            },
+            unit: 'mm'
+        });
+        $('#build-volume-unit-' + settings.get('buildVolume.unit')).prop('checked', true);
+        updateBuildVolumeUI()
+
+        // outputType
+        settings.set('slicer.output', 'wow');
+        $outputType.val(settings.get('slicer.output'));
+
+        // gcode
+        resetGcodeStart(); // gcode prefix and suffix are the same for both Sparkmaker and Sparkmaker FHD for now
+        resetGcodeEnd();
+    }
+    else if (printerType == 'Sparkmaker FHD') {
+        // screen
+        settings.set('screen', {
+            width   : 1920,
+            height  : 1080,
+            diagonal: {
+                size: 4.9686,
+                unit: 'in'
+            }
+        });
+        $('#screen-diagonal-unit-' + settings.get('screen.diagonal.unit')).prop('checked', true);
+        updateScreenUI();
+
+        // build volume
+        settings.set('buildVolume', {
+            size: {
+                x: 110.016,
+                y: 61.8357,
+                z: 125
+            },
+            unit: 'mm'
+        });
+        $('#build-volume-unit-' + settings.get('buildVolume.unit')).prop('checked', true);
+        updateBuildVolumeUI()
+
+        // outputType
+        settings.set('slicer.output', 'fhd');
+        $outputType.val(settings.get('slicer.output'));
+
+        // gcode
+        resetGcodeStart(); // gcode prefix and suffix are the same for both Sparkmaker and Sparkmaker FHD for now
+        resetGcodeEnd();
+    }
+
+    // reload 3d view with new screen and build-volume settings
+    updateBuildVolumeSettings();
+    updateScreenSettings();
+}
+
+
 // Mesh panel
 var $meshBody     = initPanel('mesh');
 var $meshFaces    = $meshBody.find('#mesh-faces');
@@ -452,9 +771,11 @@ function updateMeshInfoUI() {
     var cost   = volume * settings.get('resin.price') / 1000;
 
     $meshFaces.html(mesh.geometry.faces.length);
-    $meshVolume.html(volume);
-    $meshWeight.html(weight);
-    $meshCost.html(cost);
+
+    // mirror bugfix
+    $meshVolume.html(Math.abs(volume));
+    $meshWeight.html(Math.abs(weight));
+    $meshCost.html(Math.abs(weight));
 }
 
 // Slicer panel
@@ -465,17 +786,28 @@ var $slicerLayerValue  = $slicerBody.find('#slicer-layer-value');
 var $slicerLightOff    = $slicerBody.find('#slicer-light-off');
 var $slicerLightOn     = $slicerBody.find('#slicer-light-on');
 
+//new
+var $slicerLightStrength     = $slicerBody.find('#slicer-light-strength');
+var $slicerLightBottum     = $slicerBody.find('#slicer-light-bottom');
+var $slicerDeclineSpeed     = $slicerBody.find('#slicer-decline-speed');
+var $slicerBottomLayers = settings.get('slicer.layers.bottom');
+var $printTimeValue  = $slicerBody.find('#print-time');
+
 var $slicerLiftingSpeed  = $slicerBody.find('#slicer-lifting-speed');
 var $slicerLiftingHeight = $slicerBody.find('#slicer-lifting-height');
 
-var $slicerExportPNG = $slicerBody.find('#slicer-image-extension-png');
-var $slicerExportSVG = $slicerBody.find('#slicer-image-extension-svg');
+var $outputType = $slicerBody.find('#output-type');
 
 var $slicerSpeedYes    = $slicerBody.find('#slicer-speed-yes');
 var $slicerSpeedNo     = $slicerBody.find('#slicer-speed-no');
 var $slicerSpeedDelay  = $slicerBody.find('#slicer-speed-delay');
 var $slicerMakeZipYes  = $slicerBody.find('#slicer-make-zip-yes');
 var $slicerMakeZipNo   = $slicerBody.find('#slicer-make-zip-no');
+
+//new
+var $slicerMakeFolderYes  = $slicerBody.find('#slicer-make-folder-yes');
+var $slicerMakeFolderNo  = $slicerBody.find('#slicer-make-folder-no');
+
 var $sliceButton       = $sidebar.find('#slice-button');
 var $abortButton       = $sidebar.find('#abort-button');
 var $zipButton         = $sidebar.find('#zip-button');
@@ -487,6 +819,11 @@ function updateSlicerUI() {
     $slicerLayerHeight.val(slicer.layers.height);
     $slicerLightOff.val(slicer.light.off);
     $slicerLightOn.val(slicer.light.on);
+    //new
+    $slicerLightStrength.val(slicer.light.strength);
+    $slicerLightBottum.val(slicer.light.bottom);
+    $slicerDeclineSpeed.val(slicer.lifting.decline);
+    //$slicerBottomLayers.val(slicer.layers.bottom);
 
     $slicerLiftingSpeed.val(slicer.lifting.speed);
     $slicerLiftingHeight.val(slicer.lifting.height);
@@ -497,13 +834,22 @@ function updateSlicerSettings() {
     settings.set('slicer.light.off', $slicerLightOff.val());
     settings.set('slicer.light.on', $slicerLightOn.val());
 
+    //new
+    settings.set('slicer.light.strength', $slicerLightStrength.val());
+    settings.set('slicer.light.bottom', $slicerLightBottum.val());
+    settings.set('slicer.lifting.decline', $slicerDeclineSpeed.val());
+    //settings.set('slicer.layers.bottom', $slicerBottomLayers.val());
+
     settings.set('slicer.lifting.speed', $slicerLiftingSpeed.val());
     settings.set('slicer.lifting.height', $slicerLiftingHeight.val());
 
-    settings.set('slicer.png', $slicerExportPNG[0].checked);
-    settings.set('slicer.svg', $slicerExportSVG[0].checked);
+    settings.set('slicer.output', $outputType.val());
 
     settings.set('slicer.zip', $slicerMakeZipYes[0].checked);
+
+    //new
+    settings.set('slicer.folder', $slicerMakeFolderYes[0].checked);
+
     settings.set('slicer.speed', $slicerSpeedYes[0].checked);
     settings.set('slicer.speedDelay', $slicerSpeedDelay.val());
 
@@ -518,7 +864,10 @@ var currentSliceNumber;
 var slicesNumber;
 var zipFile;
 var zipFolder;
+var wowFile;
 
+var WOWExport;
+var FHDExport;
 var SVGExport;
 var PNGExport;
 
@@ -538,7 +887,11 @@ function slice() {
         return endSlicing();
     }
 
+    // debug
+    // console.log("currentSliceNumber", currentSliceNumber)
+
     getSlice(currentSliceNumber);
+
     $sliderInput.slider('setValue', currentSliceNumber);
 
     var time = Date.now();
@@ -553,6 +906,27 @@ function slice() {
 }
 
 function endSlicing() {
+
+    if(WOWExport) {// GCode & export logic
+        // add gcode footer from settings
+        var gcode = settings.get('gcode');
+        wowFile += gcode.end;
+
+        zipFile.file("print.wow", wowFile, {binary: true});
+
+        // hotfix for mirror bug
+        flipGeometry();
+    } else if (FHDExport) {
+        // add gcode footer from settings
+        var gcode = settings.get('gcode'); // I believe same end gcode is valid for FHD as for standard sparkmaker - Adam
+        wowFile += gcode.end;
+
+        zipFolder.file("print.wow", wowFile, {binary: true}); // probably don't need binary, but doesn't seem to hurt
+
+        // hotfix for mirror bug
+        flipGeometry();
+    }
+
     sliceImage('none');
     $sidebar.find('input, button').prop('disabled', false);
     $sliderInput.slider('enable');
@@ -577,16 +951,22 @@ function startSlicing() {
 
     zipFile   = null;
     zipFolder = null;
+    wowFile   = null;
+    WOWExport = null;
+    FHDExport = null;
     SVGExport = null;
     PNGExport = null;
 
     if (settings.get('slicer.zip')) {
         zipFile   = new JSZip();
-        zipFolder = zipFile.folder('slices');
-        zipFile.file("README.txt", 'Generated by SLAcer.js\r\nhttp://lautr3k.github.io/SLAcer.js/\r\n');
+        if (settings.get('slicer.folder')) {
+            zipFolder = zipFile.folder('slices');
+        }
+        zipFile.file("README.txt", 'Generated by SLAcer.js for SparkMaker\r\nhttps://n0sr3v.github.io/SLAcer.js/\r\n\r\nProject based on: \r\nhttps://github.com/lautr3k/SLAcer.js\r\nAppreciate this work!\r\n');
         zipFile.file("slacer.json", JSON.stringify({
-            imageExtension: settings.get('slicer.png') ? 'png' : 'svg',
-            imageDirectory: 'slices',
+            imageExtension: settings.get('slicer.output'),
+            imageDirectoryCreated: settings.get('slicer.folder') ? 'false' : 'true',
+            imageDirectory: !settings.get('slicer.folder') ? '' : 'slices',
             screenWidth   : settings.get('screen.width'),
             screenHeight  : settings.get('screen.height'),
             screenSize    : settings.get('screen.diagonal.size'),
@@ -594,16 +974,79 @@ function startSlicing() {
             layersNumber  : slicesNumber,
             layersHeight  : settings.get('slicer.layers.height') / 1000,     // mm
             exposureTime  : parseInt(settings.get('slicer.light.on')),       // ms
+            exposureStrength  : parseInt(settings.get('slicer.light.strength')),       // ms
+            bottomExposureTime  : parseInt(settings.get('slicer.light.bottom')),       // ms
             liftingSpeed  : parseInt(settings.get('slicer.lifting.speed')),  // mm/min
+            declineSpeed  : parseInt(settings.get('slicer.lifting.decline')),  // mm/min
             liftingHeight : parseInt(settings.get('slicer.lifting.height'))  // mm
         }, null, 2));
-        SVGExport = settings.get('slicer.svg');
-        PNGExport = settings.get('slicer.png');
+        if ($outputType.val() == 'wow') {
+            WOWExport = true;
+        }
+        else if ($outputType.val() == 'fhd') {
+            FHDExport = true;
+        }
+        else if ($outputType.val() == 'svg') {
+            SVGExport = true;
+        }
+        else if ($outputType.val() == 'png') {
+            PNGExport = true;
+        }
+        if (FHDExport) {
+            zipFolder = zipFile.folder('print-FHD');
+        }
+    }
+
+    if(WOWExport){// GCode logic
+
+        // hotfix for first layer bug - before flip geometry!
+        $sliderInput.slider('setValue', currentSliceNumber);
+
+        // hotfix for mirror bug
+        flipGeometry();
+
+        wowFile = "";
+
+        // Tests
+        /*
+        var array = new Uint8Array(2);
+        array[1]=255;
+        console.log(array);
+        var textDecoder = new TextDecoder("utf-8");
+        var binary_layer = textDecoder.decode(array);
+        console.log(binary_layer);
+        */
+        //console.log(textDecoder.encode(binary_layer));
+
+        // use gcode header from settings
+        var gcode = settings.get('gcode');
+        wowFile += gcode.start;
+    } else if (FHDExport) {
+        // hotfix for first layer bug - before flip geometry!
+        $sliderInput.slider('setValue', currentSliceNumber);
+
+        // hotfix for mirror bug
+        flipGeometry();
+
+        wowFile = "";
+
+        // use gcode header from settings
+        var gcode = settings.get('gcode'); // I believe same start gcode is valid for FHD as for standard sparkmaker - Adam
+        wowFile += gcode.start;
     }
 
     slicesNumber && slice();
 }
 
+function waitForZeroLayer(callback){
+    if(currentSliceNumber === 0){
+        callback();
+    }
+    else{
+        setTimeout(waitForZeroLayer(callback), 250);
+    }
+}
+
 $zipButton.on('click', function(e) {
     if (zipFile) {
         var name = 'SLAcer';
@@ -630,10 +1073,15 @@ $abortButton.on('click', function(e) {
     endSlicing();
 });
 
-$('#slicer-image-extension-' + (settings.get('slicer.png') ? 'png' : 'svg')).prop('checked', true);
+$outputType.val(settings.get('slicer.output'));
 $('#slicer-make-zip-' + (settings.get('slicer.zip') ? 'yes' : 'no')).prop('checked', true);
+
+//new
+$('#slicer-make-folder-' + (settings.get('slicer.folder') ? 'yes' : 'no')).prop('checked', true);
+
 $('#slicer-speed-' + (settings.get('slicer.speed') ? 'yes' : 'no')).prop('checked', true);
 $('#slicer input').on('input, change', updateSlicerSettings);
+$('#slicer select').on('change', updateSlicerSettings);
 updateSlicerUI();
 
 // Build volume panel
@@ -801,6 +1249,55 @@ $sliceColor.colorpicker().on('changeColor.colorpicker', function(e) {
     }
 });
 
+// gcode
+var $gcodeBody = initPanel('gcode');
+var $gcodeStart = $gcodeBody.find('#start');
+var $gcodeEnd = $gcodeBody.find('#end');
+var $gcodeResetStart = $gcodeBody.find('#resetStart');
+var $gcodeResetEnd = $gcodeBody.find('#resetEnd');
+
+function updateGcodeUI() {
+    var gcode = settings.get('gcode');
+
+    $gcodeStart.val(gcode.start);
+    $gcodeEnd.val(gcode.end);
+}
+
+function updateGcodeSettings() {
+    var startText = $gcodeStart.val();
+    var endText = $gcodeEnd.val();
+
+    settings.set('gcode', {
+        start   : $gcodeStart.val(),
+        end     : $gcodeEnd.val(),
+    });
+}
+
+function resetGcodeStart() {
+    $gcodeStart.val(getDefaultGcodeStart());
+    updateGcodeSettings();
+}
+
+function resetGcodeEnd() {
+    $gcodeEnd.val(getDefaultGcodeEnd());
+    updateGcodeSettings();
+}
+
+function getDefaultGcodeStart() {
+    return 'G21;\nG91;\nM17;\nM106 S0;\nG28 Z0;\n;W:480;\n;H:854;\n'; // see https://github.com/bastirichter/Sparkmaker/blob/master/file_format.md for details
+}
+
+function getDefaultGcodeEnd() {
+    return 'M106 S0;\nG1 Z20.0;\nG4 S300;\nM18;'; // see https://github.com/bastirichter/Sparkmaker/blob/master/file_format.md for details
+}
+
+$gcodeStart.on('change', updateGcodeSettings);
+$gcodeEnd.on('change', updateGcodeSettings);
+$gcodeResetStart.on('click', resetGcodeStart);
+$gcodeResetEnd.on('click', resetGcodeEnd);
+
+updateGcodeUI();
+
 // Alert
 var $alertPanel   = $('#alert');
 var $alertMessage = $alertPanel.find('.message');
@@ -1062,6 +1559,9 @@ loader.onError = errorHandler;
 //var stl = 'stl/Octocat-v2.stl';
 var stl = 'stl/StressTest.stl';
 //var stl = 'stl/SLAcer.stl';
+//var stl = 'stl/SparkMaker.stl';
+//var stl = 'stl/SparkMaker_fixed.stl';
+
 
 // File url
 // var url = 'http://' + window.location.hostname + window.location.pathname + stl;
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..f0d0ca7
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,8 @@
+{
+  "short_name": "SLAcer.js",
+  "name": "SLAcer.js (bêta)",
+  "description": "SLAcer.js (bêta)",
+  "start_url": "./index.html",
+  "display": "standalone",
+  "orientation": "landscape"
+}
\ No newline at end of file
diff --git a/other/print.wow b/other/print.wow
new file mode 100644
index 0000000..30876dc
Binary files /dev/null and b/other/print.wow differ
diff --git a/other/self_sliced_print.wow b/other/self_sliced_print.wow
new file mode 100644
index 0000000..275fed2
Binary files /dev/null and b/other/self_sliced_print.wow differ
diff --git a/other/slices/1.txt b/other/slices/1.txt
new file mode 100644
index 0000000..c3f7535
Binary files /dev/null and b/other/slices/1.txt differ
diff --git a/other/slices/10.txt b/other/slices/10.txt
new file mode 100644
index 0000000..8bcf39f
Binary files /dev/null and b/other/slices/10.txt differ
diff --git a/other/slices/11.txt b/other/slices/11.txt
new file mode 100644
index 0000000..495161c
Binary files /dev/null and b/other/slices/11.txt differ
diff --git a/other/slices/12.txt b/other/slices/12.txt
new file mode 100644
index 0000000..e316062
Binary files /dev/null and b/other/slices/12.txt differ
diff --git a/other/slices/13.txt b/other/slices/13.txt
new file mode 100644
index 0000000..b2f1bb2
Binary files /dev/null and b/other/slices/13.txt differ
diff --git a/other/slices/14.txt b/other/slices/14.txt
new file mode 100644
index 0000000..21e46de
Binary files /dev/null and b/other/slices/14.txt differ
diff --git a/other/slices/15.txt b/other/slices/15.txt
new file mode 100644
index 0000000..85ac93c
Binary files /dev/null and b/other/slices/15.txt differ
diff --git a/other/slices/16.txt b/other/slices/16.txt
new file mode 100644
index 0000000..0a94909
Binary files /dev/null and b/other/slices/16.txt differ
diff --git a/other/slices/2.txt b/other/slices/2.txt
new file mode 100644
index 0000000..c3f7535
Binary files /dev/null and b/other/slices/2.txt differ
diff --git a/other/slices/3.txt b/other/slices/3.txt
new file mode 100644
index 0000000..c3f7535
Binary files /dev/null and b/other/slices/3.txt differ
diff --git a/other/slices/4.txt b/other/slices/4.txt
new file mode 100644
index 0000000..c3f7535
Binary files /dev/null and b/other/slices/4.txt differ
diff --git a/other/slices/5.txt b/other/slices/5.txt
new file mode 100644
index 0000000..c3f7535
Binary files /dev/null and b/other/slices/5.txt differ
diff --git a/other/slices/6.txt b/other/slices/6.txt
new file mode 100644
index 0000000..d10e4af
Binary files /dev/null and b/other/slices/6.txt differ
diff --git a/other/slices/7.txt b/other/slices/7.txt
new file mode 100644
index 0000000..e0f2344
Binary files /dev/null and b/other/slices/7.txt differ
diff --git a/other/slices/8.txt b/other/slices/8.txt
new file mode 100644
index 0000000..0dbe9f6
Binary files /dev/null and b/other/slices/8.txt differ
diff --git a/other/slices/9.txt b/other/slices/9.txt
new file mode 100644
index 0000000..143fda1
Binary files /dev/null and b/other/slices/9.txt differ
diff --git a/stl/SparkMaker.stl b/stl/SparkMaker.stl
new file mode 100644
index 0000000..d05e6f0
Binary files /dev/null and b/stl/SparkMaker.stl differ
diff --git a/stl/SparkMaker_fixed.stl b/stl/SparkMaker_fixed.stl
new file mode 100644
index 0000000..e6479c1
Binary files /dev/null and b/stl/SparkMaker_fixed.stl differ
diff --git a/sw.js b/sw.js
new file mode 100644
index 0000000..50995c8
--- /dev/null
+++ b/sw.js
@@ -0,0 +1,61 @@
+// Use a cacheName for cache versioning
+var cacheName = 'v1:static';
+var cacheFiles = [
+    './',
+    'index.html',
+    './index.html',
+    './css/main.css',
+    './js/main.js',
+    './js/loader/stl.js',
+    './js/slacer/mesh.js',
+    './js/slacer/settings.js',
+    './js/slacer/slicer.js',
+    './js/slacer/viewer.js',
+    './js/slacer/viewcontrols.js',
+    './js/slacer/viewer2d.js',
+    './js/slacer/viewer3d.js',
+    './vendor/jquery-ui/jquery-ui.min.css',
+    './vendor/bootstrap/css/bootstrap.min.css',
+    './vendor/bootstrap-slider/css/bootstrap-slider.min.css',
+    './vendor/bootstrap-colorpicker/css/bootstrap-colorpicker.min.css',
+    './vendor/jquery-2.1.4.min.js',
+    './vendor/jquery-ui/jquery-ui.min.js',
+    './vendor/bootstrap/js/bootstrap.min.js',
+    './vendor/bootstrap-slider/bootstrap-slider.min.js',
+    './vendor/bootstrap-colorpicker/js/bootstrap-colorpicker.min.js',
+    './vendor/lodash.min.js',
+    './vendor/three.min.js',
+    './vendor/earcut.js',
+    './vendor/triangulation.js',
+    './vendor/OrbitControls.js',
+    './vendor/FileSaver.min.js',
+    './vendor/jszip.min.js'
+];
+
+// During the installation phase, you'll usually want to cache static assets.
+self.addEventListener('install', function(e) {
+    // Once the service worker is installed, go ahead and fetch the resources to make this work offline.
+    console.log('install');
+    e.waitUntil(
+        caches.open(cacheName).then(function(cache) {
+            return cache.addAll(cacheFiles).then(function() {
+                self.skipWaiting();
+            });
+        })
+    );
+});
+
+// when the browser fetches a URL…
+self.addEventListener('fetch', function(event) {
+    // … either respond with the cached object or go ahead and fetch the actual URL
+    event.respondWith(
+        caches.match(event.request).then(function(resp) {
+            return resp || fetch(event.request).then(function(response) {
+                return caches.open(cacheName).then(function(cache) {
+                    cache.put(event.request, response.clone());
+                    return response;
+                });
+            });
+        })
+    );
+});
\ No newline at end of file
