diff --git a/installer/install-centos.sh b/installer/install-centos.sh
new file mode 100644
index 0000000000000000000000000000000000000000..bee52940fec16aae0207455a9f0dfe413a6ceac9
--- /dev/null
+++ b/installer/install-centos.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+p=$OLDPWD
+wget -O /tmp/vipra.tar.gz ftp://cochu.io/vipra/vipra-current.tar.gz
+tar zxf /tmp/vipra.tar.gz -C /tmp
+rm /tmp/vipra.tar.gz
+cd /tmp/vipra*
+sudo ./install.sh >> /dev/null
+sudo yum install -y gsl-devel
+sudo make -C /opt/vipra/dtm_release/dtm
+cd $p
+rm -rf /tmp/vipra*
\ No newline at end of file
diff --git a/vipra-ui/app/html/explorer.html b/vipra-ui/app/html/explorer.html
index a7efde87cd76d7f730a8da9b32b4f76da6abcc16..87a3d44bd1e3c4bfcf88e19bec039aa9e92736dc 100644
--- a/vipra-ui/app/html/explorer.html
+++ b/vipra-ui/app/html/explorer.html
@@ -72,7 +72,7 @@
   <div class="row row-50">
     <div class="sidebar">
       <ul class="list-unstyled item-choice no-offset">
-        <li ng-repeat="topic in selectedTopics = (topics | filter: {selected: true} | orderBy:explorerModels.sorttopics:explorerModels.sortdir)" ng-mouseenter="highlightSeries(topic.id, true)" ng-mouseleave="highlightSeries(topic.id, false)" ng-class="{active:explorerModels.activeTopic.id===topic.id}" class="pointer text-muted">
+        <li ng-repeat="topic in selectedTopics = (topics | filter:{selected: true} | filter:search | orderBy:explorerModels.sorttopics:explorerModels.sortdir)" ng-mouseenter="highlightSeries(topic.id, true)" ng-mouseleave="highlightSeries(topic.id, false)" ng-class="{active:explorerModels.activeTopic.id===topic.id}" class="pointer text-muted">
           <div class="radio radio-condensed">
             <span class="valuebar" ng-style="{width:topic.topicCurrValue}"></span>
             <input tabindex="0" type="radio" ng-model="explorerModels.activeTopic" ng-attr-id="detail-{{::topic.id}}" name="topic-active" ng-value="topic">
diff --git a/vipra-ui/app/html/network.html b/vipra-ui/app/html/network.html
index fe9e9ab44144d6ca445051c75ee0f9623146a953..337c5ef415122e7819cd2d969f0b0a839ff602dc 100644
--- a/vipra-ui/app/html/network.html
+++ b/vipra-ui/app/html/network.html
@@ -19,7 +19,7 @@
           <input type="checkbox" id="showWords" ng-model="shown.words">
           <label for="showWords">Words</label>
         </div>
-        <div ng-show="!type">
+        <div style="display:none">
           Window
           <window-dropdown ng-model="selectedWindow" windows="windows" />
         </div>
diff --git a/vipra-ui/app/img/vipra-logo.png b/vipra-ui/app/img/vipra-logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..87dcf49c1cf1305e4c5caf026383c119fcef8a01
Binary files /dev/null and b/vipra-ui/app/img/vipra-logo.png differ
diff --git a/vipra-ui/app/index.html b/vipra-ui/app/index.html
index 8c976eac0623037b3603c0ed40b6ed56df400ff0..175de2910553996dbe8d8c19822a4653987ccd5f 100644
--- a/vipra-ui/app/index.html
+++ b/vipra-ui/app/index.html
@@ -22,12 +22,7 @@
           <span class="icon-bar"></span>
         </button>
         <a tabindex="0" ui-sref="index" class="navbar-brand">
