diff --git a/README.md b/README.md
index f16e22b420840b14e2eb893a46610e19230ff7e0..8763224cd8af556d458bfebc9b4f4bee346d8933 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,55 @@
-x3dom + leaflet
\ No newline at end of file
+# x3dom + leaflet
+
+You can either run the demo:
+- On a web server with PHP support
+- Using the "Standalone installation" instructions below (could taint your system)
+- Using the "Docker image" instructions below (without tainting your system)
+
+## 1. Standalone installation
+### 1.1. Install dependencies
+
+You need php-cgi installed.
+
+Change to the x3domlet directory
+```
+cd x3domlet
+```
+
+If you don't have nodejs installed you may install it as a standard user through nvm with the following command:
+```
+docker/install-nodejs.sh
+```
+
+When nodejs is installed you can run:
+```
+npm install && bower install
+```
+
+### 1.2. Copy the test data
+You need to copy the data to be displayed in directories models/ and kml/
+
+### 1.3. Run the test server and open a browser window
+File modifications will trigger the page reload
+```
+gulp
+```
+
+## 2. Docker image
+
+The docker image allow you to run the demo in a virtual container
+without tainting your system.
+
+The current user should be allowed to run docker. Otherwise use 'sudo'.
+
+### 2.1. Build the docker image
+- Change to the ./docker directory.
+- Run "make" to build the docker image.
+
+### 2.2. Test
+From the directory containing the "/models" and "/kml" folders you want to use, run:
+```
+x3domlet/docker/run.sh
+```
+It will start the x3domlet docker image and open a browser window.
+On exit the script should stop and (WARNING) will remove the container and associated volumes.
+
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000000000000000000000000000000000000..32c3aaa85ce70d95e12d9abc31d3dadee1d86598
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,20 @@
+{
+  "name": "x3domlet",
+  "description": "",
+  "main": "",
+  "authors": [
+    "Oleg Dzhimiev <oleg@elphel.com>"
+  ],
+  "license": "GPL-3.0",
+  "homepage": "https://git.elphel.com/Elphel/x3domlet",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+    "jquery": "^3.2.1"
+  }
+}
diff --git a/docker/.dockerignore b/docker/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..270fdb709c706e01b9f648b525b1c4711e2658b1
--- /dev/null
+++ b/docker/.dockerignore
@@ -0,0 +1,2 @@
+README.txt
+Makefile
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..2199d6768b9b16a7d486cc8f32433a514cbf545c
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,24 @@
+FROM debian:jessie-slim
+RUN apt-get update \
+ && apt-get install -y \
+      git \
+      wget \
+      php5-cgi \
+			vim
+RUN useradd --create-home --shell /bin/bash elphel
+COPY install-nodejs.sh /tmp
+USER elphel
+RUN /tmp/install-nodejs.sh
+WORKDIR /home/elphel
+RUN cd /home/elphel \
+ && git clone --single-branch -b gulp https://git.elphel.com/Elphel/x3domlet \
+ && export NVM_DIR="/home/elphel/.nvm" \          
+ && [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" \
+ && npm install -g bower gulpjs/gulp-cli \
+ && cd x3domlet \
+ && npm install \
+ && bower install \
+ && gulp build
+WORKDIR /home/elphel/x3domlet
+COPY docker-entrypoint.sh /home/elphel/
+ENTRYPOINT ["/home/elphel/docker-entrypoint.sh"]
diff --git a/docker/Makefile b/docker/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..9eb646e6a057abe639206486910f6e6da984b7e0
--- /dev/null
+++ b/docker/Makefile
@@ -0,0 +1,4 @@
+all: x3domlet
+
+x3domlet:
+	docker build -t x3domlet .
diff --git a/docker/README.txt b/docker/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e7fbc7c3f5fb43b89fef13a3669cec127d8878a5
--- /dev/null
+++ b/docker/README.txt
@@ -0,0 +1,10 @@
+BUILD 
+- Run "make" to build the docker image.
+
+USE
+- Run "docker-run.sh" from the directory containing the "/models"
+  and "/kml" folders you want to use. It will start the docker image
+	and open a browser window.
+
+
+NOTE: The current user must be allowed to run docker. Otherwise use 'sudo'.
diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh
new file mode 100755
index 0000000000000000000000000000000000000000..fd5665b7c857fa01fc580a93b622a3d9eb55837a
--- /dev/null
+++ b/docker/docker-entrypoint.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+export NVM_DIR="/home/elphel/.nvm"
+[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
+exec "$@"
+
diff --git a/docker/docker-run.sh b/docker/docker-run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..937d3267614773a88a55f31e44b54493b55d5bb6
--- /dev/null
+++ b/docker/docker-run.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+docker run -i \
+	-v $(pwd)/models:/home/elphel/x3domlet/models \
+	-v $(pwd)/kml:/home/elphel/x3domlet/kml \
+	-p 8080:8080 \
+	-p 35729:35729 \
+	x3domlet \
+	gulp connect &
+
+sleep 5
+xdg-open http://localhost:8080/index.html
+
diff --git a/docker/install-nodejs.sh b/docker/install-nodejs.sh
new file mode 100755
index 0000000000000000000000000000000000000000..695b6b0654c47d621fd31f132c760696afa6b78b
--- /dev/null
+++ b/docker/install-nodejs.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+set -e
+
+echo checking for installed node version
+node --version && exit
+
+echo get latest nvm release number ... 
+NVM_VERSION=$(git ls-remote --tags https://github.com/creationix/nvm master v\* | sed -r -n -e 's/.*(v[0-9\.]+)$/\1/p' | sort -V | tail -n 1)
+
+echo downloading nvm $NVM_VERSION
+# download nvm installer
+wget -q -O /tmp/install.sh https://raw.githubusercontent.com/creationix/nvm/$NVM_VERSION/install.sh
+
+echo installing nvm
+. /tmp/install.sh
+export NVM_DIR="$HOME/.nvm"
+test -s "$NVM_DIR/nvm.sh"
+. "$NVM_DIR/nvm.sh"
+
+echo get latest node LTS release number
+NODE_VERSION=$(nvm ls-remote | grep LTS | tail -n 1 | sed -r -n -e 's/.*(v[0-9\.]+).*/\1/p')
+
+echo install nodejs
+nvm install $NODE_VERSION
+
+# disable npm progress
+touch $HOME/.npmrc
+grep -q progress= $HOME/.npmrc || echo progress=false >> $HOME/.npmrc
+
+echo install latest npm
+npm install -g npm
+
+echo done
diff --git a/docker/run.sh b/docker/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..907ad7117ad73baae35ed409a676f9739bf354a1
--- /dev/null
+++ b/docker/run.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# start the container in the background
+CONTAINER=$(docker run -i \
+	-d \
+	-v $(pwd)/models:/home/elphel/x3domlet/models \
+	-v $(pwd)/kml:/home/elphel/x3domlet/kml \
+	-p 8080:8080 \
+	-p 35729:35729 \
+	x3domlet \
+	gulp connect) || exit
+
+echo $CONTAINER
+
+# temporize
+sleep 5
+
+# open in browser
+xdg-open http://127.0.0.1:8080/index.html
+
+# display container startup log
+docker logs --since 0 $CONTAINER &
+
+# attach to container
+docker attach $CONTAINER
+
+# on exit remove the container and its associated volumes
+docker rm -f -v $CONTAINER
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 0000000000000000000000000000000000000000..7cde97928c2e639e8f54a55bebca45754ce1e954
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,273 @@
+"use strict";
+
+var gulp=require('gulp'),
+    bower=require('gulp-bower'),
+    wiredep=require('wiredep').stream,
+    foreach=require('gulp-foreach'),
+    usemin=require('gulp-usemin'),
+    htmlmin=require('gulp-htmlmin'),
+    sourcemaps=require('gulp-sourcemaps'),
+    uglify=require('gulp-uglify'),
+    cleanCss=require('gulp-clean-css'),
+    rev=require('gulp-rev'),
+    connect=require('gulp-connect'),
+    express=require('express'),
+    php=require('node-php'),
+    cors=require('cors'),
+    opn=require('opn'),
+    fs=require('fs'),
+    path=require('path'),
+    extend=require('extend'),
+    Q=require('q'),
+    clean=require('gulp-clean');
+
+var app;
+var config={
+  documentRoot: './',
+  host: '0.0.0.0',
+  port: 8080,
+  home: 'index.html',
+  bowerDir: './bower_components',
+  dist: './dist',
+
+}
+
+function abort(err) {
+  console.log(JSON.stringify(err,false,4));
+  process.exit(1);
+}
+
+function getHtmlFiles() {
+  return gulp.src('*.html');
+}
+
+// handle error events and synchronous chaining using promises
+function wrap(taskName,stream,q) {
+  stream=stream.on('error',function errorHandler(err){
+    console.log('ERROR: '+taskName+' failed !');
+    console.log(JSON.stringify(err,false,4));
+    if (q) {
+      q.reject(err);
+    } else {
+      process.exit(1);
+    }
+  }).on('end',function(){
+    if (q)
+      q.resolve(stream);
+  });
+  if (q) return q.promise;
+  else return stream;
+}
+
+// download bower dependencies
+gulp.task('bower', function(cb){
+   return bower()
+    .pipe(gulp.dest(config.bowerDir));
+});
+
+// merge bower.json with file specific options
+function getBowerJson(srcFile) {
+  try {
+    var srcFileJson=require(srcFile+'.json');
+  } catch(e) {}
+  var options=(srcFileJson && srcFileJson.bower)||{};
+  var bowerJson=extend(true,{},require('./bower.json'),options);
+  return bowerJson;
+}
+
+// inject bower dependencies
+gulp.task('wiredep', function(cb){
+  return getHtmlFiles()
+  .pipe(foreach(function(stream,file){
+    var filepath=path.join(file.cwd,file.relative);
+    console.log('wiredep: '+filepath);
+    return stream.pipe(
+      wrap('wiredep', wiredep({
+        verbose: true,
+        bowerJson: getBowerJson(filepath)
+      }))
+    );
+  }))
+  .pipe(
+    gulp.dest('.')
+  );
+});
+
+// replace references to scripts and stylesheets in html files
+// and store resulting files in directory "build"
+gulp.task('usemin', function(cb){
+    return getHtmlFiles()
+    .pipe(foreach(function(stream,file){
+      console.log('usemin: '+path.join(file.cwd,file.relative));
+      return stream.pipe(usemin({
+        css: [
+//          sourcemaps.init({
+//            loadMaps: true
+//          }),
+          wrap('cleanCss', cleanCss()),
+//          'concat',
+          rev(),
+//          sourcemaps.write()
+        ],
+        html: [
+          function() {
+            return wrap('htmlmin', htmlmin({
+              collapseWhitespace:true
+            }));
+          }
+        ],
+        js: [
+          sourcemaps.init({
+            loadMaps: true
+          }),
+          wrap('uglify js', uglify()),
+          'concat',
+          rev(),
+          sourcemaps.write()
+        ],
+        inlinejs: [
+          wrap('uglify inlinejs', uglify())
+        ],
+        inlinecss: [
+          wrap('cleanCss', cleanCss()),
+          'concat'
+        ]
+      }));
+    }))
+    .pipe(gulp.dest('build/'))
+});
+
+gulp.task('cleanbuild', function(){
+  return gulp.src('./build', {read: false})
+  .pipe(clean())
+});
+
+// copy files to directory "dist"
+gulp.task(
+  'dist',
+  function(cb) {
+      var count=3;
+      function goon(){
+        if (--count==0) {
+          cb(null);
+        }
+      }
+
+      // copy assets
+      wrap(
+        'copy assets',
+        gulp.src('./assets/**/*')
+        .pipe(gulp.dest(config.dist)),
+        Q.defer()
+      )
+      .catch(abort)
+      .then(goon)
+      .done();
+
+      // copy files
+      wrap(
+        'copy files',
+        gulp.src([
+          './build/**/*',
+          '*.php'
+        ])
+        .pipe(gulp.dest(config.dist)),
+        Q.defer()
+      )
+      .catch(abort)
+      .then(goon)
+      .done();
+
+      // copy images
+      wrap(
+        'copy images',
+        gulp.src([
+          './js/**/*.png'
+        ]).pipe(gulp.dest(path.join(config.dist,'js'))),
+        Q.defer()
+      )
+      .catch(abort)
+      .then(goon)
+      .done();
+    }
+);
+// serve content through express and php-cgi
+function php_cgi(connect,options) {
+  app=express();
+  app.use('/', php.cgi(config.documentRoot));
+  return app;
+}
+
+gulp.task('server',function(cb){
+  connect.server({
+    root: config.documentRoot,
+    host: config.host,
+    port: config.port,
+    middleware: function(connect,opt){
+      return [
+        cors(),
+        php_cgi()
+      ];
+    },
+    livereload: true
+  });
+  cb(null);
+});
+
+// watch for changes
+gulp.task('watch', function(cb){
+
+  // trigger reloading html pages when specified files change
+  gulp.watch(
+    [
+      '**.html',
+      '**.php',
+      '**.css',
+      '**.js',
+      '**.kml',
+      '**.x3d',
+      '!build/**/*',
+      '!gulpfile.js'
+    ],
+    gulp.series('html')
+  );
+
+  // trigger package injection/removal on bower.json change
+  gulp.watch('bower.json', gulp.series('inject'));
+
+  cb(null);
+  
+});
+
+// open browser
+gulp.task('open', function(cb){
+  opn('http://'+config.host+':'+config.port+'/'+config.home);
+  cb(null);
+});
+
+gulp.task('connect', gulp.series('server','watch','open'));
+
+// reload html pages on change
+gulp.task('html', function(){
+  return getHtmlFiles()
+  .pipe(connect.reload());
+});
+
+// inject bower dependencies
+gulp.task('inject', gulp.series('bower','wiredep'));
+
+// inject bower dependencies and generate directory 'build' content with usemin
+gulp.task('build', gulp.series('bower','wiredep','usemin'));
+
+gulp.task('prod-root', function(cb){
+  config.documentRoot=config.dist;
+  cb(null);
+});
+
+// start server with frorm "build" directory
+gulp.task('prod', gulp.series('prod-root','build','dist','connect'));
+
+gulp.task(
+  'default',
+  gulp.series('inject','connect')
+);
diff --git a/index.html b/index.html
index 23e818e4f1877be6d84b82eed998411a594b7282..474cbaa7287a2563ffee8eaaa4e8bd98f9b5ee9a 100644
--- a/index.html
+++ b/index.html
@@ -4,12 +4,20 @@
     <meta charset="utf-8"/>
     <title>x3d models index</title>
 
-    <script type='text/javascript' src='js/jquery/jquery-3.1.1.js'></script>
-    <script type='text/javascript' src='js/leaflet/leaflet-src.js'></script>
-    <script type='text/javascript' src='js/index.js'></script>
-
+    <!-- build:css css/index.css -->
+    <!-- bower:css -->
+    <!-- endbower -->
     <link rel='stylesheet' type='text/css' href='js/leaflet/leaflet.css'></link>
     <link rel='stylesheet' type='text/css' href='js/index.css'></link>
+    <!-- endbuild -->
+
+    <!-- build:js js/index.js -->
+    <!-- bower:js -->
+    <script src='bower_components/jquery/dist/jquery.js'></script>
+    <!-- endbower -->
+    <script type='text/javascript' src='js/leaflet/leaflet-src.js'></script>
+    <script type='text/javascript' src='js/index.js'></script>
+    <!-- endbuild -->
 
   </head>
   <body>
diff --git a/js/ui_init.js b/js/ui_init.js
index dcc30f8bcf832351156b899e38cb90f0394bfed2..cf075eee67f9eff1974aee638dc001901c053dd6 100644
--- a/js/ui_init.js
+++ b/js/ui_init.js
@@ -122,23 +122,23 @@ function light_init(){
     var model_url = SETTINGS.basepath+"/"+SETTINGS.path+"/"+SETTINGS.version+"/"+SETTINGS.path+".x3d";
     var model_back_url = SETTINGS.basepath+"/"+SETTINGS.path+"/"+SETTINGS.version+"/"+SETTINGS.path+"-texture-bgnd-ext.jpeg";
 
-    var model = $(`
-        <group>
-            <inline name='mymodel' namespacename='mymodel' url='`+model_url+`'></inline>
-        </group>
-        <group>
-            <Background
-                id="Background"
-                class="Background"
-                backUrl=  "js/images/background_side.jpeg"
-                bottomUrl="js/images/background_floor.jpeg"
-                frontUrl= "`+model_back_url+`"
-                leftUrl=  "js/images/background_side.jpeg"
-                rightUrl= "js/images/background_side.jpeg"
-                topUrl=   "js/images/background_sky.jpeg">
-            </Background>
-        </group>
-        `);
+    var model = $([
+        '<group>',
+        '    <inline name="mymodel" namespacename="mymodel" url="'+model_url+'"></inline>',
+        '</group>',
+        '<group>',
+        '    <Background ',
+        '        id="Background"',
+        '        class="Background"',
+        '        backUrl=  "js/images/background_side.jpeg"',
+        '        bottomUrl="js/images/background_floor.jpeg"',
+        '        frontUrl= "'+model_back_url+'"',
+        '        leftUrl=  "js/images/background_side.jpeg"',
+        '        rightUrl= "js/images/background_side.jpeg"',
+        '        topUrl=   "js/images/background_sky.jpeg">',
+        '    </Background>',
+        '</group>'
+      ].join('\n'));
 
     x3delement.append(model);
 
@@ -175,7 +175,6 @@ function light_init(){
             Scene.initResize();
 
             $.getScript("js/x3dom/x3dom-full.debug.js",function(){
-
                 Map = new LeafletObject('leaflet_map',Data,{});
                 //wait until it DOM is extended
                 x3dom.runtime.ready = function(){
@@ -189,7 +188,6 @@ function light_init(){
 
                 };
             });
-
         },
     });
 
diff --git a/js/x3dom_init.js b/js/x3dom_init.js
index beeaa05d260bd5eaeb882b2d70fb648a914b2c8e..c46e1b292cb20940c2cc7a9f63fb29c3633046da 100644
--- a/js/x3dom_init.js
+++ b/js/x3dom_init.js
@@ -441,24 +441,24 @@ X3DOMObject.prototype.createMarker = function(x,y,z,id){
         size  = self.data.markers[index].size/2;
     }
 
-    var html = `
-    <group id='`+id+`' class='`+sph_class+`'>
-    <switch whichChoice='0'>
-    <transform translation='`+x+` `+y+` `+z+`' rotation='0 0 0 0'>
-        <shape class='shapemarker'>
-        <appearance>
-            <material diffuseColor='`+color+`' transparency='0.0' myColor='`+color+`'></material>
-        </appearance>
-        <Sphere DEF="sphere" radius="`+size+`" />
-        </shape>
-    </transform>
-    </switch>
-    </group>
-    `;
+    var html = [
+      '<group id="'+id+'" class="'+sph_class+'">',
+      '  <switch whichChoice="0">',
+      '    <transform translation="'+x+' '+y+' '+z+'" rotation="0 0 0 0">',
+      '      <shape class="shapemarker">',
+      '        <appearance>',
+      '          <material diffuseColor="'+color+'" transparency="0.0" myColor="'+color+'"></material>',
+      '        </appearance>',
+      '        <Sphere DEF="sphere" radius="'+size+'" />',
+      '      </shape>',
+      '    </transform>',
+      '  </switch>',
+      '</group>'
+    ].join('\n');
 
     var sphere_element = $(html);
 
-    $(this.element).find("scene").append(sphere_element);
+    $('scene',this.element).append(sphere_element);
 
     //var shape = $(sphere_element).find("shape");
     //var id_prefix = $(sphere_element).attr("id").substr(0,7);
diff --git a/map.html b/map.html
index ccc430484c9f2e210d2214e82e9869cce45875f0..0bd6d19a0050ebf5f1923f8d645125b1aacbd206 100644
--- a/map.html
+++ b/map.html
@@ -3,16 +3,25 @@
 <head>
   <title>Ze Map</title>
   <meta charset="utf-8"/>
-  <script type='text/javascript' src='js/jquery/jquery-3.1.1.js'></script>
+<!-- build:css css/map.css -->
+<!-- bower:css -->
+<!-- endbower -->
+  <link rel='stylesheet' type='text/css' href='js/leaflet/leaflet.css'></link>
+  <link rel='stylesheet' type='text/css' href='js/map.css'></link>
+<!--endbuild-->
+<!-- build:js js/map.js -->
+<!-- bower:js -->
+<script src='bower_components/jquery/dist/jquery.js'></script>
+<!-- endbower -->
   <script type='text/javascript' src='js/leaflet/leaflet-src.js'></script>
   <script type='text/javascript' src='js/leaflet/leaflet.camera-view-marker-controls.js'></script>
   <script type='text/javascript' src='js/leaflet/leaflet.camera-view-marker.js'></script>
   <script type='text/javascript' src='js/leaflet/leaflet.camera-view-marker.measure.js'></script>
   <script type='text/javascript' src='js/map.js'></script>
-  <link rel='stylesheet' type='text/css' href='js/leaflet/leaflet.css'></link>
-  <link rel='stylesheet' type='text/css' href='js/map.css'></link>
+<!--endbuild-->
 </head>
 <body>
   <div id="leaflet_map"></div>
 </body>
 </html>
+ls
diff --git a/package.json b/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..5f35bb81bd701be065a318ad844df62800f8d7e7
--- /dev/null
+++ b/package.json
@@ -0,0 +1,42 @@
+{
+  "name": "x3domlet",
+  "version": "1.0.0",
+  "repository": {
+    "type": "git",
+    "url": "https://git.elphel.com/Elphel/x3domlet"
+  },
+  "author": "Oleg Dzhimiev <oleg@elphel.com>",
+  "license": "GPL-3.0",
+  "devDependencies": {
+    "cors": "^2.8.3",
+    "express": "^4.15.3",
+    "extend": "^3.0.1",
+    "gulp": "github:gulpjs/gulp#4.0",
+    "gulp-bower": "0.0.13",
+    "gulp-clean-css": "^3.4.1",
+    "gulp-concat": "^2.6.1",
+    "gulp-connect": "^5.0.0",
+    "gulp-cssmin": "^0.2.0",
+    "gulp-foreach": "^0.1.0",
+    "gulp-htmlmin": "^3.0.0",
+    "gulp-rev": "^7.1.2",
+    "gulp-sourcemaps": "^2.6.0",
+    "gulp-uglify": "^3.0.0",
+    "gulp-usemin": "^0.3.28",
+    "gulp4": "^4.0.1",
+    "node-php": "0.0.1",
+    "opn": "^5.0.0",
+    "q": "^1.5.0",
+    "shelljs": "^0.7.8",
+    "wiredep": "^4.0.0",
+    "gulp-clean": "^0.3.2"
+  },
+  "description": "x3dom + leaflet",
+  "dependencies": {
+  },
+  "scripts": {
+    "postinstall": "node scripts/postinstall.js",
+    "start": "node scripts/postinstall.js && gulp"
+  },
+  "main": "gulpfile.js"
+}
diff --git a/scripts/postinstall.js b/scripts/postinstall.js
new file mode 100755
index 0000000000000000000000000000000000000000..9fec7520244a76e0677639455c78e34d2bca4d16
--- /dev/null
+++ b/scripts/postinstall.js
@@ -0,0 +1,7 @@
+#!/usr/bin/env node
+var shelljs=require('shelljs');
+if (!shelljs.which('php-cgi')) {
+  console.log('php-cgi not found. Maybe you can install it with:');
+  console.log('sudo apt-get install php5-cgi');
+  process.exit(1);
+}
diff --git a/test.html b/test.html
index d08ea4a8392c0c2f8f91840dd3cb967e7041bc87..2ab688a86a5871a28c7a9ebba5cde0eed9db3399 100644
--- a/test.html
+++ b/test.html
@@ -4,7 +4,19 @@
     <meta charset="utf-8"/>
     <title>Scene+Map</title>
 
-    <script type='text/javascript' src='js/jquery/jquery-3.1.1.js'></script>
+    <!-- build:css css/test.css -->
+    <!-- bower:css -->
+    <!-- endbower -->
+    <link rel='stylesheet' type='text/css' href='js/leaflet/leaflet.css'></link>
+    <link rel='stylesheet' type='text/css' href='js/x3dom/x3dom.css'></link>
+
+    <link rel='stylesheet' type='text/css' href='js/ui.css'></link>
+    <!-- endbuild -->
+
+    <!-- build:js js/test.js -->
+    <!-- bower:js -->
+    <script src='bower_components/jquery/dist/jquery.js'></script>
+    <!-- endbower -->
 
     <script type='text/javascript' src='js/leaflet/leaflet-src.js'></script>
     <script type='text/javascript' src='js/leaflet/L.extra.js'></script>
@@ -12,6 +24,7 @@
     <script type='text/javascript' src='js/leaflet/leaflet.camera-view-marker.js'></script>
     <script type='text/javascript' src='js/leaflet/leaflet.camera-view-marker.measure.js'></script>
 
+    <!---script type='text/javascript' src='js/x3dom/x3dom-full.debug.js'></script-->
     <script type='text/javascript' src='js/x3dom_init.js'></script>
     <script type='text/javascript' src='js/x3dom_functions.js'></script>
 
@@ -25,11 +38,7 @@
     <script type='text/javascript' src='js/ui_align.js'></script>
 
     <script type='text/javascript' src='js/util_functions.js'></script>
-
-    <link rel='stylesheet' type='text/css' href='js/leaflet/leaflet.css'></link>
-    <link rel='stylesheet' type='text/css' href='js/x3dom/x3dom.css'></link>
-
-    <link rel='stylesheet' type='text/css' href='js/ui.css'></link>
+    <!-- endbuild -->
 
   </head>
   <body>