diff --git a/app/components/architecture-visualisation-cola.js b/app/components/architecture-visualisation-cola.js
new file mode 100644
index 0000000000000000000000000000000000000000..14a538d5d32e88391b73b8f395d890cab5442237
--- /dev/null
+++ b/app/components/architecture-visualisation-cola.js
@@ -0,0 +1,145 @@
+import Ember from 'ember';
+import d3 from 'd3';
+import cola from 'npm:webcola';
+import _ from 'npm:lodash';
+
+export default Ember.Component.extend({
+    init: function() {
+        this._super();
+        const self = this;
+        const log = self.debug.bind(self);
+        log('loaded');
+        // this.interval = setInterval(function() {
+        //     const graph = self.get('graph');
+
+        //     log('update interval called', graph);
+
+        //     if(!graph) {
+        //         return; // eventual consistent
+        //     }
+        //     const edges = graph.edges || [];
+        //     const index = Math.floor(Math.random()*edges.length);
+        //     if(Math.random() > 0.5) {
+        //         edges.splice(index, 1);
+        //     } else { // FIXME: does not render updates
+        //         const children = _.get(graph, 'children', []);
+        //         const randomNodeIndex = Math.floor(Math.random()*children.length);
+        //         const randomNodeId = children[randomNodeIndex].id;
+        //         graph.edges = _.set(edges, `${index}.target`, randomNodeId);
+        //         log(`updating random edge (${index}) to target a random node id ${randomNodeId}`, randomNodeIndex, edges);
+        //     }
+        //     self.set('graph', graph);
+        //     self.renderGraph();
+        // }, 1000);
+    },
+    willDestroyElement() {
+        clearInterval(this.interval);
+    },
+    didInsertElement: function() {
+        const log = this.debug.bind(this);
+        const width = window.innerWidth;
+        const height = window.innerHeight;
+        this.debug('element', this.element);
+        const zoom = d3.behavior.zoom()
+            .on("zoom", redraw);
+
+        const svg = d3.select(this.element)
+            .append("svg")
+            .attr("width", width)
+            .attr("height", height)
+            .attr('class', 'architectureVisualisation')
+            .call(zoom)
+            .append("g");
+        const root = svg.append('g').attr('class', 'root');
+
+        this.svg = svg;
+        this.layouter = cola.d3adaptor()
+            .linkDistance(80)
+            .avoidOverlaps(true)
+            .handleDisconnected(false)
+            .size([width, height]);
+        // group shizzle
+
+        this.debug('element', this.element);
+
+        function redraw() {
+            svg.attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")");
+        }
+
+        const graph = this.get('graph');
+
+        const nodes = graph.nodes;
+        const links = graph.links;
+        const groups = graph.groups;
+        this.layouter
+            .nodes(nodes)
+            .links(links)
+            .groups(groups)
+            .start(100, 0, 50, 50);
+
+        // nodes
+        const nodeData = root.selectAll('.node')
+            .data(nodes);
+        const groupData = root.selectAll('.group')
+            .data(groups);
+        const nodeEnter = nodeData.enter()
+            .append('g');
+
+        nodeData
+            .attr('class', 'node leaf')
+            .attr('width', 10)
+            .attr('height', 10)
+            .attr('x', 0)
+            .attr('y', 0);
+
+        const atoms = nodeEnter.append('rect');
+
+        nodeEnter.append('title')
+            .text(d => d.id);
+
+        nodeEnter.append('text')
+            .attr('x', (d) => d.children? 0 : 2.5)
+            .attr('y', 5)
+            .text((d) => _.get(d, 'labels.0.text', d.id))
+            .attr('font-size', '4px')
+            .attr('font-size', '4px');
+
+        nodeData.exit()
+            .remove();
+
+        // edges
+        // FIXME does not handle updates (neither enter() nor exit())
+        const linkData = root.selectAll('.link')
+            .data(links, p => p.id);
+        const link = linkData.enter()
+            .append('path')
+            .attr('class', 'link')
+            .attr('d', 'M0 0');
+
+
+        linkData.exit()
+            .remove();
+
+        // apply edge routes
+        // linkData.transition().attr('d', (d) => {
+        //     log('test', this.layouter);
+        //   let path = '';
+        //   path += 'M' + d.sourcePoint.x + ' ' + d.sourcePoint.y + ' ';
+        //     (d.bendPoints || []).forEach(bp => path += 'L' + bp.x + ' ' + bp.y + ' ');
+        //   path += 'L' + d.targetPoint.x + ' ' + d.targetPoint.y + ' ';
+        //   return path;
+        // });
+
+        // apply nodeEnter positions
+        nodeData.transition()
+          .attr('transform', (d) => 'translate(' + (d.x || 0) + ' ' + (d.y || 0) + ')');
+
+        atoms.transition()
+          .attr('width', (d) => d.width)
+          .attr('height', (d) => d.height);
+        // this.layouter.on('finish', onFinish);
+        // this.renderGraph();
+    }
+});
+
+
diff --git a/app/components/architecture-visualisation-cytoscape.js b/app/components/architecture-visualisation-cytoscape.js
new file mode 100644
index 0000000000000000000000000000000000000000..e4d7bb53bf17423cc117bf2cb370f4b9cb2ccfc3
--- /dev/null
+++ b/app/components/architecture-visualisation-cytoscape.js
@@ -0,0 +1,97 @@
+import Ember from 'ember';
+import cytoscape from 'npm:cytoscape';
+import cycola from 'npm:cytoscape-cola';
+// import cola from 'npm:webcola';
+import _ from 'npm:lodash';
+
+export default Ember.Component.extend({
+    classNames: ['cytoscapeRenderingSpace'],
+    init: function() {
+        cycola( cytoscape, cola );
+
+        this._super();
+        const self = this;
+        const log = self.debug.bind(self);
+        log('loaded');
+        // this.interval = setInterval(function() {
+        //     const graph = self.get('graph');
+
+        //     log('update interval called', graph);
+
+        //     if(!graph) {
+        //         return; // eventual consistent
+        //     }
+        //     const edges = graph.edges || [];
+        //     const index = Math.floor(Math.random()*edges.length);
+        //     if(Math.random() > 0.5) {
+        //         edges.splice(index, 1);
+        //     } else { // FIXME: does not render updates
+        //         const children = _.get(graph, 'children', []);
+        //         const randomNodeIndex = Math.floor(Math.random()*children.length);
+        //         const randomNodeId = children[randomNodeIndex].id;
+        //         graph.edges = _.set(edges, `${index}.target`, randomNodeId);
+        //         log(`updating random edge (${index}) to target a random node id ${randomNodeId}`, randomNodeIndex, edges);
+        //     }
+        //     self.set('graph', graph);
+        //     self.renderGraph();
+        // }, 1000);
+    },
+    willDestroyElement() {
+        clearInterval(this.interval);
+    },
+    didInsertElement: function() {
+        this.cytoscape = cytoscape({
+          container: this.element,
+
+          boxSelectionEnabled: false,
+          autounselectify: true,
+
+          style: [
+            {
+              selector: 'node',
+              css: {
+                'content': 'data(id)',
+                'text-valign': 'center',
+                'text-halign': 'center'
+              }
+            },
+            {
+              selector: '$node > node',
+              css: {
+                'padding-top': '10px',
+                'padding-left': '10px',
+                'padding-bottom': '10px',
+                'padding-right': '10px',
+                'text-valign': 'top',
+                'text-halign': 'center',
+                'background-color': '#bbb'
+              }
+            },
+            {
+              selector: 'edge',
+              css: {
+                'target-arrow-shape': 'triangle'
+              }
+            },
+            {
+              selector: ':selected',
+              css: {
+                'background-color': 'black',
+                'line-color': 'black',
+                'target-arrow-color': 'black',
+                'source-arrow-color': 'black'
+              }
+            }
+          ],
+
+          elements: this.get('graph'),
+
+          layout: {
+            name: 'cola',
+            padding: 5
+          }
+        });
+    }
+});
+
+
diff --git a/app/components/architecture-visualisation.js b/app/components/architecture-visualisation.js
index 715f5db23a424fb9fad72920446db91e52a5530a..a4365ead3a6e6d89d8c0cd9e776b6a0bf931cb3f 100644
--- a/app/components/architecture-visualisation.js
+++ b/app/components/architecture-visualisation.js
@@ -8,28 +8,28 @@ export default Ember.Component.extend({
         this._super();
         const self = this;
         const log = self.debug.bind(self);
-        this.interval = setInterval(function() {
-            const graph = self.get('graph');
-
-            log('update interval called', graph);
-
-            if(!graph) {
-                return; // eventual consistent
-            }
-            const edges = graph.edges || [];
-            const index = Math.floor(Math.random()*edges.length);
-            if(Math.random() > 0.5) {
-                edges.splice(index, 1);
-            } else { // FIXME: does not render updates
-                const children = _.get(graph, 'children', []);
-                const randomNodeIndex = Math.floor(Math.random()*children.length);
-                const randomNodeId = children[randomNodeIndex].id;
-                graph.edges = _.set(edges, `${index}.target`, randomNodeId);
-                log(`updating random edge (${index}) to target a random node id ${randomNodeId}`, randomNodeIndex, edges);
-            }
-            self.set('graph', graph);
-            self.renderGraph();
-        }, 1000);
+        // this.interval = setInterval(function() {
+        //     const graph = self.get('graph');
+
+        //     log('update interval called', graph);
+
+        //     if(!graph) {
+        //         return; // eventual consistent
+        //     }
+        //     const edges = graph.edges || [];
+        //     const index = Math.floor(Math.random()*edges.length);
+        //     if(Math.random() > 0.5) {
+        //         edges.splice(index, 1);
+        //     } else { // FIXME: does not render updates
+        //         const children = _.get(graph, 'children', []);
+        //         const randomNodeIndex = Math.floor(Math.random()*children.length);
+        //         const randomNodeId = children[randomNodeIndex].id;
+        //         graph.edges = _.set(edges, `${index}.target`, randomNodeId);
+        //         log(`updating random edge (${index}) to target a random node id ${randomNodeId}`, randomNodeIndex, edges);
+        //     }
+        //     self.set('graph', graph);
+        //     self.renderGraph();
+        // }, 1000);
     },
     willDestroyElement() {
         clearInterval(this.interval);
@@ -56,7 +56,10 @@ export default Ember.Component.extend({
             .size([width, height])
             .transformGroup(root)
             .options({
-                edgeRouting: "ORTHOGONAL"
+                edgeRouting: "ORTHOGONAL",
+                aspectRatio: 1.7,
+                separateConnComp: true,
+                // layoutHierarchy: false
             });
         // group shizzle
 
@@ -112,7 +115,6 @@ export default Ember.Component.extend({
 
             // apply edge routes
             linkData.transition().attr('d', (d) => {
-                log('test');
               let path = '';
               path += 'M' + d.sourcePoint.x + ' ' + d.sourcePoint.y + ' ';
                 (d.bendPoints || []).forEach(bp => path += 'L' + bp.x + ' ' + bp.y + ' ');
diff --git a/app/index.html b/app/index.html
index c49346f27f1ff588f6f731877411cf635c0f10db..4763ae76e9389e6fe4090179af1ff19a18647ca4 100644
--- a/app/index.html
+++ b/app/index.html
@@ -11,6 +11,7 @@
 
     <link rel="stylesheet" href="assets/vendor.css">
     <link rel="stylesheet" href="assets/frontend-prototype.css">
+    <script src="http://marvl.infotech.monash.edu/webcola/cola.v3.min.js"></script>
 
     {{content-for "head-footer"}}
   </head>
diff --git a/app/router.js b/app/router.js
index f6c0454579fdefd05864742a53f7090a09a4f9a6..fc46ed2107522b1950e4d202c22c83d0133ae6aa 100644
--- a/app/router.js
+++ b/app/router.js
@@ -6,8 +6,10 @@ const Router = Ember.Router.extend({
 });
 
 Router.map(function() {
-    this.route('home', {path: '/'});
-    this.route('architecture', {path: '/architecture'});
+  this.route('home', {path: '/'});
+  this.route('architecture', {path: '/architecture'});
+  this.route('cola', {path: '/cola'});
+  this.route('cytoscape');
 });
 
 export default Router;
diff --git a/app/routes/architecture.js b/app/routes/architecture.js
index d78a1ba4f345803dfb4d3e7e0cff2d1c4846b1a6..b3b46e58c472db2eeeffa6db2e22d40902addb85 100644
--- a/app/routes/architecture.js
+++ b/app/routes/architecture.js
@@ -7,7 +7,10 @@ export default Ember.Route.extend({
         labels: [{text: 'My Architecture'}],
         'properties': {
             'direction': 'RIGHT',
-            'spacing': 10
+            'spacing': 10,
+            'de.cau.cs.kieler.aspectRatio': 1.7,
+            'de.cau.cs.kieler.separateConnComp': true,
+            'separateConnComp': true
         },
         children: [{
             id: 'VM_Profile',
@@ -128,7 +131,7 @@ export default Ember.Route.extend({
             id: 'VM_2>Auth->VM_4>User',
             source: 'VM_2>Auth',
             target: 'VM_4>User',
-        }, {
+        } /*{
             id: 'VM_Big>User->VM_Profile>Database',
             source: 'VM_Big>User',
             target: 'VM_Profile>Database',
@@ -164,7 +167,7 @@ export default Ember.Route.extend({
             id: 'VM_8>User->VM_Profile>Database',
             source: 'VM_8>User',
             target: 'VM_Profile>Database',
-        }]
+        }*/]
     };
   }
 });
\ No newline at end of file
diff --git a/app/routes/cola.js b/app/routes/cola.js
new file mode 100644
index 0000000000000000000000000000000000000000..0a406f9ade27984706d99266a8951c98da479f01
--- /dev/null
+++ b/app/routes/cola.js
@@ -0,0 +1,31 @@
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+  model() {
+    return {
+        "nodes":[
+          {"name":"a","width":60,"height":40},
+          {"name":"b","width":60,"height":40},
+          {"name":"c","width":60,"height":40},
+          {"name":"d","width":60,"height":40},
+          {"name":"e","width":60,"height":40},
+          {"name":"f","width":60,"height":40},
+          {"name":"g","width":60,"height":40}
+        ],
+        "links":[
+          {"source":1,"target":2},
+          {"source":2,"target":3},
+          {"source":3,"target":4},
+          {"source":0,"target":1},
+          {"source":2,"target":0},
+          {"source":3,"target":5},
+          {"source":0,"target":5}
+        ],
+        "groups":[
+          {"leaves":[0], "groups":[1]},
+          {"leaves":[1,2]},
+          {"leaves":[3,4]}
+        ]
+    };
+  }
+});
\ No newline at end of file
diff --git a/app/styles/app.scss b/app/styles/app.scss
index 1c11d3099cce62f5e51e8a0286aa65b15942c61f..9fb42c09daafbdff166499016efd6792e8e03a19 100644
--- a/app/styles/app.scss
+++ b/app/styles/app.scss
@@ -3,4 +3,5 @@ body {
 }
 
 @import "components/_architecture";
+@import "components/_cytoscape";
 
diff --git a/app/styles/components/_cytoscape.scss b/app/styles/components/_cytoscape.scss
new file mode 100644
index 0000000000000000000000000000000000000000..4fe0241a91a4e2b770bc88dbbfd579fff4dbce98
--- /dev/null
+++ b/app/styles/components/_cytoscape.scss
@@ -0,0 +1,7 @@
+.cytoscapeRenderingSpace {
+  height: 100%;
+  width: 100%;
+  position: absolute;
+  left: 0;
+  top: 0;
+}
\ No newline at end of file
diff --git a/app/templates/application.hbs b/app/templates/application.hbs
index c009e1f31ca94f76ced0bb9adafbd5b0bf5e3744..8231f96b83518b468ace123ecbc3c47ea2965219 100644
--- a/app/templates/application.hbs
+++ b/app/templates/application.hbs
@@ -2,6 +2,8 @@
 <ul>
     <li>Go to {{#link-to 'home'}}Home{{/link-to}}</li>
     <li>Go to {{#link-to 'architecture'}}Klay-based Architecture{{/link-to}}</li>
+    <li>Go to {{#link-to 'cola'}}Webcola Architecture{{/link-to}}</li>
+    <li>Go to {{#link-to 'cytoscape'}}Cytoscape Architecture{{/link-to}}</li>
 </ul>
 
 {{outlet}}
diff --git a/app/templates/cola.hbs b/app/templates/cola.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..959c621878f0e2c4072b9a971bb575f62cba133a
--- /dev/null
+++ b/app/templates/cola.hbs
@@ -0,0 +1,2 @@
+Visualisierung:
+{{architecture-visualisation-cola graph=model}}
\ No newline at end of file
diff --git a/app/templates/cytoscape.hbs b/app/templates/cytoscape.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..e74a09ba3a3edf4f1585698eac9cb9bb9b2ea931
--- /dev/null
+++ b/app/templates/cytoscape.hbs
@@ -0,0 +1 @@
+{{architecture-visualisation-cytoscape graph=model}}
\ No newline at end of file
diff --git a/package.json b/package.json
index 46367b26428f9435f1d8ff3aa94034e850a34f3e..6c07f1559fa28fb642d7c1ddf05815e968819b98 100644
--- a/package.json
+++ b/package.json
@@ -46,7 +46,10 @@
     "lodash": "^4.11.1"
   },
   "dependencies": {
+    "cytoscape": "^2.6.12",
+    "cytoscape-cola": "^1.4.0",
     "klayjs": "^0.4.1",
-    "klayjs-d3": "^0.3.4"
+    "klayjs-d3": "^0.3.4",
+    "webcola": "^3.1.2"
   }
 }
diff --git a/tests/unit/models/baseentity-test.js b/tests/unit/models/baseentity-test.js
new file mode 100644
index 0000000000000000000000000000000000000000..479e8f0e0346f8aaabd4b507aeecd38e07269e2c
--- /dev/null
+++ b/tests/unit/models/baseentity-test.js
@@ -0,0 +1,12 @@
+import { moduleForModel, test } from 'ember-qunit';
+
+moduleForModel('baseentity', 'Unit | Model | baseentity', {
+  // Specify the other units that are required for this test.
+  needs: []
+});
+
+test('it exists', function(assert) {
+  let model = this.subject();
+  // let store = this.store();
+  assert.ok(!!model);
+});
diff --git a/tests/unit/models/system-test.js b/tests/unit/models/system-test.js
new file mode 100644
index 0000000000000000000000000000000000000000..fe98d2c93451624611df45ab7f69e7b60d294655
--- /dev/null
+++ b/tests/unit/models/system-test.js
@@ -0,0 +1,12 @@
+import { moduleForModel, test } from 'ember-qunit';
+
+moduleForModel('system', 'Unit | Model | system', {
+  // Specify the other units that are required for this test.
+  needs: []
+});
+
+test('it exists', function(assert) {
+  let model = this.subject();
+  // let store = this.store();
+  assert.ok(!!model);
+});
diff --git a/tests/unit/routes/cytoscape-test.js b/tests/unit/routes/cytoscape-test.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b8e45a0cbe78e4f197737aaabf8575fcbd8b6c3
--- /dev/null
+++ b/tests/unit/routes/cytoscape-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:cytoscape', 'Unit | Route | cytoscape', {
+  // Specify the other units that are required for this test.
+  // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+  let route = this.subject();
+  assert.ok(route);
+});