-          <svg class="logo hover" viewBox="0 0 200 120" ng-class="{animate:loading.any}">
-            <polyline style="animation-delay:0s" class="logo-shape" points="0,0 100,45 100,75 0,0" fill="#006591" />
-            <polyline style="animation-delay:.5s" class="logo-shape" points="100,45 200,0 100,75 100,45" fill="#0079a2" />
-            <polyline style="animation-delay:1s" class="logo-shape" points="100,75 200,0 100,120 100,75" fill="#006591" />
-            <polyline style="animation-delay:1.5s" class="logo-shape" points="0,0 100,75 100,120 0,0" fill="#0079a2" />
-          </svg>
+          <img src="img/vipra-logo.png">
         </a>
       </div>
       <div class="collapse navbar-collapse" id="vipra-navbar-collapse-1">
diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js
index 349a0dc01b3cb09398254231974b1bc239359b01..0ea47e94957666a4de36fe6e3f9d1790457f0a43 100644
--- a/vipra-ui/app/js/controllers.js
+++ b/vipra-ui/app/js/controllers.js
@@ -281,9 +281,15 @@
           randomSeed: 1
         },
         physics: {
+          maxVelocity: 70,
           barnesHut: {
-            springConstant: 0.008,
-            gravitationalConstant: -3500
+            centralGravity: 0.5,
+            springConstant: 0.01,
+            gravitationalConstant: -7000,
+            avoidOverlap: 0.2
+          },
+          stabilization: {
+            fit: false
           }
         },
         interaction: {
@@ -299,10 +305,12 @@
         words: false
       };
 
-      var newNode = function(title, type, show, dbid, color, shape, loader) {
+      var newNode = function(title, type, show, dbid, color, shape, loader, x, y) {
         ids[dbid] = ++id;
         return {
           id: id,
+          x: x,
+          y: y,
           title: title,
           label: title.multiline(5).ellipsize(50),
           type: type,
@@ -345,17 +353,17 @@
         };
       };
 
-      var topicNode = function(topic) {
+      var topicNode = function(topic, x, y) {
         topic = topic.topic || topic;
-        return newNode(topic.name, 'topic', 'topics.show', topic.id, $scope.colors.topics, 'triangle', $scope.loadTopic);
+        return newNode(topic.name, 'topic', 'topics.show', topic.id, $scope.colors.topics, 'triangle', $scope.loadTopic, x, y);
       };
 
-      var articleNode = function(article) {
-        return newNode(article.title, 'article', 'articles.show', article.id, $scope.colors.articles, 'square', $scope.loadArticle);
+      var articleNode = function(article, x, y) {
+        return newNode(article.title, 'article', 'articles.show', article.id, $scope.colors.articles, 'square', $scope.loadArticle, x, y);
       };
 
-      var wordNode = function(word) {
-        return newNode(word.id, 'word', 'words.show', word.id, $scope.colors.words, 'box', $scope.loadWord);
+      var wordNode = function(word, x, y) {
+        return newNode(word.id, 'word', 'words.show', word.id, $scope.colors.words, 'box', $scope.loadWord, x, y);
       };
 
       var edgeExists = function(idA, idB) {
@@ -377,7 +385,7 @@
       };
 
       // construct new nodes
-      var constructor = function(result, node, nodeFunction) {
+      var constructor = function(result, nodeFunction, node, props) {
         if (result) {
           var newNodes = [],
             newEdges = [];
@@ -391,10 +399,16 @@
                 addEdge(ids[current.id], node.id);
               }
             } else {
-              newNodes.push(nodeFunction(current));
               if(node) {
+                if(props) {
+                  newNodes.push(nodeFunction(current, props.pointer.canvas.x, props.pointer.canvas.y));
+                } else {
+                  newNodes.push(nodeFunction(current));
+                }
                 newEdges.push(newEdge(id, node.id));
                 addEdge(id, node.id);
+              } else {
+                newNodes.push(nodeFunction(current));
               }
             }
           }
@@ -406,16 +420,12 @@
       };
 
       // on node select
-      var selectTimeout;
       $scope.select = function(props) {
-        $timeout.cancel(selectTimeout);
-        selectTimeout = $timeout(function() {
-          var node = $scope.nodes.get(props.nodes[0]);
-          if (node) {
-            node.loader(node);
-            $scope.nodes.update(node);
-          }
-        }, 500);
+        var node = $scope.nodes.get(props.nodes[0]);
+        if (node) {
+          node.loader(node, props);
+          $scope.nodes.update(node);
+        }
       };
 
       $scope.deselect = function() {
@@ -424,7 +434,7 @@
         });
       };
 
-      $scope.loadArticle = function(node) {
+      $scope.loadArticle = function(node, props) {
         ArticleFactory.get({
           id: node.dbid,
           fields: '_all'
@@ -434,42 +444,42 @@
           if (data.topics) {
             for (i = 0; i < data.topics.length; i++)
               data.topics[i] = data.topics[i].topic;
-            constructor(data.topics, node, topicNode);
+            constructor(data.topics, topicNode, node, props);
           }
           if (data.similarArticles && $scope.shown.similararticles) {
             var articles = [];
             for (i = 0; i < data.similarArticles.length; i++)
               articles.push(data.similarArticles[i].article);
-            constructor(articles, node, articleNode);
+            constructor(articles, articleNode, node, props);
           }
         });
       };
 
-      $scope.loadTopic = function(node) {
+      $scope.loadTopic = function(node, props) {
         if ($scope.shown.articles) {
           TopicFactory.articles({
             id: node.dbid,
             limit: 50
           }, function(data) {
-            constructor(data, node, articleNode);
+            constructor(data, articleNode, node, props);
           });
         }
         if ($scope.shown.words) {
           TopicFactory.get({
             id: node.dbid
           }, function(data) {
-            constructor(data.words, node, wordNode);
+            constructor(data.words, wordNode, node, props);
           });
         }
       };
 
-      $scope.loadWord = function(node) {
+      $scope.loadWord = function(node, props) {
         if ($scope.shown.articles) {
           ArticleFactory.query({
             word: node.dbid,
             topicModel: $scope.rootModels.topicModel.id
           }, function(data) {
-            constructor(data, node, articleNode);
+            constructor(data, articleNode, node, props);
           });
         }
         if ($scope.shown.topics) {
@@ -477,7 +487,7 @@
             word: node.dbid,
             topicModel: $scope.rootModels.topicModel.id
           }, function(data) {
-            constructor(data, node, topicNode);
+            constructor(data, topicNode, node, props);
           });
         }
       };
@@ -608,7 +618,7 @@
             TopicFactory.query({
               topicModel: $scope.rootModels.topicModel.id
             }, function(data) {
-              constructor(data, null, topicNode);
+              constructor(data, topicNode);
             });
           }
         };
@@ -632,7 +642,7 @@
         }, function(data) {
           $scope.windows = data;
         });
-      }
+      };
 
       $scope.$watch('rootModels.topicModel', function() {
         $scope.reloadWindows();
diff --git a/vipra-ui/app/less/app.less b/vipra-ui/app/less/app.less
index abb14385268ae0c83f99a9e3656d0fcced8874c9..525ddd12b3219419577a353745b85d89e9a99d41 100644
--- a/vipra-ui/app/less/app.less
+++ b/vipra-ui/app/less/app.less
@@ -110,9 +110,15 @@ a:hover {
     bottom: 10px;
     right: 10px;
   }
+  &.small {
+    max-width: 220px;
+  }
   &.small:not(.collapsed) {
     width: 220px;
   }
+  &.large {
+    max-width: 400px;
+  }
   &.large:not(.collapsed) {
     width: 400px;
   }
@@ -760,7 +766,7 @@ entity-menu {
 
 .title-band {
   background: linear-gradient(141deg, #0fb8ad 0%, #1fc8db 51%, #2cb5e8 75%);
-  padding: 100px 0 50px 0;
+  padding: 80px 0 50px 0;
   &.slim {
     padding: 80px 0 30px 0;
   }