diff --git a/.gitignore b/.gitignore
index 28c3bf0dbdb0fb025f6aaaeaf2428651691653b5..2f5c12e033920f950017f13929ca8e16bbf1d9e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,5 +24,6 @@ httpxx*
 neurolots*
 nsol*
 vmmlib*
+SimIL*
 
 nlrender/Shaders.h
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d7b3c5fcd72dcfd1bd4ecf008668fd90a73c993a..5b5042850394f12cdd0e666a4b9d85563d598d97 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -10,7 +10,7 @@ Ubuntu-OptionalDeps-master:
   - export DOCKER_REPO="gitlabci@vg-lab.es:apps"
   - export CMAKE_EXTRA_TARGETS="install"
   - export BUILD_OPTIONALS_SUBPROJECTS=1
-  - export CMAKE_EXTRA_ARGS="-DCLONE_SUBPROJECTS=ON -DNEUROTESSMESH_OPTIONALS_AS_REQUIRED=ON"
+  - export CMAKE_EXTRA_ARGS="-DCLONE_SUBPROJECTS=ON -DNEUROTESSMESH_OPTIONALS_AS_REQUIRED=ON -DSIMIL_BRION_ENABLED=ON"
   - export BUILD_GENERATOR="Ninja"
   - bash .gitlab-ci.sh
  only:
@@ -24,7 +24,7 @@ Ubuntu-OptionalDeps:
   - module load Qt-5.15.2
   - export CMAKE_EXTRA_TARGETS="install"
   - export BUILD_OPTIONALS_SUBPROJECTS=1
-  - export CMAKE_EXTRA_ARGS="-DCLONE_SUBPROJECTS=ON -DNEUROTESSMESH_OPTIONALS_AS_REQUIRED=ON"
+  - export CMAKE_EXTRA_ARGS="-DCLONE_SUBPROJECTS=ON -DNEUROTESSMESH_OPTIONALS_AS_REQUIRED=ON -DSIMIL_BRION_ENABLED=ON"
   - export BUILD_GENERATOR="Ninja"
   - bash .gitlab-ci.sh
  except:
diff --git a/.gitsubprojects b/.gitsubprojects
index bed78cb7920717f337edb4af5e286ba99779cfb7..d2c6037390be2097ffc268e75b8f8236daf9ab93 100644
--- a/.gitsubprojects
+++ b/.gitsubprojects
@@ -1,8 +1,9 @@
 #-*- mode: cmake -*-
-# git_subproject(Brion https://github.com/BlueBrain/Brion.git f74dcc5)
-# git_subproject(ZeroEQ https://github.com/HBPVis/ZeroEQ.git 1e66ee3)
-# git_subproject(Lexis https://github.com/HBPVis/Lexis.git 617eedb)
-# git_subproject(gmrvlex git@gitlab.gmrv.es:nsviz/gmrvlex.git c20b194)
-git_subproject(neurolots https://github.com/gmrvvis/neurolots.git fcab672a)
+#git_subproject(Brion https://github.com/BlueBrain/Brion.git f74dcc5)
+#git_subproject(ZeroEQ https://github.com/HBPVis/ZeroEQ.git 1e66ee3)
+#git_subproject(Lexis https://github.com/HBPVis/Lexis.git 617eedb)
+#git_subproject(gmrvlex git@gitlab.gmrv.es:nsviz/gmrvlex.git c20b194)
+git_subproject(neurolots https://github.com/gmrvvis/neurolots.git f8ea6d1e)
 git_subproject(ReTo https://github.com/gmrvvis/ReTo.git 211c49a)
 git_subproject(acuterecorder https://github.com/vg-lab/AcuteRecorder.git 0b84c2b1)
+#git_subproject( SimIL https://github.com/gmrvvis/SimIL.git 1921f818 )
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0c4887d96364296adce936972ee76b40192a9889..6869902bec97188a281e30291ed1a68e531a89f4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,7 @@
 #
 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
-project(NeuroTessMesh VERSION 0.3.2)
+project(NeuroTessMesh VERSION 0.4.0)
 set(NeuroTessMesh_VERSION_ABI 1)
 
 # Disable in source building
@@ -55,10 +55,17 @@ common_find_package(ZeroEQ ${NEUROTESSMESH_OPTS_FIND_ARGS})
 common_find_package(gmrvlex ${NEUROTESSMESH_OPTS_FIND_ARGS})
 common_find_package(GLUT SYSTEM)
 common_find_package(Boost COMPONENTS system filesystem SYSTEM)
-common_find_package( acuterecorder REQUIRED )
+common_find_package(acuterecorder REQUIRED )
 
 list(APPEND NEUROTESSMESH_DEPENDENT_LIBRARIES Qt5Core Qt5Widget Qt5OpenGL GLEW neurolots acuterecorder)
 
+if(NEUROTESSMESH_OPTIONALS_AS_REQUIRED)
+  common_find_package(Brion REQUIRED)
+  common_find_package(SimIL REQUIRED)
+  add_compile_definitions(SIMIL_USE_BRION)
+  list( APPEND NEUROTESSMESH_DEPENDENT_LIBRARIES SimIL QSimIL Brion Brain)
+endif()
+
 if ( ZEROEQ_FOUND )
   common_find_package(Threads REQUIRED)
   list( APPEND NEUROTESSMESH_DEPENDENT_LIBRARIES ZeroEQ )
@@ -78,3 +85,4 @@ if (GLUT_FOUND AND BOOST_FOUND)
 endif( )
 include(CPackConfig)
 include(DoxygenRule)
+
diff --git a/neurotessmesh/CMakeLists.txt b/neurotessmesh/CMakeLists.txt
index 9fbfdb0435b01561876d00d182b0f46fac7ead53..289f1a5a5d44e5ad7157238a8f57e76bdf04de9c 100644
--- a/neurotessmesh/CMakeLists.txt
+++ b/neurotessmesh/CMakeLists.txt
@@ -22,11 +22,13 @@ set( NEUROTESSMESH_SOURCES
   ColorSelectionWidget.cpp
   CMakeSetup.rc
   Scene.cpp
+  LoaderThread.cpp
   )
 
 set( NEUROTESSMESH_HEADERS
   ${PROJECT_BINARY_DIR}/include/neurotessmesh/version.h
   Scene.h
+  LoaderThread.h
   )
 
 set(NEUROTESSMESH_MOC_HEADERS
@@ -48,7 +50,10 @@ set( NEUROTESSMESH_LINK_LIBRARIES
   nlrender
   acuterecorder
   )
-
+  
+if (NEUROTESSMESH_OPTIONALS_AS_REQUIRED)
+  list( APPEND NEUROTESSMESH_LINK_LIBRARIES SimIL QSimIL Brion Brain)
+endif()
 
 if ( ZEROEQ_FOUND )
   list( APPEND NEUROTESSMESH_LINK_LIBRARIES ZeroEQ )
diff --git a/neurotessmesh/LoaderThread.cpp b/neurotessmesh/LoaderThread.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c65474680fa31675a97703daab7ad786839fd0e9
--- /dev/null
+++ b/neurotessmesh/LoaderThread.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2022 VG-Lab/URJC.
+ *
+ * Authors: Felix de las Pozas Alvarez <felix.delaspozas@urjc.es>
+ *
+ * This file is part of SimIL <https://github.com/vg-lab/SimIL>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3.0 as published
+ * by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include "LoaderThread.h"
+
+// deps
+#include <nsol/nsol.h>
+#ifdef NEUROTESSMESH_USE_SIMIL
+  #include <simil/simil.h>
+#endif
+
+// Qt
+#include <QString>
+#include <QFileInfo>
+#include <QVBoxLayout>
+#include <QProgressBar>
+#include <QIcon>
+
+using namespace neurotessmesh;
+
+LoaderThread::LoaderThread(const std::string &arg1, const std::string &arg2,
+                           const LoaderThread::DataFileType type)
+: QThread()
+, m_fileName{arg1}
+, m_target{arg2}
+, m_type{type}
+, m_dataset{nullptr}
+, m_player{nullptr}
+{
+}
+
+void LoaderThread::run()
+{
+  try
+  {
+    m_dataset = new nsol::DataSet();
+    QFileInfo fi(QString::fromStdString(m_fileName));
+    emit progress(QString("Loading %1").arg(fi.fileName()), 10);
+
+    switch(m_type)
+    {
+    case DataFileType::BlueConfig:
+#ifdef NSOL_USE_BRION
+
+      emit progress(tr("Loading Hierarchy"), 25);
+
+      m_dataset->loadBlueConfigHierarchy< nsol::Node,
+                                          nsol::NeuronMorphologySection,
+                                          nsol::Dendrite,
+                                          nsol::Axon,
+                                          nsol::Soma,
+                                          nsol::NeuronMorphology,
+                                          nsol::Neuron,
+                                          nsol::MiniColumn,
+                                          nsol::Column >( m_fileName, m_target );
+
+      emit progress(tr("Loading Morphologies"), 50);
+
+      m_dataset->loadAllMorphologies< nsol::Node,
+                                      nsol::NeuronMorphologySection,
+                                      nsol::Dendrite,
+                                      nsol::Axon,
+                                      nsol::Soma,
+                                      nsol::NeuronMorphology,
+                                      nsol::Neuron,
+                                      nsol::MiniColumn,
+                                      nsol::Column >( );
+
+      emit progress(tr("Loading Spikes"), 75);
+#ifdef NEUROTESSMESH_USE_SIMIL
+      { // load the spikes data with SimIL, only for blueconfig.
+        auto spikesData  = new simil::SpikeData(m_fileName, simil::TDataType::TBlueConfig, m_target);
+        spikesData->reduceDataToGIDS();
+
+        m_player = new simil::SpikesPlayer( );
+        m_player->LoadData( spikesData );
+      }
+#endif
+#else
+      std::cerr << "Error: Brion support not built-in" << std::endl;
+#endif
+      break;
+
+    case DataFileType::SWC:
+      emit progress(tr("Loading Neuron"), 50);
+      m_dataset->loadNeuronFromFile< nsol::Node,
+                                     nsol::NeuronMorphologySection,
+                                     nsol::Dendrite,
+                                     nsol::Axon,
+                                     nsol::Soma,
+                                     nsol::NeuronMorphology,
+                                     nsol::Neuron >( m_fileName, 1 );
+      break;
+
+    case DataFileType::NsolScene:
+      emit progress(tr("Loading Scene"), 50);
+      m_dataset->loadXmlScene< nsol::Node,
+                               nsol::NeuronMorphologySection,
+                               nsol::Dendrite,
+                               nsol::Axon,
+                               nsol::Soma,
+                               nsol::NeuronMorphology,
+                               nsol::Neuron >( m_fileName );
+      break;
+
+    default:
+      throw std::runtime_error( "Data file type not supported" );
+    }
+
+    emit progress("Generating Meshes", 100);
+
+  }
+  catch(const std::exception &e)
+  {
+    if(m_dataset) delete m_dataset;
+    m_errors = QString::fromStdString(e.what());
+  }
+}
+
+LoadingDialog::LoadingDialog( QWidget* p )
+  : QDialog( p , Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint )
+{
+  setWindowIcon(QIcon( ":/icons/rsc/neurotessmesh.png" ));
+
+  auto layout = new QVBoxLayout( );
+  m_progress = new QProgressBar( this );
+  m_progress->setMinimumWidth( 590 );
+  m_progress->setValue(0);
+  m_progress->setFormat("");
+  layout->addWidget( m_progress , 1 , Qt::AlignHCenter | Qt::AlignVCenter );
+  layout->setMargin( 4 );
+  setLayout( layout );
+
+  setSizePolicy( QSizePolicy::MinimumExpanding ,
+                 QSizePolicy::MinimumExpanding );
+  setFixedSize( 600 , sizeHint( ).height( ));
+}
+
+void LoadingDialog::progress( const QString& message , const unsigned int value )
+{
+  m_progress->setValue( value );
+
+  if ( !message.isEmpty( ))
+    m_progress->setFormat( tr( "%1 - %p%" ).arg( message ));
+  else
+    m_progress->setFormat("%p%");
+}
+
+void LoadingDialog::closeDialog( )
+{
+  close( );
+  deleteLater( );
+}
diff --git a/neurotessmesh/LoaderThread.h b/neurotessmesh/LoaderThread.h
new file mode 100644
index 0000000000000000000000000000000000000000..153772e8032ffa929aa9fc1ba9c4760468697378
--- /dev/null
+++ b/neurotessmesh/LoaderThread.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2022 VG-Lab/URJC.
+ *
+ * Authors: Felix de las Pozas Alvarez <felix.delaspozas@urjc.es>
+ *
+ * This file is part of SimIL <https://github.com/vg-lab/SimIL>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3.0 as published
+ * by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef NEUROTESSMESH_LOADERTHREAD_H_
+#define NEUROTESSMESH_LOADERTHREAD_H_
+
+// Qt
+#include <QThread>
+#include <QDialog>
+
+class QString;
+class QProgressBar;
+
+namespace nsol
+{
+  class DataSet;
+}
+
+namespace simil
+{
+  class SpikesPlayer;
+}
+
+namespace neurotessmesh
+{
+  /** \class LoaderThread
+   * \brief Loads the dataset data in a thread.
+   *
+   */
+  class LoaderThread
+  : public QThread
+  {
+      Q_OBJECT
+    public:
+      enum class DataFileType
+      { BlueConfig, SWC, NsolScene };
+
+      /** \brief LoaderThread class constructor.
+       * \param[in] arg1 Dataset filename.
+       * \param[in] arg1 Blueconfig target.
+       * \param[in] type Dataset type.
+       *
+       */
+      explicit LoaderThread(const std::string &arg1, const std::string &arg2,
+                            const DataFileType type);
+
+      /** \brief LoaderThread class virtual destructor.
+       *
+       */
+      virtual ~LoaderThread()
+      {};
+
+      /** \brief Returns the dataset.
+       *
+       */
+      nsol::DataSet *getDataset() const
+      { return m_dataset; }
+
+      /** \brief Returns the spikes player.
+       *
+       */
+      simil::SpikesPlayer *getPlayer() const
+      { return m_player; }
+
+      virtual void run();
+
+      /** \brief Returns the error description or empty if none.
+       *
+       */
+      QString errors() const
+      { return m_errors; }
+
+    signals:
+      void progress(const QString &text, const unsigned int value);
+
+    private:
+      const std::string  m_fileName; /** name of file to load. */
+      const std::string  m_target;   /** blueconfig target.    */
+      const DataFileType m_type;     /** type of file to load. */
+
+      nsol::DataSet       *m_dataset; /** nsol dataset with data.      */
+      simil::SpikesPlayer *m_player;  /** spikes data or null if none. */
+
+      QString m_errors;
+  };
+
+  class LoadingDialog
+    : public QDialog
+  {
+      Q_OBJECT
+    public:
+      /** \brief LoadingDialog class constructor.
+       * \param[in] p Raw pointer of the widget parent of this one.
+       * \param[in] f QDialog flags.
+       *
+       */
+      explicit LoadingDialog( QWidget* p = nullptr );
+
+      /** \brief LoadingDialog class virtual destructor.
+       *
+       */
+      virtual ~LoadingDialog( )
+      { };
+
+    public slots:
+
+      /** \brief Updates the dialog with the message and progress value
+       * \param[in] message Progress message.
+       * \param[in] value Progress value in [0,100].
+       *
+       */
+      void progress( const QString& message , const unsigned int value );
+
+      /** \brief Closes and deletes the dialog.
+       *
+       */
+      void closeDialog( );
+
+    private:
+      QProgressBar* m_progress; /** progress bar. */
+  };
+
+}
+#endif /* NEUROTESSMESH_LOADERTHREAD_H_ */
diff --git a/neurotessmesh/MainWindow.cpp b/neurotessmesh/MainWindow.cpp
index 1d9461e99dc85c9144947494ad2e32162c52f669..06c0402cef85ac8ffdc1b0de1d394a62e8107eaa 100644
--- a/neurotessmesh/MainWindow.cpp
+++ b/neurotessmesh/MainWindow.cpp
@@ -10,8 +10,11 @@
 
 
 #include "MainWindow.h"
+#include "LoaderThread.h"
 #include <neurotessmesh/version.h>
 #include <nsol/nsol.h>
+#include <neurotessmesh/Scene.h>
+
 #ifdef NEUROLOTS_USE_GMRVZEQ
 #include <gmrvzeq/version.h>
 #endif
@@ -20,6 +23,10 @@
 #endif
 
 #include <acuterecorder/acuterecorder.h>
+#ifdef NEUROTESSMESH_USE_SIMIL
+  #include <qsimil/qsimil.h>
+  #include <simil/simil.h>
+#endif
 
 #include <QFileDialog>
 #include <QInputDialog>
@@ -33,21 +40,24 @@
 
 constexpr const char* POSITION_KEY = "positionData";
 
-MainWindow::MainWindow( QWidget* parent_, bool updateOnIdle_ )
+MainWindow::MainWindow( QWidget* parent_ , bool updateOnIdle_ )
   : QMainWindow( parent_ )
   , _lastOpenedFileName( "" )
   , _ui( new Ui::MainWindow )
   , _openGLWidget( nullptr )
+  , _scene( nullptr )
   , _recorder( nullptr )
+  , m_dataLoader{ nullptr }
 {
   _ui->setupUi( this );
 
-  auto recorderAction = RecorderUtils::recorderAction();
-  _ui->menuTools->insertAction(_ui->menuTools->actions().first(), recorderAction);
-  _ui->toolBar->addAction(recorderAction);
+  auto recorderAction = RecorderUtils::recorderAction( );
+  _ui->menuTools->insertAction( _ui->menuTools->actions( ).first( ) ,
+                                recorderAction );
+  _ui->toolBar->addAction( recorderAction );
 
-  connect(recorderAction, SIGNAL(triggered(bool)),
-          this,           SLOT(openRecorder()));
+  connect( recorderAction , SIGNAL( triggered( bool )) ,
+           this , SLOT( openRecorder( )));
 
   _ui->actionUpdateOnIdle->setChecked( updateOnIdle_ );
   _ui->actionShowFPSOnIdleUpdate->setChecked( false );
@@ -55,8 +65,7 @@ MainWindow::MainWindow( QWidget* parent_, bool updateOnIdle_ )
 #ifdef NSOL_USE_BRION
   _ui->actionOpenBlueConfig->setEnabled( true );
 #else
-  //_ui->actionOpenBlueConfig->setEnabled( false );
-  _ui->actionOpenBlueConfig->setVisible(false);
+  _ui->actionOpenBlueConfig->setEnabled( false );
 #endif
 
 #ifdef NSOL_USE_QT5CORE
@@ -65,34 +74,35 @@ MainWindow::MainWindow( QWidget* parent_, bool updateOnIdle_ )
   _ui->actionOpenXMLScene->setEnabled( false );
 #endif
 
-  connect( _ui->actionQuit, SIGNAL( triggered( )),
-           QApplication::instance(), SLOT( quit( )));
+  connect( _ui->actionQuit , SIGNAL( triggered( )) ,
+           QApplication::instance( ) , SLOT( quit( )));
 
-  connect( _ui->actionAbout, SIGNAL(triggered( )),
-           this, SLOT( showAbout( )));
+  connect( _ui->actionAbout , SIGNAL( triggered( )) ,
+           this , SLOT( showAbout( )));
+
+  _openGLWidget = new OpenGLWidget( );
+  this->setCentralWidget( _openGLWidget );
+  _openGLWidget->setMinimumSize( QSize( 100 , 100 ));
 
   _initExtractionDock( );
   _initConfigurationDock( );
   _initRenderOptionsDock( );
+  _initPlayerDock( );
 
-  _openGLWidget = new OpenGLWidget();
-  this->setCentralWidget( _openGLWidget );
-  _openGLWidget->setMinimumSize( QSize( 100, 100 ));
-
-  if( _openGLWidget->format( ).version( ).first < 4 )
+  if ( _openGLWidget->format( ).version( ).first < 4 )
   {
     std::cerr << "This application requires at least OpenGL 4.0" << std::endl;
     exit( -1 );
   }
 
-  auto positionsMenu = new QMenu();
-  positionsMenu->setTitle("Camera positions");
-  _ui->actionCamera_Positions->setMenu(positionsMenu);
+  auto positionsMenu = new QMenu( );
+  positionsMenu->setTitle( "Camera positions" );
+  _ui->actionCamera_Positions->setMenu( positionsMenu );
 }
 
-MainWindow::~MainWindow( void )
+MainWindow::~MainWindow( )
 {
-    delete _ui;
+  delete _ui;
 }
 
 void MainWindow::init( const std::string& zeqSession_ )
@@ -103,135 +113,126 @@ void MainWindow::init( const std::string& zeqSession_ )
   if ( !zeqSession_.empty( ))
     _openGLWidget->setZeqSession( zeqSession_ );
 
-  connect( _ui->actionHome, SIGNAL( triggered( )),
-           this, SLOT( home( )));
+  connect( _ui->actionHome , SIGNAL( triggered( )) ,
+           this , SLOT( home( )));
 
-  connect( _ui->actionUpdateOnIdle, SIGNAL( triggered( )),
-           _openGLWidget, SLOT( toggleUpdateOnIdle( )));
+  connect( _ui->actionUpdateOnIdle , SIGNAL( triggered( )) ,
+           _openGLWidget , SLOT( toggleUpdateOnIdle( )));
 
-  connect( _ui->actionShowFPSOnIdleUpdate, SIGNAL( triggered( )),
-           _openGLWidget, SLOT( toggleShowFPS( )));
+  connect( _ui->actionShowFPSOnIdleUpdate , SIGNAL( triggered( )) ,
+           _openGLWidget , SLOT( toggleShowFPS( )));
 
-  connect( _ui->actionWireframe, SIGNAL( triggered( )),
-           _openGLWidget, SLOT( toggleWireframe( )));
+  connect( _ui->actionWireframe , SIGNAL( triggered( )) ,
+           _openGLWidget , SLOT( toggleWireframe( )));
 
-  connect( _ui->actionOpenBlueConfig, SIGNAL( triggered( )),
-           this, SLOT( openBlueConfigThroughDialog( )));
+  connect( _ui->actionOpenBlueConfig , SIGNAL( triggered( )) ,
+           this , SLOT( openBlueConfigThroughDialog( )));
 
-  connect( _ui->actionOpenXMLScene, SIGNAL( triggered( )),
-           this, SLOT( openXMLSceneThroughDialog( )));
+  connect( _ui->actionOpenXMLScene , SIGNAL( triggered( )) ,
+           this , SLOT( openXMLSceneThroughDialog( )));
 
-  connect( _ui->actionOpenSWCFile, SIGNAL( triggered( )),
-           this, SLOT( openSWCFileThroughDialog( )));
+  connect( _ui->actionOpenSWCFile , SIGNAL( triggered( )) ,
+           this , SLOT( openSWCFileThroughDialog( )));
 
-  connect( _radiusSlider, SIGNAL( valueChanged( int )),
-           this, SLOT( onActionGenerate( int )));
+  connect( _radiusSlider , SIGNAL( valueChanged( int )) ,
+           this , SLOT( onActionGenerate( int )));
 
-  connect( _extractButton, SIGNAL( clicked( )),
-           _openGLWidget, SLOT( extractEditNeuronMesh( )));
+  connect( _extractButton , SIGNAL( clicked( )) ,
+           _openGLWidget , SLOT( extractEditNeuronMesh( )));
 
-  connect( _lotSlider, SIGNAL( valueChanged( int )),
-           _openGLWidget, SLOT( onLotValueChanged( int )));
+  connect( _lotSlider , SIGNAL( valueChanged( int )) ,
+           _openGLWidget , SLOT( onLotValueChanged( int )));
   _lotSlider->valueChanged( _lotSlider->value( ));
 
-  connect( _distanceSlider, SIGNAL( valueChanged( int )),
-           _openGLWidget, SLOT( onDistanceValueChanged( int )));
+  connect( _distanceSlider , SIGNAL( valueChanged( int )) ,
+           _openGLWidget , SLOT( onDistanceValueChanged( int )));
   _distanceSlider->valueChanged( _distanceSlider->value( ));
 
-  connect( _radioHomogeneous, SIGNAL( clicked( )),
-           _openGLWidget, SLOT( onHomogeneousClicked( )));
+  connect( _radioHomogeneous , SIGNAL( clicked( )) ,
+           _openGLWidget , SLOT( onHomogeneousClicked( )));
 
-  connect( _radioLinear, SIGNAL( clicked( )),
-           _openGLWidget, SLOT( onLinearClicked( )));
+  connect( _radioLinear , SIGNAL( clicked( )) ,
+           _openGLWidget , SLOT( onLinearClicked( )));
   _radioLinear->clicked( );
 
-  connect( _backGroundColor, SIGNAL( colorChanged( QColor )),
-           _openGLWidget, SLOT( changeClearColor( QColor )));
-  _backGroundColor->color( QColor( 255, 255, 255 ));
+  connect( _neuronRender , SIGNAL( currentIndexChanged( int )) ,
+           _openGLWidget , SLOT( changeNeuronPiece( int )));
+  _neuronRender->currentIndexChanged( 1 );
 
-  connect( _neuronColor, SIGNAL( colorChanged( QColor )),
-           _openGLWidget, SLOT( changeNeuronColor( QColor )));
-  _neuronColor->color( QColor( 0, 120, 250 ));
+  connect( _selectedNeuronRender , SIGNAL( currentIndexChanged( int )) ,
+           _openGLWidget , SLOT( changeSelectedNeuronPiece( int )));
+  _selectedNeuronRender->currentIndexChanged( 0 );
 
-  connect( _selectedNeuronColor, SIGNAL( colorChanged( QColor )),
-           _openGLWidget, SLOT( changeSelectedNeuronColor( QColor )));
-  _selectedNeuronColor->color( QColor( 250, 120, 0 ));
+  connect( _ui->actionLoad_camera_positions , SIGNAL( triggered( bool )) ,
+           this ,
+           SLOT( loadCameraPositions( )));
 
-  connect( _neuronRender, SIGNAL( currentIndexChanged( int )),
-           _openGLWidget, SLOT( changeNeuronPiece( int )));
-  _neuronRender->currentIndexChanged( 1 );
+  connect( _ui->actionSave_camera_positions , SIGNAL( triggered( bool )) ,
+           this ,
+           SLOT( saveCameraPositions( )));
 
-  connect( _selectedNeuronRender, SIGNAL( currentIndexChanged( int )),
-           _openGLWidget, SLOT( changeSelectedNeuronPiece( int )));
-  _selectedNeuronRender->currentIndexChanged( 0 );
+  connect( _ui->actionAdd_camera_position , SIGNAL( triggered( bool )) , this ,
+           SLOT( addCameraPosition( )));
 
-  connect(_ui->actionLoad_camera_positions, SIGNAL(triggered(bool)), this,
-            SLOT(loadCameraPositions()));
+  connect( _ui->actionRemove_camera_position , SIGNAL( triggered( bool )) ,
+           this ,
+           SLOT( removeCameraPosition( )));
 
-  connect(_ui->actionSave_camera_positions, SIGNAL(triggered(bool)), this,
-            SLOT(saveCameraPositions()));
+  connect( _backGroundColor , SIGNAL( colorChanged( QColor )) ,
+           _openGLWidget , SLOT( changeClearColor( QColor )));
 
-  connect(_ui->actionAdd_camera_position, SIGNAL(triggered(bool)), this,
-            SLOT(addCameraPosition()));
+  connect( _neuronColor , SIGNAL( colorChanged( QColor )) ,
+           _openGLWidget , SLOT( changeNeuronColor( QColor )));
 
-  connect(_ui->actionRemove_camera_position, SIGNAL(triggered(bool)), this,
-            SLOT(removeCameraPosition()));
+  connect( _selectedNeuronColor , SIGNAL( colorChanged( QColor )) ,
+           _openGLWidget , SLOT( changeSelectedNeuronColor( QColor )));
 }
 
-void MainWindow::showStatusBarMessage ( const QString& message )
+void MainWindow::showStatusBarMessage( const QString& message )
 {
   _ui->statusbar->showMessage( message );
 }
 
-void MainWindow::openBlueConfig( const std::string& fileName,
+void MainWindow::openBlueConfig( const std::string& fileName ,
                                  const std::string& targetLabel )
 {
-  _openGLWidget->loadData( fileName,
-                           neurotessmesh::Scene::TDataFileType::BlueConfig,
-                           targetLabel );
-  updateNeuronList( );
-  _openGLWidget->changeNeuronPiece(_neuronRender->currentIndex());
-  _openGLWidget->changeSelectedNeuronPiece(_selectedNeuronRender->currentIndex());
+  loadData( fileName , targetLabel ,
+            neurotessmesh::LoaderThread::DataFileType::BlueConfig );
 }
 
 void MainWindow::openXMLScene( const std::string& fileName )
 {
-  _openGLWidget->loadData( fileName,
-                           neurotessmesh::Scene::TDataFileType::NsolScene );
-  updateNeuronList( );
-  _openGLWidget->changeNeuronPiece(_neuronRender->currentIndex());
-  _openGLWidget->changeSelectedNeuronPiece(_selectedNeuronRender->currentIndex());
+  loadData( fileName , std::string( ) ,
+            neurotessmesh::LoaderThread::DataFileType::NsolScene );
 }
 
 void MainWindow::openSWCFile( const std::string& fileName )
 {
-  _openGLWidget->loadData( fileName,
-                           neurotessmesh::Scene::TDataFileType::SWC );
-  updateNeuronList( );
-  _openGLWidget->changeNeuronPiece(_neuronRender->currentIndex());
-  _openGLWidget->changeSelectedNeuronPiece(_selectedNeuronRender->currentIndex());
+  loadData( fileName , std::string( ) ,
+            neurotessmesh::LoaderThread::DataFileType::SWC );
 }
 
-void MainWindow::updateNeuronList( void )
+void MainWindow::updateNeuronList( )
 {
   _neuronList->clear( );
-  const std::vector< unsigned int >& ids = _openGLWidget->neuronIdList( );
+  const std::vector< unsigned int >& ids = _scene->neuronIndices( );
 
-  for( const auto& id: ids )
+  for ( const auto& id: ids )
   {
     _neuronList->addItem( QString::number( id ));
   }
 }
 
-void MainWindow::home( void )
+void MainWindow::home( )
 {
+  _scene->home( );
   _openGLWidget->home( );
   _generateNeuritesLayout( );
   _extractButton->setEnabled( false );
   _somaGroup->hide( );
 }
 
-void MainWindow::openBlueConfigThroughDialog( void )
+void MainWindow::openBlueConfigThroughDialog( )
 {
 #ifdef NSOL_USE_BRION
 
@@ -258,12 +259,12 @@ void MainWindow::openBlueConfigThroughDialog( void )
 #endif
 }
 
-void MainWindow::openXMLSceneThroughDialog( void )
+void MainWindow::openXMLSceneThroughDialog( )
 {
 #ifdef NSOL_USE_QT5CORE
   QString path = QFileDialog::getOpenFileName(
-    this, tr( "Open XML Scene" ), _lastOpenedFileName,
-    tr( "XML ( *.xml);; All files (*)" ), nullptr,
+    this , tr( "Open XML Scene" ) , _lastOpenedFileName ,
+    tr( "XML ( *.xml);; All files (*)" ) , nullptr ,
     QFileDialog::DontUseNativeDialog );
 
   if ( path != QString( "" ))
@@ -275,11 +276,11 @@ void MainWindow::openXMLSceneThroughDialog( void )
 
 }
 
-void MainWindow::openSWCFileThroughDialog( void )
+void MainWindow::openSWCFileThroughDialog( )
 {
   QString path = QFileDialog::getOpenFileName(
-    this, tr( "Open Swc File" ), _lastOpenedFileName,
-    tr( "swc ( *.swc);; All files (*)" ), nullptr,
+    this , tr( "Open Swc File" ) , _lastOpenedFileName ,
+    tr( "swc ( *.swc);; All files (*)" ) , nullptr ,
     QFileDialog::DontUseNativeDialog );
 
   if ( path != QString( "" ))
@@ -289,11 +290,11 @@ void MainWindow::openSWCFileThroughDialog( void )
   }
 }
 
-void MainWindow::showAbout( void )
+void MainWindow::showAbout( )
 {
 
   QMessageBox::about(
-    this, tr( "About " ) + tr( "NeuroTessMesh" ),
+    this , tr( "About " ) + tr( "NeuroTessMesh" ) ,
     tr( "<p><BIG><b>" ) + tr( "NeuroTessMesh" ) + tr( "</b></BIG><br><br>" ) +
     tr( "version " ) +
     tr( neurotessmesh::Version::getString( ).c_str( )) +
@@ -301,73 +302,73 @@ void MainWindow::showAbout( void )
     tr( std::to_string( neurotessmesh::Version::getRevision( )).c_str( )) +
     tr( ")" ) +
     tr( "<br><br>Using: " ) +
-    tr( "<ul>") +
+    tr( "<ul>" ) +
     tr( "<li>nsol " ) +
     tr( nsol::Version::getString( ).c_str( )) +
     tr( " (" ) +
     tr( std::to_string( nsol::Version::getRevision( )).c_str( )) +
     tr( ")</li> " ) +
-#ifdef NSOL_USE_BRION
+    #ifdef NSOL_USE_BRION
     tr( "<li>Brion " ) +
     tr( brion::Version::getString( ).c_str( )) +
     tr( " (" ) +
     tr( std::to_string( brion::Version::getRevision( )).c_str( )) +
     tr( ")" ) +
     tr ( "</li> " ) +
-#endif
-#ifdef NEUROLOTS_USE_ZEROEQ
+    #endif
+    #ifdef NEUROLOTS_USE_ZEROEQ
     tr( "<li>ZEQ " ) +
     tr( zeroeq::Version::getString( ).c_str( )) +
     tr( " (" ) +
     tr( std::to_string( zeroeq::Version::getRevision( )).c_str( )) +
     tr( ")" ) +
     tr ( "</li> " ) +
-#endif
-#ifdef NEUROLOTS_USE_GMRVLEX
+    #endif
+    #ifdef NEUROLOTS_USE_GMRVLEX
     tr( "<li>gmrvzeq " ) +
     tr( gmrvlex::Version::getString( ).c_str( )) +
     tr( " (" ) +
     tr( std::to_string( gmrvlex::Version::getRevision( )).c_str( )) +
     tr( ")" ) +
     tr ( "</li> " ) +
-#endif
-#ifdef NEUROLOTS_USE_DEFLECT
+    #endif
+    #ifdef NEUROLOTS_USE_DEFLECT
     tr( "<li>Deflect " ) +
     tr( deflect::Version::getString( ).c_str( )) +
     tr( " (" ) +
     tr( std::to_string( deflect::Version::getRevision( )).c_str( )) +
     tr( ")" ) +
     tr ( "</li> " ) +
-#endif
+    #endif
     tr( "<li>AcuteRecorder " ) +
-    tr( acuterecorder::Version::getString().c_str( )) +
+    tr( acuterecorder::Version::getString( ).c_str( )) +
     tr( " (" ) +
     tr( std::to_string( acuterecorder::Version::getRevision( )).c_str( )) +
     tr( ")" ) +
-    tr ( "</li> " ) +
+    tr( "</li> " ) +
 
-    tr ( "</ul>" ) +
+    tr( "</ul>" ) +
     tr( "<br>VG-Lab - Universidad Rey Juan Carlos<br>"
-       "<a href=www.vg-lab.es>www.vg-lab.es</a><br>"
-       "<a href='mailto:dev@vg-lab.es'>dev@vg-lab.es</a><br><br>"
-       "<br>(C) 2015-2022. Universidad Rey Juan Carlos<br><br>"
-       "<img src=':/icons/rsc/logoVGLab.png' >&nbsp;&nbsp;&nbsp;&nbsp;"
-       "<img src=':/icons/rsc/logoURJC.png' ><br><br> "
-       "</p>"
-       "")
-    );
+        "<a href=www.vg-lab.es>www.vg-lab.es</a><br>"
+        "<a href='mailto:dev@vg-lab.es'>dev@vg-lab.es</a><br><br>"
+        "<br>(C) 2015-2022. Universidad Rey Juan Carlos<br><br>"
+        "<img src=':/icons/rsc/logoVGLab.png' >&nbsp;&nbsp;&nbsp;&nbsp;"
+        "<img src=':/icons/rsc/logoURJC.png' ><br><br> "
+        "</p>"
+        "" )
+  );
 }
 
-void MainWindow::openRecorder()
+void MainWindow::openRecorder( )
 {
-  auto action = qobject_cast<QAction *>(sender());
+  auto action = qobject_cast< QAction* >( sender( ));
 
   // The button stops the recorder if found.
-  if( _recorder )
+  if ( _recorder )
   {
-    if(action) action->setDisabled( true );
+    if ( action ) action->setDisabled( true );
 
-    RecorderUtils::stopAndWait(_recorder, this);
+    RecorderUtils::stopAndWait( _recorder , this );
 
     // Recorder will be deleted after finishing.
     _recorder = nullptr;
@@ -379,7 +380,7 @@ void MainWindow::openRecorder()
   params.widgetsToRecord.emplace_back( "Main Widget" , this );
   params.includeScreens = false;
 
-  if(!_ui->actionAdvancedRecorderOptions->isChecked())
+  if ( !_ui->actionAdvancedRecorderOptions->isChecked( ))
   {
     params.showWorker = false;
     params.showWidgetSourceMode = false;
@@ -389,23 +390,24 @@ void MainWindow::openRecorder()
   RecorderDialog dialog( nullptr , params , true );
   dialog.setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" ));
   dialog.setFixedSize( 800 , 600 );
-  if ( dialog.exec( ) == QDialog::Accepted)
+  if ( dialog.exec( ) == QDialog::Accepted )
   {
     _recorder = dialog.getRecorder( );
     connect( _recorder , SIGNAL( finished( )) ,
              _recorder , SLOT( deleteLater( )));
     connect( _recorder , SIGNAL( finished( )) ,
              this , SLOT( finishRecording( )));
-    if(action) action->setChecked( true );
-  } else
+    if ( action ) action->setChecked( true );
+  }
+  else
   {
-    if(action) action->setChecked( false );
+    if ( action ) action->setChecked( false );
   }
 }
 
 void MainWindow::updateExtractMeshDock( void )
 {
-  if( _ui->actionEditSave->isChecked( ))
+  if ( _ui->actionEditSave->isChecked( ))
     _extractMeshDock->show( );
   else
     _extractMeshDock->close( );
@@ -413,7 +415,7 @@ void MainWindow::updateExtractMeshDock( void )
 
 void MainWindow::updateConfigurationDock( void )
 {
-  if( _ui->actionConfiguration->isChecked( ))
+  if ( _ui->actionConfiguration->isChecked( ))
     _configurationDock->show( );
   else
     _configurationDock->close( );
@@ -421,384 +423,434 @@ void MainWindow::updateConfigurationDock( void )
 
 void MainWindow::updateRenderOptionsDock( void )
 {
-  if( _ui->actionRenderOptions->isChecked( ))
+  if ( _ui->actionRenderOptions->isChecked( ))
     _renderOptionsDock->show( );
   else
     _renderOptionsDock->close( );
 }
 
+void MainWindow::updatePlayerOptionsDock( )
+{
+#ifdef NEUROTESSMESH_USE_SIMIL
+  auto playerWidget = qobject_cast< qsimil::QSimControlWidget* >(
+    _playerDock->widget( ));
+  bool enabled = false;
+  if ( playerWidget )
+  {
+    auto player = dynamic_cast<simil::SpikesPlayer*>(playerWidget->getSimulationPlayer( ));
+    enabled = player && !player->spikes( ).empty( );
+  }
+
+  _playerDock->setEnabled( enabled );
+  if ( _ui->actionSimulation_player_options->isChecked( ))
+    _playerDock->show( );
+  else
+    _playerDock->hide( );
+#else
+  _ui->actionSimulation_player_options->setEnabled(false);
+  _playerDock->setVisible(false);
+#endif
+}
 
 void MainWindow::onListClicked( QListWidgetItem* item )
 {
   int id = item->text( ).toInt( );
-  _openGLWidget->neuronToEdit( id );
+  _scene->setNeuronToEdit( id );
+  _openGLWidget->update( );
   _generateNeuritesLayout( );
   _extractButton->setEnabled( true );
   _somaGroup->show( );
-
 }
 
 void MainWindow::onActionGenerate( int /*value_*/ )
 {
-  float alphaRadius = ( float )_radiusSlider->value( ) / 100.0f;
+  float alphaRadius = static_cast<float>(_radiusSlider->value( )) / 100.0f;
   std::vector< float > alphaNeurites;
 
-  for ( unsigned int i = 0; i < _neuriteSliders.size( ); i++ )
+  for ( auto& _neuriteSlider: _neuriteSliders )
   {
-    alphaNeurites.push_back(( float ) _neuriteSliders[i]->value( ) / 100.0f );
+    alphaNeurites.push_back(
+      static_cast<float>(_neuriteSlider->value( )) / 100.0f );
   }
 
-  _openGLWidget->regenerateNeuronToEdit( alphaRadius, alphaNeurites );
+
+  _openGLWidget->makeCurrent( );
+  _openGLWidget->update( );
+  _scene->regenerateEditNeuronMesh( alphaRadius , alphaNeurites );
 }
 
 void MainWindow::finishRecording( )
 {
-  auto actionRecorder = _ui->menuTools->actions().first();
-  if(actionRecorder)
+  auto actionRecorder = _ui->menuTools->actions( ).first( );
+  if ( actionRecorder )
   {
     actionRecorder->setEnabled( true );
     actionRecorder->setChecked( false );
   }
 }
 
-void MainWindow::loadCameraPositions()
+void MainWindow::loadCameraPositions( )
 {
   const QString title = "Load camera positions";
 
-  auto actions = _ui->actionCamera_Positions->menu()->actions();
-  const auto numActions = actions.size();
-  if(numActions > 0)
+  auto actions = _ui->actionCamera_Positions->menu( )->actions( );
+  const auto numActions = actions.size( );
+  if ( numActions > 0 )
   {
-    const auto warnText = tr("Loading new camera positions will remove"
-                              " %1 existing position%2. Are you sure?").arg(numActions).arg(numActions > 1 ? "s":"");
-    if(QMessageBox::Ok != QMessageBox::warning(this, title, warnText, QMessageBox::Cancel|QMessageBox::Ok))
+    const auto warnText = tr( "Loading new camera positions will remove"
+                              " %1 existing position%2. Are you sure?" ).arg(
+      numActions ).arg(
+      numActions > 1 ? "s" : "" );
+    if ( QMessageBox::Ok != QMessageBox::warning( this , title , warnText ,
+                                                  QMessageBox::Cancel |
+                                                  QMessageBox::Ok ))
       return;
   }
 
   const QString nameFilter = "Camera positions (*.json)";
   QDir directory;
 
-  if(_lastOpenedFileName.isEmpty())
-    directory = QDir::home();
+  if ( _lastOpenedFileName.isEmpty( ))
+    directory = QDir::home( );
   else
-    directory = QFileInfo(_lastOpenedFileName).dir();
-
-  QFileDialog fDialog(this);
-  fDialog.setWindowIcon(QIcon(":/icons/rsc/neurotessmesh.png"));
-  fDialog.setWindowTitle(title);
-  fDialog.setAcceptMode(QFileDialog::AcceptMode::AcceptOpen);
-  fDialog.setDefaultSuffix("json");
-  fDialog.setDirectory(directory);
-  fDialog.setOption(QFileDialog::Option::DontUseNativeDialog, true);
-  fDialog.setFileMode(QFileDialog::FileMode::ExistingFile);
-  fDialog.setNameFilters(QStringList{nameFilter});
-  fDialog.setNameFilter(nameFilter);
-
-  if(fDialog.exec() != QFileDialog::Accepted)
+    directory = QFileInfo( _lastOpenedFileName ).dir( );
+
+  QFileDialog fDialog( this );
+  fDialog.setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" ));
+  fDialog.setWindowTitle( title );
+  fDialog.setAcceptMode( QFileDialog::AcceptMode::AcceptOpen );
+  fDialog.setDefaultSuffix( "json" );
+  fDialog.setDirectory( directory );
+  fDialog.setOption( QFileDialog::Option::DontUseNativeDialog , true );
+  fDialog.setFileMode( QFileDialog::FileMode::ExistingFile );
+  fDialog.setNameFilters( QStringList{ nameFilter } );
+  fDialog.setNameFilter( nameFilter );
+
+  if ( fDialog.exec( ) != QFileDialog::Accepted )
     return;
 
-  if(fDialog.selectedFiles().empty()) return;
+  if ( fDialog.selectedFiles( ).empty( )) return;
 
-  auto file = fDialog.selectedFiles().first();
+  auto file = fDialog.selectedFiles( ).first( );
 
-  QFile posFile{file};
-  if(!posFile.open(QIODevice::ReadOnly|QIODevice::Text))
+  QFile posFile{ file };
+  if ( !posFile.open( QIODevice::ReadOnly | QIODevice::Text ))
   {
-    const QString errorText = tr("Unable to open: %1").arg(file);
-    QMessageBox::critical(this, title, errorText);
+    const QString errorText = tr( "Unable to open: %1" ).arg( file );
+    QMessageBox::critical( this , title , errorText );
     return;
   }
 
-  const auto contents = posFile.readAll();
+  const auto contents = posFile.readAll( );
   QJsonParseError parserError;
 
-  const auto  jsonDoc = QJsonDocument::fromJson(contents, &parserError);
-  if(jsonDoc.isNull() || !jsonDoc.isObject())
+  const auto jsonDoc = QJsonDocument::fromJson( contents , &parserError );
+  if ( jsonDoc.isNull( ) || !jsonDoc.isObject( ))
   {
-    const auto message = tr("Couldn't read the contents of %1 or parsing error.").arg(file);
-
-    QMessageBox msgbox{this};
-    msgbox.setWindowTitle(title);
-    msgbox.setIcon(QMessageBox::Icon::Critical);
-    msgbox.setText(message);
-    msgbox.setWindowIcon(QIcon(":/icons/rsc/neurotessmesh.png"));
-    msgbox.setStandardButtons(QMessageBox::Ok);
-    msgbox.setDetailedText(parserError.errorString());
-    msgbox.exec();
+    const auto message = tr(
+      "Couldn't read the contents of %1 or parsing error." ).arg( file );
+
+    QMessageBox msgbox{ this };
+    msgbox.setWindowTitle( title );
+    msgbox.setIcon( QMessageBox::Icon::Critical );
+    msgbox.setText( message );
+    msgbox.setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" ));
+    msgbox.setStandardButtons( QMessageBox::Ok );
+    msgbox.setDetailedText( parserError.errorString( ));
+    msgbox.exec( );
     return;
   }
 
-  const auto jsonObj = jsonDoc.object();
-  if(jsonObj.isEmpty())
+  const auto jsonObj = jsonDoc.object( );
+  if ( jsonObj.isEmpty( ))
   {
-    const auto message = tr("Error parsing the contents of %1.").arg(file);
-
-    QMessageBox msgbox{this};
-    msgbox.setWindowTitle(title);
-    msgbox.setIcon(QMessageBox::Icon::Critical);
-    msgbox.setText(message);
-    msgbox.setWindowIcon(QIcon(":/icons/rsc/neurotessmesh.png"));
-    msgbox.setStandardButtons(QMessageBox::Ok);
-    msgbox.exec();
+    const auto message = tr( "Error parsing the contents of %1." ).arg( file );
+
+    QMessageBox msgbox{ this };
+    msgbox.setWindowTitle( title );
+    msgbox.setIcon( QMessageBox::Icon::Critical );
+    msgbox.setText( message );
+    msgbox.setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" ));
+    msgbox.setStandardButtons( QMessageBox::Ok );
+    msgbox.exec( );
     return;
   }
 
-  const QFileInfo currentFile{_lastOpenedFileName};
-  const QString jsonPositionsFile = jsonObj.value("filename").toString();
-  if(!jsonPositionsFile.isEmpty() && jsonPositionsFile.compare(currentFile.fileName(), Qt::CaseInsensitive) != 0)
+  const QFileInfo currentFile{ _lastOpenedFileName };
+  const QString jsonPositionsFile = jsonObj.value( "filename" ).toString( );
+  if ( !jsonPositionsFile.isEmpty( ) &&
+       jsonPositionsFile.compare( currentFile.fileName( ) ,
+                                  Qt::CaseInsensitive ) != 0 )
   {
-    const auto message = tr("This positions are from file '%1'. Current file"
-                            " is '%2'. Do you want to continue?").arg(jsonPositionsFile).arg(currentFile.fileName());
-
-    QMessageBox msgbox{this};
-    msgbox.setWindowTitle(title);
-    msgbox.setIcon(QMessageBox::Icon::Question);
-    msgbox.setText(message);
-    msgbox.setWindowIcon(QIcon(":/icons/rsc/neurotessmesh.png"));
-    msgbox.setStandardButtons(QMessageBox::Cancel|QMessageBox::Ok);
-    msgbox.setDefaultButton(QMessageBox::Ok);
-
-    if(QMessageBox::Ok != msgbox.exec())
+    const auto message = tr( "This positions are from file '%1'. Current file"
+                             " is '%2'. Do you want to continue?" )
+      .arg( jsonPositionsFile )
+      .arg( currentFile.fileName( ));
+
+    QMessageBox msgbox{ this };
+    msgbox.setWindowTitle( title );
+    msgbox.setIcon( QMessageBox::Icon::Question );
+    msgbox.setText( message );
+    msgbox.setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" ));
+    msgbox.setStandardButtons( QMessageBox::Cancel | QMessageBox::Ok );
+    msgbox.setDefaultButton( QMessageBox::Ok );
+
+    if ( QMessageBox::Ok != msgbox.exec( ))
       return;
   }
 
   // Clear existing actions before entering new ones.
-  for(auto action: actions)
+  for ( auto action: actions )
   {
-    _ui->actionCamera_Positions->menu()->removeAction(action);
+    _ui->actionCamera_Positions->menu( )->removeAction( action );
     delete action;
   }
 
-  const auto jsonPositions = jsonObj.value("positions").toArray();
+  const auto jsonPositions = jsonObj.value( "positions" ).toArray( );
 
-  auto createPosition = [this](const QJsonValue &v)
+  auto createPosition = [ this ]( const QJsonValue& v )
   {
-    const auto o = v.toObject();
+    const auto o = v.toObject( );
 
-    const auto name = o.value("name").toString();
-    const auto position = o.value("position").toString();
-    const auto radius = o.value("radius").toString();
-    const auto rotation = o.value("rotation").toString();
+    const auto name = o.value( "name" ).toString( );
+    const auto position = o.value( "position" ).toString( );
+    const auto radius = o.value( "radius" ).toString( );
+    const auto rotation = o.value( "rotation" ).toString( );
 
-    auto action = new QAction(name);
-    action->setProperty(POSITION_KEY, position + ";" + radius + ";" + rotation);
+    auto action = new QAction( name );
+    action->setProperty( POSITION_KEY ,
+                         position + ";" + radius + ";" + rotation );
 
-    connect(action, SIGNAL(triggered(bool)), this, SLOT(applyCameraPosition()));
+    connect( action , SIGNAL( triggered( bool )) ,
+             this , SLOT( applyCameraPosition( )));
 
-    _ui->actionCamera_Positions->menu()->addAction(action);
+    _ui->actionCamera_Positions->menu( )->addAction( action );
   };
-  std::for_each(jsonPositions.constBegin(), jsonPositions.constEnd(), createPosition);
+  std::for_each( jsonPositions.constBegin( ) , jsonPositions.constEnd( ) ,
+                 createPosition );
 
-  const bool positionsExist = !_ui->actionCamera_Positions->menu()->actions().isEmpty();
-  _ui->actionSave_camera_positions->setEnabled(positionsExist);
-  _ui->actionRemove_camera_position->setEnabled(positionsExist);
-  _ui->actionCamera_Positions->setEnabled(positionsExist);
+  const bool positionsExist = !_ui->actionCamera_Positions->menu( )->actions( ).isEmpty( );
+  _ui->actionSave_camera_positions->setEnabled( positionsExist );
+  _ui->actionRemove_camera_position->setEnabled( positionsExist );
+  _ui->actionCamera_Positions->setEnabled( positionsExist );
 }
 
-void MainWindow::saveCameraPositions()
+void MainWindow::saveCameraPositions( )
 {
   const QString nameFilter = "Camera positions (*.json)";
   QDir directory;
   QString filename;
 
-  if(_lastOpenedFileName.isEmpty())
+  if ( _lastOpenedFileName.isEmpty( ))
   {
-    directory = QDir::home();
+    directory = QDir::home( );
     filename = "positions.json";
   }
   else
   {
-    QFileInfo fi(_lastOpenedFileName);
-    directory = fi.dir();
-    filename = QString("%1_positions.json").arg(fi.baseName());
+    QFileInfo fi( _lastOpenedFileName );
+    directory = fi.dir( );
+    filename = QString( "%1_positions.json" ).arg( fi.baseName( ));
   }
 
-  QFileDialog fDialog(this);
-  fDialog.setWindowIcon(QIcon(":/icons/rsc/neurotessmesh.png"));
-  fDialog.setWindowTitle("Save camera positions");
-  fDialog.setAcceptMode(QFileDialog::AcceptMode::AcceptSave);
-  fDialog.setDefaultSuffix("json");
-  fDialog.selectFile(filename);
-  fDialog.setDirectory(directory);
-  fDialog.setOption(QFileDialog::Option::DontUseNativeDialog, true);
-  fDialog.setOption(QFileDialog::Option::DontConfirmOverwrite, false);
-  fDialog.setFileMode(QFileDialog::FileMode::AnyFile);
-  fDialog.setNameFilters(QStringList{nameFilter});
-  fDialog.setNameFilter(nameFilter);
-
-  if(fDialog.exec() != QFileDialog::Accepted)
+  QFileDialog fDialog( this );
+  fDialog.setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" ));
+  fDialog.setWindowTitle( "Save camera positions" );
+  fDialog.setAcceptMode( QFileDialog::AcceptMode::AcceptSave );
+  fDialog.setDefaultSuffix( "json" );
+  fDialog.selectFile( filename );
+  fDialog.setDirectory( directory );
+  fDialog.setOption( QFileDialog::Option::DontUseNativeDialog , true );
+  fDialog.setOption( QFileDialog::Option::DontConfirmOverwrite , false );
+  fDialog.setFileMode( QFileDialog::FileMode::AnyFile );
+  fDialog.setNameFilters( QStringList{ nameFilter } );
+  fDialog.setNameFilter( nameFilter );
+
+  if ( fDialog.exec( ) != QFileDialog::Accepted )
     return;
 
-  if(fDialog.selectedFiles().empty()) return;
+  if ( fDialog.selectedFiles( ).empty( )) return;
 
-  filename = fDialog.selectedFiles().first();
+  filename = fDialog.selectedFiles( ).first( );
 
-  QFile wFile{filename};
-  if(!wFile.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate))
+  QFile wFile{ filename };
+  if ( !wFile.open(
+    QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ))
   {
-    const auto message = tr("Unable to open file %1 for writing.").arg(filename);
-
-    QMessageBox msgbox{this};
-    msgbox.setWindowTitle(tr("Save camera positions"));
-    msgbox.setIcon(QMessageBox::Icon::Critical);
-    msgbox.setText(message);
-    msgbox.setWindowIcon(QIcon(":/icons/rsc/neurotessmesh.png"));
-    msgbox.setDefaultButton(QMessageBox::Ok);
-    msgbox.exec();
+    const auto message = tr( "Unable to open file %1 for writing." ).arg(
+      filename );
+
+    QMessageBox msgbox{ this };
+    msgbox.setWindowTitle( tr( "Save camera positions" ));
+    msgbox.setIcon( QMessageBox::Icon::Critical );
+    msgbox.setText( message );
+    msgbox.setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" ));
+    msgbox.setDefaultButton( QMessageBox::Ok );
+    msgbox.exec( );
     return;
   }
 
-  QApplication::setOverrideCursor(Qt::WaitCursor);
+  QApplication::setOverrideCursor( Qt::WaitCursor );
 
-  const auto actions = _ui->actionCamera_Positions->menu()->actions();
+  const auto actions = _ui->actionCamera_Positions->menu( )->actions( );
 
   QJsonArray positionsObjs;
 
-  auto insertPosition = [&positionsObjs, this](const QAction *a)
+  auto insertPosition = [ &positionsObjs ]( const QAction* a )
   {
-    if(!a) return;
-    const auto posData = a->property(POSITION_KEY).toString();
-    const auto parts = posData.split(";");
-    Q_ASSERT(parts.size() == 3);
-    const auto position = parts.first();
-    const auto radius = parts.at(1);
-    const auto rotation = parts.last();
+    if ( !a ) return;
+    const auto posData = a->property( POSITION_KEY ).toString( );
+    const auto parts = posData.split( ";" );
+    Q_ASSERT( parts.size( ) == 3 );
+    const auto& position = parts.first( );
+    const auto& radius = parts.at( 1 );
+    const auto& rotation = parts.last( );
 
     QJsonObject positionObj;
-    positionObj.insert("name", a->text());
-    positionObj.insert("position", position);
-    positionObj.insert("radius", radius);
-    positionObj.insert("rotation", rotation);
+    positionObj.insert( "name" , a->text( ));
+    positionObj.insert( "position" , position );
+    positionObj.insert( "radius" , radius );
+    positionObj.insert( "rotation" , rotation );
 
     positionsObjs << positionObj;
   };
-  std::for_each(actions.cbegin(), actions.cend(), insertPosition);
+  std::for_each( actions.cbegin( ) , actions.cend( ) , insertPosition );
 
   QJsonObject obj;
-  obj.insert("filename", QFileInfo{_lastOpenedFileName}.fileName());
-  obj.insert("positions", positionsObjs);
+  obj.insert( "filename" , QFileInfo{ _lastOpenedFileName }.fileName( ));
+  obj.insert( "positions" , positionsObjs );
 
-  QJsonDocument doc{obj};
-  wFile.write(doc.toJson());
+  QJsonDocument doc{ obj };
+  wFile.write( doc.toJson( ));
 
-  QApplication::restoreOverrideCursor();
+  QApplication::restoreOverrideCursor( );
 
-  if(wFile.error() != QFile::NoError)
+  if ( wFile.error( ) != QFile::NoError )
   {
-    const auto message = tr("Error saving file %1.").arg(filename);
-
-    QMessageBox msgbox{this};
-    msgbox.setWindowTitle(tr("Save camera positions"));
-    msgbox.setIcon(QMessageBox::Icon::Critical);
-    msgbox.setText(message);
-    msgbox.setDetailedText(wFile.errorString());
-    msgbox.setWindowIcon(QIcon(":/icons/rsc/neurotessmesh.png"));
-    msgbox.setDefaultButton(QMessageBox::Ok);
-    msgbox.exec();
+    const auto message = tr( "Error saving file %1." ).arg( filename );
+
+    QMessageBox msgbox{ this };
+    msgbox.setWindowTitle( tr( "Save camera positions" ));
+    msgbox.setIcon( QMessageBox::Icon::Critical );
+    msgbox.setText( message );
+    msgbox.setDetailedText( wFile.errorString( ));
+    msgbox.setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" ));
+    msgbox.setDefaultButton( QMessageBox::Ok );
+    msgbox.exec( );
   }
 
-  wFile.flush();
-  wFile.close();
+  wFile.flush( );
+  wFile.close( );
 }
 
-void MainWindow::addCameraPosition()
+void MainWindow::addCameraPosition( )
 {
   QStringList items;
 
-  auto actions = _ui->actionCamera_Positions->menu()->actions();
-  auto insertItemName = [&items](const QAction *a){ items << a->text(); };
-  std::for_each(actions.cbegin(), actions.cend(), insertItemName);
+  auto actions = _ui->actionCamera_Positions->menu( )->actions( );
+  auto insertItemName = [ &items ]( const QAction* a )
+  { items << a->text( ); };
+  std::for_each( actions.cbegin( ) , actions.cend( ) , insertItemName );
 
-  const QString title = tr("Add camera position");
+  const QString title = tr( "Add camera position" );
 
   bool ok = false;
   QString name;
-  while(!ok || name.isEmpty())
+  while ( !ok || name.isEmpty( ))
   {
-    name = QInputDialog::getText(this, title, tr("Position name:"), QLineEdit::Normal, tr("New position"), &ok);
+    name = QInputDialog::getText( this , title , tr( "Position name:" ) ,
+                                  QLineEdit::Normal , tr( "New position" ) ,
+                                  &ok );
 
-    if(ok && !name.isEmpty())
+    if ( ok && !name.isEmpty( ))
     {
-      QString tempName(name);
+      QString tempName( name );
       int collision = 0;
-      while(items.contains(tempName, Qt::CaseInsensitive))
+      while ( items.contains( tempName , Qt::CaseInsensitive ))
       {
         ++collision;
-        tempName = tr("%1 (%2)").arg(name).arg(collision);
+        tempName = tr( "%1 (%2)" ).arg( name ).arg( collision );
       }
 
       name = tempName;
     }
   }
 
-  auto action = new QAction(name);
+  auto action = new QAction( name );
 
-  const auto position = _openGLWidget->cameraPosition();
-  action->setProperty(POSITION_KEY, position.toString());
+  const auto position = _openGLWidget->cameraPosition( );
+  action->setProperty( POSITION_KEY , position.toString( ));
 
-  connect(action, SIGNAL(triggered(bool)), this, SLOT(applyCameraPosition()));
-  _ui->actionCamera_Positions->menu()->addAction(action);
-  _ui->actionCamera_Positions->setEnabled(true);
-  _ui->actionSave_camera_positions->setEnabled(true);
-  _ui->actionRemove_camera_position->setEnabled(true);
+  connect( action , SIGNAL( triggered( bool )) ,
+           this , SLOT( applyCameraPosition( )));
+  _ui->actionCamera_Positions->menu( )->addAction( action );
+  _ui->actionCamera_Positions->setEnabled( true );
+  _ui->actionSave_camera_positions->setEnabled( true );
+  _ui->actionRemove_camera_position->setEnabled( true );
 }
 
-void MainWindow::removeCameraPosition()
+void MainWindow::removeCameraPosition( )
 {
   bool ok = false;
   QStringList items;
 
-  auto actions = _ui->actionCamera_Positions->menu()->actions();
-  auto insertItemName = [&items](const QAction *a){ items << a->text(); };
-  std::for_each(actions.cbegin(), actions.cend(), insertItemName);
+  auto actions = _ui->actionCamera_Positions->menu( )->actions( );
+  auto insertItemName = [ &items ]( const QAction* a )
+  { items << a->text( ); };
+  std::for_each( actions.cbegin( ) , actions.cend( ) , insertItemName );
 
-  auto item = QInputDialog::getItem(this, tr("Remove camera position"), tr("Position name:"), items, 0, false, &ok);
-  if (ok && !item.isEmpty())
+  auto item = QInputDialog::getItem( this , tr( "Remove camera position" ) ,
+                                     tr( "Position name:" ) , items , 0 ,
+                                     false , &ok );
+  if ( ok && !item.isEmpty( ))
   {
-    auto actionOfName = [&item](const QAction *a){ return a->text() == item; };
-    const auto it = std::find_if(actions.cbegin(), actions.cend(), actionOfName);
-    auto distance = std::distance(actions.cbegin(), it);
-    auto action = actions.at(distance);
-    _ui->actionCamera_Positions->menu()->removeAction(action);
+    auto actionOfName = [ &item ]( const QAction* a )
+    { return a->text( ) == item; };
+    const auto it = std::find_if( actions.cbegin( ) , actions.cend( ) ,
+                                  actionOfName );
+    auto distance = std::distance( actions.cbegin( ) , it );
+    auto action = actions.at( static_cast<int>(distance));
+    _ui->actionCamera_Positions->menu( )->removeAction( action );
     delete action;
 
-    const auto enabled = actions.size() > 1;
-    _ui->actionRemove_camera_position->setEnabled(enabled);
-    _ui->actionSave_camera_positions->setEnabled(enabled);
-    _ui->actionCamera_Positions->setEnabled(enabled);
+    const auto enabled = actions.size( ) > 1;
+    _ui->actionRemove_camera_position->setEnabled( enabled );
+    _ui->actionSave_camera_positions->setEnabled( enabled );
+    _ui->actionCamera_Positions->setEnabled( enabled );
   }
 }
 
-void MainWindow::applyCameraPosition()
+void MainWindow::applyCameraPosition( )
 {
-  auto action = qobject_cast<QAction *>(sender());
-  if(action)
+  auto action = qobject_cast< QAction* >( sender( ));
+  if ( action )
   {
-    auto positionString = action->property(POSITION_KEY).toString();
-    CameraPosition position(positionString);
-    _openGLWidget->setCameraPosition(position);
+    auto positionString = action->property( POSITION_KEY ).toString( );
+    CameraPosition position( positionString );
+    _scene->cameraPosition( position.position , position.radius ,
+                            position.rotation );
   }
 }
 
-void MainWindow::_generateNeuritesLayout( void )
+void MainWindow::_generateNeuritesLayout( )
 {
-  const unsigned int numDendrites = _openGLWidget->numNeuritesToEdit( );
+  const unsigned int numDendrites = _scene->numEditMorphologyNeurites( );
 
   _neuriteSliders.clear( );
 
-  QLayoutItem* child;
-  while(( child = _neuritesLayout->takeAt( 0 )) != 0 )
+  QLayoutItem * child;
+  while (( child = _neuritesLayout->takeAt( 0 )) != 0 )
   {
     delete child->widget( );
   }
 
   QSlider* _neuriteSlider;
-  for( unsigned int i = 0; i < numDendrites; i++ )
+  for ( unsigned int i = 0; i < numDendrites; i++ )
   {
     _neuriteSlider = new QSlider( Qt::Horizontal );
-    _neuriteSlider->setMinimum(0);
-    _neuriteSlider->setMaximum(200);
-    _neuriteSlider->setValue(100);
+    _neuriteSlider->setMinimum( 0 );
+    _neuriteSlider->setMaximum( 200 );
+    _neuriteSlider->setValue( 100 );
     _neuriteSlider->setToolTip(
       "Scales the distance between the position of the first tracing point of\n"
       "neurite n and the surface of the initial sphere used to generate the\n"
@@ -812,40 +864,38 @@ void MainWindow::_generateNeuritesLayout( void )
 
     _neuritesLayout->addWidget( _neuriteSlider );
     _neuriteSliders.push_back( _neuriteSlider );
-    // connect( _neuriteSlider, SIGNAL( sliderReleased( )),
-    //        this, SLOT( onActionGenerate( )));
-    connect( _neuriteSlider, SIGNAL( valueChanged( int )),
-           this, SLOT( onActionGenerate( int )));
+    connect( _neuriteSlider , SIGNAL( valueChanged( int )) ,
+             this , SLOT( onActionGenerate( int )));
   }
-  _radiusSlider->setValue(100);
+  _radiusSlider->setValue( 100 );
 }
 
-void MainWindow::_initExtractionDock( void )
+void MainWindow::_initExtractionDock( )
 {
   _extractMeshDock = new QDockWidget( );
-  this->addDockWidget( Qt::DockWidgetAreas::enum_type::RightDockWidgetArea,
-                       _extractMeshDock, Qt::Vertical );
-  _extractMeshDock->setSizePolicy(QSizePolicy::MinimumExpanding,
-                             QSizePolicy::Expanding);
-
-  _extractMeshDock->setFeatures(QDockWidget::DockWidgetClosable |
-                           QDockWidget::DockWidgetMovable |
-                           QDockWidget::DockWidgetFloatable);
+  this->addDockWidget( Qt::DockWidgetAreas::enum_type::RightDockWidgetArea ,
+                       _extractMeshDock , Qt::Vertical );
+  _extractMeshDock->setSizePolicy( QSizePolicy::MinimumExpanding ,
+                                   QSizePolicy::Expanding );
+
+  _extractMeshDock->setFeatures( QDockWidget::DockWidgetClosable |
+                                 QDockWidget::DockWidgetMovable |
+                                 QDockWidget::DockWidgetFloatable );
   _extractMeshDock->setWindowTitle( QString( "Edit And Save" ));
-  _extractMeshDock->setMinimumSize( 200, 200 );
+  _extractMeshDock->setMinimumSize( 200 , 200 );
 
   _extractMeshDock->close( );
 
-  QWidget* newWidget = new QWidget( );
+  auto* newWidget = new QWidget( );
   _extractMeshDock->setWidget( newWidget );
 
-  QVBoxLayout* _meshDockLayout = new QVBoxLayout( );
+  auto* _meshDockLayout = new QVBoxLayout( );
   _meshDockLayout->setAlignment( Qt::AlignTop );
   newWidget->setLayout( _meshDockLayout );
 
   //Neurons group
-  QGroupBox* _neuronsGroup = new QGroupBox( QString( "Select Neuron" ));
-  QVBoxLayout* _neuronsLayout = new QVBoxLayout( );
+  auto* _neuronsGroup = new QGroupBox( QString( "Select Neuron" ));
+  auto* _neuronsLayout = new QVBoxLayout( );
   _neuronsGroup->setLayout( _neuronsLayout );
   _meshDockLayout->addWidget( _neuronsGroup );
 
@@ -855,7 +905,7 @@ void MainWindow::_initExtractionDock( void )
 
   // Soma reconstruction group
   _somaGroup = new QGroupBox( QString( "Parameters" ));
-  QVBoxLayout* _somaGroupLayout = new QVBoxLayout( );
+  auto* _somaGroupLayout = new QVBoxLayout( );
   _somaGroup->setLayout( _somaGroupLayout );
   _meshDockLayout->addWidget( _somaGroup );
   _somaGroup->hide( );
@@ -866,68 +916,69 @@ void MainWindow::_initExtractionDock( void )
   _radiusSlider->setValue( 100 );
   _radiusSlider->setToolTip(
     "Scales the radius of the initial sphere used to generate the soma. [0-1]."
-    );
+  );
 
   _somaGroupLayout->addWidget( new QLabel( QString( "Radius factor" )));
   _somaGroupLayout->addWidget( _radiusSlider );
 
-  QScrollArea* _neuritesArea = new QScrollArea( );
-  _neuritesArea->setSizePolicy( QSizePolicy::MinimumExpanding,
+  auto* _neuritesArea = new QScrollArea( );
+  _neuritesArea->setSizePolicy( QSizePolicy::MinimumExpanding ,
                                 QSizePolicy::Expanding );
   _neuritesArea->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
   _neuritesArea->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
   _neuritesArea->setWidgetResizable( true );
   _neuritesArea->setFrameShape( QFrame::NoFrame );
   _somaGroupLayout->addWidget( _neuritesArea );
-  QWidget* _neuritesWidget = new QWidget( );
+  auto* _neuritesWidget = new QWidget( );
   _neuritesArea->setWidget( _neuritesWidget );
   _neuritesLayout = new QVBoxLayout( );
   _neuritesWidget->setLayout( _neuritesLayout );
 
   _extractButton = new QPushButton( QString( "Save" ));
-  _extractButton->setSizePolicy( QSizePolicy::Fixed,
-                                 QSizePolicy::Fixed);
+  _extractButton->setSizePolicy( QSizePolicy::Fixed ,
+                                 QSizePolicy::Fixed );
   _extractButton->setEnabled( false );
   _meshDockLayout->addWidget( _extractButton );
 
-  connect( _neuronList, SIGNAL( itemClicked( QListWidgetItem* )),
-           this, SLOT( onListClicked( QListWidgetItem* )));
+  connect( _neuronList , SIGNAL( itemClicked( QListWidgetItem * )) ,
+           this , SLOT( onListClicked( QListWidgetItem * )));
+
+  connect( _extractMeshDock->toggleViewAction( ) , SIGNAL( toggled( bool )) ,
+           _ui->actionEditSave , SLOT( setChecked( bool )));
 
-  connect( _extractMeshDock->toggleViewAction( ), SIGNAL( toggled( bool )),
-           _ui->actionEditSave, SLOT( setChecked( bool )));
-  connect( _ui->actionEditSave, SIGNAL( triggered( )),
-           this, SLOT( updateExtractMeshDock( )));
+  connect( _ui->actionEditSave , SIGNAL( triggered( )) ,
+           this , SLOT( updateExtractMeshDock( )));
 
 }
 
-void MainWindow::_initConfigurationDock( void )
+void MainWindow::_initConfigurationDock( )
 {
   _configurationDock = new QDockWidget( );
-  this->addDockWidget( Qt::DockWidgetAreas::enum_type::LeftDockWidgetArea,
-                       _configurationDock, Qt::Vertical );
-  _configurationDock->setSizePolicy(QSizePolicy::MinimumExpanding,
-                             QSizePolicy::Expanding);
-
-  _configurationDock->setFeatures(QDockWidget::DockWidgetClosable |
-                           QDockWidget::DockWidgetMovable |
-                           QDockWidget::DockWidgetFloatable);
+  this->addDockWidget( Qt::DockWidgetAreas::enum_type::LeftDockWidgetArea ,
+                       _configurationDock , Qt::Vertical );
+  _configurationDock->setSizePolicy( QSizePolicy::MinimumExpanding ,
+                                     QSizePolicy::Expanding );
+
+  _configurationDock->setFeatures( QDockWidget::DockWidgetClosable |
+                                   QDockWidget::DockWidgetMovable |
+                                   QDockWidget::DockWidgetFloatable );
   _configurationDock->setWindowTitle( QString( "Configuration" ));
-  _configurationDock->setMinimumSize( 200, 200 );
+  _configurationDock->setMinimumSize( 200 , 200 );
 
   _configurationDock->close( );
 
-  QWidget* newWidget = new QWidget( );
+  auto* newWidget = new QWidget( );
   _configurationDock->setWidget( newWidget );
 
-  QVBoxLayout* _configDockLayout = new QVBoxLayout( );
+  auto* _configDockLayout = new QVBoxLayout( );
   _configDockLayout->setAlignment( Qt::AlignTop );
   newWidget->setLayout( _configDockLayout );
 
-  QGroupBox* tessParamsGroup = new QGroupBox( QString( "Tessellation params" ));
-  tessParamsGroup->setSizePolicy( QSizePolicy::Fixed,
-                                  QSizePolicy::Fixed);
+  auto* tessParamsGroup = new QGroupBox( QString( "Tessellation params" ));
+  tessParamsGroup->setSizePolicy( QSizePolicy::Fixed ,
+                                  QSizePolicy::Fixed );
   _configDockLayout->addWidget( tessParamsGroup );
-  QVBoxLayout* vbox = new QVBoxLayout;
+  auto* vbox = new QVBoxLayout;
   tessParamsGroup->setLayout( vbox );
 
   _lotSlider = new QSlider( Qt::Horizontal );
@@ -936,7 +987,7 @@ void MainWindow::_initConfigurationDock( void )
   _lotSlider->setValue( 4 );
   _lotSlider->setToolTip(
     "Maximum level of subdivisions for the visualization [1-30]."
-    );
+  );
   vbox->addWidget(
     new QLabel( QString( "Subdivision Level" )));
   vbox->addWidget( _lotSlider );
@@ -946,8 +997,8 @@ void MainWindow::_initConfigurationDock( void )
   _distanceSlider->setMaximum( 1000 );
   _distanceSlider->setValue( 10 );
   _distanceSlider->setToolTip(
-     "Further distance to which the subdivision is applied [0-1], being 1\n"
-     "the camera maximum visibility distance." );
+    "Further distance to which the subdivision is applied [0-1], being 1\n"
+    "the camera maximum visibility distance." );
   vbox->addWidget(
     new QLabel( QString( "Distance threshold" )));
   vbox->addWidget( _distanceSlider );
@@ -965,67 +1016,67 @@ void MainWindow::_initConfigurationDock( void )
 
   _radioLinear->setChecked( true );
 
-  connect( _radioLinear, SIGNAL( toggled( bool )),
-           _distanceSlider, SLOT( setEnabled( bool )));
+  connect( _radioLinear , SIGNAL( toggled( bool )) ,
+           _distanceSlider , SLOT( setEnabled( bool )));
 
+  connect( _configurationDock->toggleViewAction( ) , SIGNAL( toggled( bool )) ,
+           _ui->actionConfiguration , SLOT( setChecked( bool )));
 
-  connect( _configurationDock->toggleViewAction( ), SIGNAL( toggled( bool )),
-           _ui->actionConfiguration, SLOT( setChecked( bool )));
-  connect( _ui->actionConfiguration, SIGNAL( triggered( )),
-           this, SLOT( updateConfigurationDock( )));
+  connect( _ui->actionConfiguration , SIGNAL( triggered( )) ,
+           this , SLOT( updateConfigurationDock( )));
 }
 
-void MainWindow::_initRenderOptionsDock( void )
+void MainWindow::_initRenderOptionsDock( )
 {
   _renderOptionsDock = new QDockWidget( );
-  this->addDockWidget( Qt::DockWidgetAreas::enum_type::LeftDockWidgetArea,
-                       _renderOptionsDock, Qt::Vertical );
-  _renderOptionsDock->setSizePolicy(QSizePolicy::Fixed,
-                                    QSizePolicy::Fixed);
-  _renderOptionsDock->setFeatures(QDockWidget::DockWidgetClosable |
-                           QDockWidget::DockWidgetMovable |
-                           QDockWidget::DockWidgetFloatable);
+  this->addDockWidget( Qt::DockWidgetAreas::enum_type::LeftDockWidgetArea ,
+                       _renderOptionsDock , Qt::Vertical );
+  _renderOptionsDock->setSizePolicy( QSizePolicy::Fixed ,
+                                     QSizePolicy::Fixed );
+  _renderOptionsDock->setFeatures( QDockWidget::DockWidgetClosable |
+                                   QDockWidget::DockWidgetMovable |
+                                   QDockWidget::DockWidgetFloatable );
   _renderOptionsDock->setWindowTitle( QString( "Render Options" ));
-  _renderOptionsDock->setMinimumSize( 200, 200 );
+  _renderOptionsDock->setMinimumSize( 200 , 200 );
 
   _renderOptionsDock->close( );
 
-  QWidget* newWidget = new QWidget( );
+  auto* newWidget = new QWidget( );
   _renderOptionsDock->setWidget( newWidget );
 
-  QVBoxLayout* roDockLayout = new QVBoxLayout( );
+  auto* roDockLayout = new QVBoxLayout( );
   roDockLayout->setAlignment( Qt::AlignTop );
   newWidget->setLayout( roDockLayout );
 
 
-  QGroupBox* colorGroup = new QGroupBox( QString( "Color" ));
-  colorGroup->setSizePolicy( QSizePolicy(QSizePolicy::Fixed,
-                                         QSizePolicy::Fixed));
+  auto* colorGroup = new QGroupBox( QString( "Color" ));
+  colorGroup->setSizePolicy( QSizePolicy( QSizePolicy::Fixed ,
+                                          QSizePolicy::Fixed ));
   roDockLayout->addWidget( colorGroup );
-  QGridLayout* gridbox = new QGridLayout;
+  auto* gridbox = new QGridLayout;
   colorGroup->setLayout( gridbox );
 
-  gridbox->addWidget( new QLabel( QString("Background color")), 0, 0);
+  gridbox->addWidget( new QLabel( QString( "Background color" )) , 0 , 0 );
   _backGroundColor = new ColorSelectionWidget( this );
-  gridbox->addWidget( _backGroundColor, 0, 1 );
+  gridbox->addWidget( _backGroundColor , 0 , 1 );
 
-  gridbox->addWidget( new QLabel( QString("Neuron color")), 1, 0);
+  gridbox->addWidget( new QLabel( QString( "Neuron color" )) , 1 , 0 );
   _neuronColor = new ColorSelectionWidget( this );
-  gridbox->addWidget( _neuronColor, 1, 1 );
+  gridbox->addWidget( _neuronColor , 1 , 1 );
 
-  gridbox->addWidget( new QLabel( QString("Selected neuron color")), 2, 0);
+  gridbox->addWidget( new QLabel( QString( "Selected neuron color" )) , 2 , 0 );
   _selectedNeuronColor = new ColorSelectionWidget( this );
-  gridbox->addWidget( _selectedNeuronColor, 2, 1 );
+  gridbox->addWidget( _selectedNeuronColor , 2 , 1 );
 
 
-  QGroupBox* renderGroup = new QGroupBox( QString( "Render piece selection" ));
+  auto* renderGroup = new QGroupBox( QString( "Render piece selection" ));
   roDockLayout->addWidget( renderGroup );
-  QVBoxLayout* vbox = new QVBoxLayout;
+  auto* vbox = new QVBoxLayout;
   renderGroup->setLayout( vbox );
 
   _neuronRender = new QComboBox( );
-  _neuronRender->setSizePolicy( QSizePolicy(QSizePolicy::Fixed,
-                                            QSizePolicy::Fixed));
+  _neuronRender->setSizePolicy( QSizePolicy( QSizePolicy::Fixed ,
+                                             QSizePolicy::Fixed ));
   vbox->addWidget( new QLabel( QString( "Neuron" )));
   vbox->addWidget( _neuronRender );
   _neuronRender->addItem( QString( "all" ));
@@ -1033,39 +1084,165 @@ void MainWindow::_initRenderOptionsDock( void )
   _neuronRender->addItem( QString( "neurites" ));
 
   _selectedNeuronRender = new QComboBox( );
-  _selectedNeuronRender->setSizePolicy( QSizePolicy(QSizePolicy::Fixed,
-                                                    QSizePolicy::Fixed));
+  _selectedNeuronRender->setSizePolicy( QSizePolicy( QSizePolicy::Fixed ,
+                                                     QSizePolicy::Fixed ));
   vbox->addWidget( new QLabel( QString( "Selected neuron" )));
   vbox->addWidget( _selectedNeuronRender );
   _selectedNeuronRender->addItem( QString( "all" ));
   _selectedNeuronRender->addItem( QString( "soma" ));
   _selectedNeuronRender->addItem( QString( "neurites" ));
 
-  connect( _renderOptionsDock->toggleViewAction( ), SIGNAL( toggled( bool )),
-           _ui->actionRenderOptions, SLOT( setChecked( bool )));
-  connect( _ui->actionRenderOptions, SIGNAL( triggered( )),
-           this, SLOT( updateRenderOptionsDock( )));
+  connect( _renderOptionsDock->toggleViewAction( ) , SIGNAL( toggled( bool )) ,
+           _ui->actionRenderOptions , SLOT( setChecked( bool )));
+
+  connect( _ui->actionRenderOptions , SIGNAL( triggered( )) ,
+           this , SLOT( updateRenderOptionsDock( )));
 }
 
-void MainWindow::closeEvent(QCloseEvent *e)
+void MainWindow::closeEvent( QCloseEvent* e )
 {
-  if(_recorder)
+  if ( _recorder )
   {
-    QMessageBox msgBox(this);
-    msgBox.setWindowTitle(tr("Exit NeuroTessMesh"));
+    QMessageBox msgBox( this );
+    msgBox.setWindowTitle( tr( "Exit NeuroTessMesh" ));
     msgBox.setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" ));
-    msgBox.setText(tr("A recording is being made. Do you really want to exit NeuroTessMesh?"));
-    msgBox.setStandardButtons(QMessageBox::Cancel|QMessageBox::Yes);
+    msgBox.setText( tr(
+      "A recording is being made. Do you really want to exit NeuroTessMesh?" ));
+    msgBox.setStandardButtons( QMessageBox::Cancel | QMessageBox::Yes );
 
-    if(msgBox.exec() != QMessageBox::Yes)
+    if ( msgBox.exec( ) != QMessageBox::Yes )
     {
-      e->ignore();
+      e->ignore( );
       return;
     }
 
-    RecorderUtils::stopAndWait(_recorder, this);
+    RecorderUtils::stopAndWait( _recorder , this );
     _recorder = nullptr;
   }
 
-  QMainWindow::closeEvent(e);
+  QMainWindow::closeEvent( e );
+}
+
+void MainWindow::_initPlayerDock( )
+{
+  _playerDock = new QDockWidget( );
+  this->addDockWidget( Qt::DockWidgetAreas::enum_type::BottomDockWidgetArea ,
+                       _playerDock , Qt::Horizontal );
+  _playerDock->setSizePolicy( QSizePolicy::MinimumExpanding ,
+                              QSizePolicy::Expanding );
+
+  _playerDock->setFeatures( QDockWidget::DockWidgetClosable |
+                            QDockWidget::DockWidgetMovable |
+                            QDockWidget::DockWidgetFloatable );
+  _playerDock->setAllowedAreas(Qt::DockWidgetAreas::enum_type::BottomDockWidgetArea|
+                               Qt::DockWidgetAreas::enum_type::TopDockWidgetArea);
+  _playerDock->setWindowTitle( QString( "Player Options" ));
+  _playerDock->show( );
+  _playerDock->close( );
+
+#ifdef NEUROTESSMESH_USE_SIMIL
+  auto playerControls = new qsimil::QSimControlWidget( _playerDock );
+  _playerDock->setWidget( playerControls );
+
+  connect( playerControls , SIGNAL( frame( )) ,
+           _openGLWidget , SLOT( update( )));
+
+  connect( _playerDock->toggleViewAction( ) , SIGNAL( toggled( bool )) ,
+           _ui->actionSimulation_player_options , SLOT( setChecked( bool )));
+
+  connect( _ui->actionSimulation_player_options , SIGNAL( triggered( )) ,
+           this , SLOT( updatePlayerOptionsDock( )));
+#endif
+}
+
+void MainWindow::loadData( const std::string& arg1 , const std::string& arg2 ,
+                           const neurotessmesh::LoaderThread::DataFileType type )
+{
+  if ( m_dataLoader ) return; // already loading?
+
+  m_dataLoader = std::make_shared< neurotessmesh::LoaderThread >( arg1 , arg2 ,
+                                                                  type );
+  auto dialog = new neurotessmesh::LoadingDialog{ this };
+
+  connect( m_dataLoader.get( ) , SIGNAL( finished( )) ,
+           this , SLOT( onDataLoaded( )) , Qt::QueuedConnection );
+
+  connect( m_dataLoader.get( ) , SIGNAL( destroyed( QObject * )) ,
+           dialog , SLOT( closeDialog( )));
+
+  connect( m_dataLoader.get( ) ,
+           SIGNAL( progress(const QString & , const unsigned int)) ,
+           dialog , SLOT( progress(const QString & , const unsigned int)));
+
+  dialog->show( );
+
+  m_dataLoader->start( );
+}
+
+void MainWindow::onDataLoaded( )
+{
+  const auto errors = m_dataLoader->errors( );
+  if ( !errors.isEmpty( ))
+  {
+    m_dataLoader = nullptr;
+
+    QMessageBox msgbox{ this };
+    msgbox.setWindowTitle( tr( "Error loading dataset" ));
+    msgbox.setIcon( QMessageBox::Icon::Critical );
+    msgbox.setText( errors );
+    msgbox.setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" ));
+    msgbox.setStandardButtons( QMessageBox::Ok );
+    msgbox.exec( );
+    return;
+  }
+
+  try
+  {
+    _openGLWidget->makeCurrent();
+    _openGLWidget->update( );
+
+    _scene = std::make_shared< neurotessmesh::Scene >(
+      _openGLWidget->getCamera( ) , m_dataLoader->getDataset( )
+#ifdef NEUROTESSMESH_USE_SIMIL
+      , m_dataLoader->getPlayer( )
+#endif
+      );
+    _openGLWidget->setScene( _scene );
+  }
+  catch ( const std::exception& e )
+  {
+    QMessageBox msgbox{ this };
+    msgbox.setWindowTitle( tr( "Error loading dataset" ));
+    msgbox.setIcon( QMessageBox::Icon::Critical );
+    msgbox.setText( tr( "Unable to load dataset. Geometry error." ));
+    msgbox.setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" ));
+    msgbox.setStandardButtons( QMessageBox::Ok );
+    msgbox.exec( );
+    return;
+  }
+
+  _openGLWidget->onLotValueChanged( _lotSlider->value( ));
+  _openGLWidget->onDistanceValueChanged( _distanceSlider->value( ));
+
+  updateNeuronList( );
+  _backGroundColor->color( QColor( 255 , 255 , 255 ));
+  _neuronColor->color( QColor( 0 , 120 , 250 ));
+  _selectedNeuronColor->color( QColor( 250 , 120 , 0 ));
+
+  _openGLWidget->home( );
+  _openGLWidget->changeNeuronPiece( _neuronRender->currentIndex( ));
+  _openGLWidget->changeSelectedNeuronPiece(
+    _selectedNeuronRender->currentIndex( ));
+#ifdef NEUROTESSMESH_USE_SIMIL
+  auto playerWidget = qobject_cast< qsimil::QSimControlWidget* >(
+    _playerDock->widget( ));
+  if ( playerWidget )
+  {
+
+    // disable hasta que hagamos el merge a master de SimIL
+    playerWidget->init( m_dataLoader->getPlayer( ));
+  }
+#endif
+
+  m_dataLoader = nullptr;
 }
diff --git a/neurotessmesh/MainWindow.h b/neurotessmesh/MainWindow.h
index 960597eae6af66fed865f23a28e02d50b011b026..d76464f6175e1c2ea1b02cc724eb104223f2ca89 100644
--- a/neurotessmesh/MainWindow.h
+++ b/neurotessmesh/MainWindow.h
@@ -12,7 +12,7 @@
 #include <QMainWindow>
 #include "OpenGLWidget.h"
 #include "ColorSelectionWidget.h"
-
+#include "LoaderThread.h"
 
 #include <QDockWidget>
 #include <QListWidget>
@@ -24,47 +24,67 @@
 
 namespace Ui
 {
-class MainWindow;
+  class MainWindow;
 }
 
 class Recorder;
+
 class QCloseEvent;
 
+namespace neurotessmesh
+{
+  class LoaderThread;
+}
+
 class MainWindow
   : public QMainWindow
 {
-  Q_OBJECT
+Q_OBJECT
 
 public:
 
-  explicit MainWindow( QWidget* parent_ = nullptr,
+  explicit MainWindow( QWidget* parent_ = nullptr ,
                        bool updateOnIdle_ = false );
-  ~MainWindow( void );
+
+  ~MainWindow( );
 
   void init( const std::string& zeqSession_ );
 
-  void showStatusBarMessage ( const QString& message );
+  void showStatusBarMessage( const QString& message );
+
+  void openBlueConfig( const std::string& fileName ,
+                       const std::string& target );
 
-  void openBlueConfig( const std::string& fileName,
-                       const std::string& target);
   void openXMLScene( const std::string& fileName );
+
   void openSWCFile( const std::string& fileName );
 
-  void updateNeuronList( void );
+  void updateNeuronList( );
 
 public slots:
 
-  void home( void );
-  void openBlueConfigThroughDialog( void );
-  void openXMLSceneThroughDialog( void );
-  void openSWCFileThroughDialog( void );
-  void showAbout( void );
-  void openRecorder( void );
-
-  void updateExtractMeshDock( void );
-  void updateConfigurationDock( void );
-  void updateRenderOptionsDock( void );
-  void onListClicked( QListWidgetItem *item );
+  void home( );
+
+  void openBlueConfigThroughDialog( );
+
+  void openXMLSceneThroughDialog( );
+
+  void openSWCFileThroughDialog( );
+
+  void showAbout( );
+
+  void openRecorder( );
+
+  void updateExtractMeshDock( );
+
+  void updateConfigurationDock( );
+
+  void updateRenderOptionsDock( );
+
+  void updatePlayerOptionsDock( );
+
+  void onListClicked( QListWidgetItem* item );
+
   void onActionGenerate( int value_ );
 
 protected slots:
@@ -74,46 +94,70 @@ protected slots:
   /** \brief Loads camera positions from a file.
    *
    */
-  void loadCameraPositions();
+  void loadCameraPositions( );
 
   /** \brief Saves camera positions to a file on disk.
    *
    */
-  void saveCameraPositions();
+  void saveCameraPositions( );
 
   /** \brief Stores current camera position in the positions list.
    *
    */
-  void addCameraPosition();
+  void addCameraPosition( );
 
   /** \brief Lets the user select a position to remove from the positions list.
    *
    */
-  void removeCameraPosition();
+  void removeCameraPosition( );
 
   /** \brief Changes the camera position to the one specified by the user.
    *
    */
-  void applyCameraPosition();
+  void applyCameraPosition( );
+
+  /** \brief Gets the dataset and player from the loader thread and initializes
+   * openGL widget and scene.
+   *
+   */
+  void onDataLoaded( );
 
 protected:
-  virtual void closeEvent(QCloseEvent *e) override;
+  virtual void closeEvent( QCloseEvent* e ) override;
 
   QString _lastOpenedFileName;
 
 private:
 
-  void _generateNeuritesLayout( void );
-  void _initExtractionDock( void );
-  void _initConfigurationDock( void );
-  void _initRenderOptionsDock( void );
+  void _generateNeuritesLayout( );
+
+  void _initExtractionDock( );
+
+  void _initConfigurationDock( );
+
+  void _initRenderOptionsDock( );
+
+  void _initPlayerDock( );
+
+  /** \brief Launches a LoaderThread with the gicen arguments.
+   * \param[in] arg1 First argument,required: dataset filename.
+   * \param[in] arg2 Second argument, only required for BlueConfig (target).
+   * \param[in] type Dataset type.
+   *
+   */
+  void loadData( const std::string& arg1 ,
+                 const std::string& arg2 ,
+                 neurotessmesh::LoaderThread::DataFileType type );
 
   Ui::MainWindow* _ui;
   OpenGLWidget* _openGLWidget;
 
+  std::shared_ptr< neurotessmesh::Scene > _scene;
+
   QDockWidget* _extractMeshDock;
   QDockWidget* _configurationDock;
   QDockWidget* _renderOptionsDock;
+  QDockWidget* _playerDock;
 
   QListWidget* _neuronList;
   QSlider* _radiusSlider;
@@ -137,4 +181,5 @@ private:
 
   // Recorder
   Recorder* _recorder;
+  std::shared_ptr< neurotessmesh::LoaderThread > m_dataLoader;
 };
diff --git a/neurotessmesh/OpenGLWidget.cpp b/neurotessmesh/OpenGLWidget.cpp
index 858c4e2c8a6f931436b3cb5f964d28d6f6a458a7..206707889ac2d94e5dc97e80562eb2ef71610853 100644
--- a/neurotessmesh/OpenGLWidget.cpp
+++ b/neurotessmesh/OpenGLWidget.cpp
@@ -11,30 +11,32 @@
 
 #include "OpenGLWidget.h"
 #include "MainWindow.h"
+#include "Scene.h"
 
 #include <QOpenGLContext>
 #include <QMouseEvent>
 #include <QColorDialog>
 #include <QFileDialog>
 #include <QMessageBox>
+#include <QDebug>
 
 #include <sstream>
 #include <string>
 #include <iostream>
+#include <utility>
 
 #include <nlrender/nlrender.h>
 
-const float OpenGLWidget::_colorFactor = 1 / 255.0f;
 const QString FPSLABEL_STYLESHEET = "QLabel { background-color : #333;"
                                     "color : white;"
                                     "padding: 3px;"
                                     "margin: 10px;"
                                     "border-radius: 10px;}";
 
-OpenGLWidget::OpenGLWidget( QWidget* parent_,
+OpenGLWidget::OpenGLWidget( QWidget* parent_ ,
                             Qt::WindowFlags windowsFlags_ )
-  : QOpenGLWidget( parent_, windowsFlags_ )
-  , _scene{nullptr}
+  : QOpenGLWidget( parent_ , windowsFlags_ )
+  , _scene( nullptr )
   , _mouseX( 0 )
   , _mouseY( 0 )
   , _rotation( false )
@@ -47,23 +49,24 @@ OpenGLWidget::OpenGLWidget( QWidget* parent_,
   , _showFps( false )
   , _frameCount( 0 )
 #ifdef NEUROTESSMESH_USE_LEXIS
-  , _subscriber( nullptr )
-  , _subscriberThread( nullptr )
+, _subscriber( nullptr )
+, _subscriberThread( nullptr )
 #endif
 {
   try
   {
     _camera = new reto::OrbitalCameraController( );
   }
-  catch(...)
+  catch ( ... )
   {
-    _camera = new reto::OrbitalCameraController(nullptr, reto::Camera::NO_ZEROEQ);
+    _camera = new reto::OrbitalCameraController( nullptr ,
+                                                 reto::Camera::NO_ZEROEQ );
   }
 
   _cameraTimer = new QTimer( );
   _cameraTimer->start(( 1.0f / 60.f ) * 100 );
-  connect( _cameraTimer, SIGNAL( timeout( )), this, SLOT( timerUpdate( )));
-  _fpsLabel.setStyleSheet(FPSLABEL_STYLESHEET);
+  connect( _cameraTimer , SIGNAL( timeout( )) , this , SLOT( timerUpdate( )));
+  _fpsLabel.setStyleSheet( FPSLABEL_STYLESHEET );
 
   // This is needed to get key events
   this->setFocusPolicy( Qt::WheelFocus );
@@ -71,36 +74,16 @@ OpenGLWidget::OpenGLWidget( QWidget* parent_,
   _lastSavedFileName = QDir::currentPath( );
 }
 
-OpenGLWidget::~OpenGLWidget( void )
+OpenGLWidget::~OpenGLWidget( )
 {
   delete _camera;
-  delete _scene;
   delete _cameraTimer;
 }
 
-bool OpenGLWidget::loadData(
-  const std::string& fileName_,
-  const neurotessmesh::Scene::TDataFileType fileType_,
-  const std::string& target_ )
+void OpenGLWidget::setScene( std::shared_ptr< neurotessmesh::Scene > scene )
 {
+  _scene = std::move( scene );
   makeCurrent( );
-  const auto errorString = _scene->loadData( fileName_, fileType_, target_ );
-
-  if(!errorString.empty())
-  {
-    const QString message = QString("Error loading file '%1'.\n%2")
-                             .arg(QString::fromStdString(fileName_))
-                             .arg(QString::fromStdString(errorString));
-
-    QMessageBox msgBox(this);
-    msgBox.setWindowTitle(tr("Error Loading Data"));
-    msgBox.setWindowIcon(QIcon(":/icons/rsc/neurotessmesh.png"));
-    msgBox.setText(message);
-    msgBox.setIcon(QMessageBox::Icon::Critical);
-    msgBox.exec();
-  }
-
-  return errorString.empty();
 }
 
 void OpenGLWidget::idleUpdate( bool idleUpdate_ )
@@ -108,60 +91,35 @@ void OpenGLWidget::idleUpdate( bool idleUpdate_ )
   _idleUpdate = idleUpdate_;
 }
 
-const std::vector< unsigned int > OpenGLWidget::neuronIdList( void ) const
-{
-  return _scene->neuronIndices( );
-}
-
-void OpenGLWidget::neuronToEdit( const unsigned int id_ )
+void OpenGLWidget::home( )
 {
-  _scene->setNeuronToEdit( id_ );
-  update( );
-}
-
-unsigned int OpenGLWidget::numNeuritesToEdit( void ) const
-{
-  return _scene->numEditMorphologyNeurites( );
-}
-
-void OpenGLWidget::regenerateNeuronToEdit(
-  const float alphaRadius_,
-  const std::vector< float >& alphaNeurites_ )
-{
-  makeCurrent( );
-  _scene->regenerateEditNeuronMesh( alphaRadius_, alphaNeurites_ );
-  update( );
-}
-
-void OpenGLWidget::home( void )
-{
-  _scene->home( );
   update( );
 }
 
 void OpenGLWidget::setZeqSession( const std::string&
 
 #ifdef NEUROTESSMESH_USE_LEXIS
-                                  session_
-  )
+  session_
+)
 {
-  if ( !session_.empty( ))
+  if (!session_.empty())
   {
-    if ( _camera )
+    if (_camera)
     {
       delete _camera;
     }
 
     try
     {
-      _camera = new reto::OrbitalCameraController( nullptr, session_ );
+      _camera = new reto::OrbitalCameraController(nullptr, session_);
     }
-    catch(...)
+    catch (...)
     {
-      _camera = new reto::OrbitalCameraController(nullptr, reto::Camera::NO_ZEROEQ);
+      _camera = new reto::OrbitalCameraController(nullptr,
+          reto::Camera::NO_ZEROEQ);
     }
 
-    if ( _subscriberThread )
+    if (_subscriberThread)
     {
       _subscriberThread->~thread();
       delete _subscriberThread;
@@ -170,119 +128,82 @@ void OpenGLWidget::setZeqSession( const std::string&
 
     try
     {
-    _subscriber = new zeroeq::Subscriber( session_ );
+      _subscriber = new zeroeq::Subscriber(session_);
 
-    _subscriber->subscribe(
-      lexis::data::SelectedIDs::ZEROBUF_TYPE_IDENTIFIER( ),
-      [&]( const void* selectedData, size_t selectedSize )
-      { _onSelectionEvent( lexis::data::SelectedIDs::create(
-                             selectedData, selectedSize ));});
+      _subscriber->subscribe(
+          lexis::data::SelectedIDs::ZEROBUF_TYPE_IDENTIFIER(),
+          [&](const void *selectedData, size_t selectedSize)
+          { _onSelectionEvent( lexis::data::SelectedIDs::create(
+                    selectedData, selectedSize ));});
 
 #ifdef NEUROTESSMESH_USE_GMRVLEX
-    _subscriber->subscribe(
-      zeroeq::gmrv::FocusedIDs::ZEROBUF_TYPE_IDENTIFIER( ),
-      [&]( const void* focusedData, size_t focusedSize )
-      { _onFocusEvent( zeroeq::gmrv::FocusedIDs::create(
-                             focusedData, focusedSize ));});
+      _subscriber->subscribe(
+          zeroeq::gmrv::FocusedIDs::ZEROBUF_TYPE_IDENTIFIER(),
+          [&](const void *focusedData, size_t focusedSize)
+          { _onFocusEvent( zeroeq::gmrv::FocusedIDs::create(
+                    focusedData, focusedSize ));});
 #endif
 
-    _subscriberThread =
-      new std::thread( [&](){
-          try
-          {
-            while ( true )
-              _subscriber->receive( 10000 );
-          }
-          catch( ... )
-          {
-            std::cerr << "Connexion closed" << std::endl;
-          }
-        });
+      _subscriberThread = new std::thread([&]()
+      {
+        try
+        {
+          while ( true )
+          _subscriber->receive( 10000 );
+        }
+        catch( ... )
+        {
+          std::cerr << "EXCEPTION: ZeroEQ Conection closed -> "
+          << __FILE__ << ":" << __LINE__ << std::endl;
+        }
+      });
 
     }
-    catch ( ... )
+    catch (...)
     {
       std::cerr << "Zeroeq Session Error: could not connect to " << session_
-                << " session" << std::endl;
+          << " session" << std::endl;
     }
   }
 }
-
 #else
-
-  )
+                                )
 {
   std::cerr << "Zeq not supported " << std::endl;
 }
-#endif
-
-CameraPosition OpenGLWidget::cameraPosition() const
-{
-  CameraPosition pos;
-  pos.position = _camera->position();
-  pos.radius   = _camera->radius();
-  pos.rotation = _camera->rotation();
-
-  return pos;
-}
 
-void OpenGLWidget::setCameraPosition(const CameraPosition &pos)
-{
-  if(_camera)
-  {
-    _scene->cameraPosition(pos.position, pos.radius, pos.rotation);
-    _camera->position(pos.position);
-    _camera->radius(pos.radius);
-    _camera->rotation(pos.rotation);
-    update();
-  }
-}
+#endif
 
-void OpenGLWidget::changeClearColor( QColor color )
+reto::OrbitalCameraController* OpenGLWidget::getCamera( ) const
 {
-    makeCurrent( );
-    glClearColor( float( color.red( )) * _colorFactor,
-                  float( color.green( )) * _colorFactor,
-                  float( color.blue( )) * _colorFactor,
-                  float( color.alpha( )) * _colorFactor);
-    update( );
+  return _camera;
 }
 
-void OpenGLWidget::changeNeuronColor( QColor color )
+CameraPosition OpenGLWidget::cameraPosition( ) const
 {
-  makeCurrent( );
-  _scene->unselectedNeuronColor(
-    Eigen::Vector3f( float( color.red( )) * _colorFactor,
-                     float( color.green( )) * _colorFactor,
-                     float( color.blue( )) * _colorFactor ));
-  update( );
-}
+  CameraPosition pos;
+  pos.position = _camera->position( );
+  pos.radius = _camera->radius( );
+  pos.rotation = _camera->rotation( );
 
-void OpenGLWidget::changeSelectedNeuronColor(  QColor color )
-{
-  makeCurrent( );
-  _scene->selectedNeuronColor(
-    Eigen::Vector3f( float( color.red( )) * _colorFactor,
-                     float( color.green( )) * _colorFactor,
-                     float( color.blue( )) * _colorFactor ));
-  update( );
+  return pos;
 }
 
-void OpenGLWidget::toggleUpdateOnIdle( void )
+void OpenGLWidget::toggleUpdateOnIdle( )
 {
   _idleUpdate = !_idleUpdate;
   if ( _idleUpdate )
     update( );
 }
 
-void OpenGLWidget::toggleShowFPS( void )
+void OpenGLWidget::toggleShowFPS( )
 {
   _showFps = !_showFps;
   if ( _idleUpdate )
     update( );
 }
 
-void OpenGLWidget::toggleWireframe( void )
+void OpenGLWidget::toggleWireframe( )
 {
   makeCurrent( );
   _wireframe = !_wireframe;
@@ -290,45 +211,45 @@ void OpenGLWidget::toggleWireframe( void )
   if ( _wireframe )
   {
     glEnable( GL_POLYGON_OFFSET_LINE );
-    glPolygonOffset( -1, -1 );
+    glPolygonOffset( -1 , -1 );
     glLineWidth( 1.5 );
-    glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+    glPolygonMode( GL_FRONT_AND_BACK , GL_LINE );
   }
   else
   {
-    glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+    glPolygonMode( GL_FRONT_AND_BACK , GL_FILL );
     glDisable( GL_POLYGON_OFFSET_LINE );
   }
 
   update( );
 }
 
-void OpenGLWidget::timerUpdate( void )
+void OpenGLWidget::timerUpdate( )
 {
-  if( _camera->isAniming() )
+  if ( _camera->isAniming( ))
   {
-    _camera->anim();
+    _camera->anim( );
     this->update( );
   }
 }
 
-void OpenGLWidget::extractEditNeuronMesh( void )
+void OpenGLWidget::extractEditNeuronMesh( )
 {
-  if( _scene->isEditNeuronMeshExtraction( ))
+  if ( _scene->isEditNeuronMeshExtraction( ))
   {
     QString path;
     const QString filter( tr( "OBJ (*.obj);; All files (*)" ));
-    QFileDialog fd(this, QString( "Save mesh to OBJ file" ),
-                   _lastSavedFileName, filter );
+    QFileDialog fd( this , QString( "Save mesh to OBJ file" ) ,
+                    _lastSavedFileName , filter );
 
-    fd.setOption( QFileDialog::DontUseNativeDialog, true );
-    fd.setDefaultSuffix( "obj") ;
+    fd.setOption( QFileDialog::DontUseNativeDialog , true );
+    fd.setDefaultSuffix( "obj" );
     fd.setFileMode( QFileDialog/*::FileMode*/::AnyFile );
     fd.setAcceptMode( QFileDialog/*::AcceptMode*/::AcceptSave );
     if ( fd.exec( ))
-      path = fd.selectedFiles( )[0];
+      path = fd.selectedFiles( )[ 0 ];
 
-    if ( !path.isEmpty() )
+    if ( !path.isEmpty( ))
     {
       _lastSavedFileName = QFileInfo( path ).path( );
       this->makeCurrent( );
@@ -340,73 +261,87 @@ void OpenGLWidget::extractEditNeuronMesh( void )
 
 void OpenGLWidget::onLotValueChanged( int value_ )
 {
-  _scene->levelOfDetail(static_cast<float>(value_) * 0.1  );
-  update( );
+  if ( _scene )
+  {
+    _scene->levelOfDetail( static_cast<float>(value_) * 0.1f );
+    update( );
+  }
 }
 
 void OpenGLWidget::onDistanceValueChanged( int value_ )
 {
-  _scene->maximumDistance(static_cast<float>(value_) / 1000.0f );
-  update( );
+  if ( _scene )
+  {
+    _scene->maximumDistance( static_cast<float>(value_) / 1000.0f );
+    update( );
+  }
 }
 
-void OpenGLWidget::onHomogeneousClicked( void )
+void OpenGLWidget::onHomogeneousClicked( )
 {
-  _scene->subdivisionCriteria( nlrender::Renderer::HOMOGENEOUS );
-  update( );
+  if ( _scene )
+  {
+    _scene->subdivisionCriteria( nlrender::Renderer::HOMOGENEOUS );
+    update( );
+  }
 }
 
-void OpenGLWidget::onLinearClicked( void )
+void OpenGLWidget::onLinearClicked( )
 {
-  _scene->subdivisionCriteria( nlrender::Renderer::LINEAR );
-  update( );
+  if ( _scene )
+  {
+    _scene->subdivisionCriteria( nlrender::Renderer::LINEAR );
+    update( );
+  }
 }
+
 void OpenGLWidget::changeNeuronPiece( int index_ )
 {
-  switch( index_ )
+  if ( !_scene ) return;
+  switch ( index_ )
   {
-  case 0:
-    _scene->paintUnselectedSoma( true );
-    _scene->paintUnselectedNeurites( true );
-    break;
-  case 1:
-    _scene->paintUnselectedSoma( true );
-    _scene->paintUnselectedNeurites( false );
-    break;
-  case 2:
-    _scene->paintUnselectedSoma( false );
-    _scene->paintUnselectedNeurites( true );
-    break;
+    case 0:
+      _scene->paintUnselectedSoma( true );
+      _scene->paintUnselectedNeurites( true );
+      break;
+    case 1:
+      _scene->paintUnselectedSoma( true );
+      _scene->paintUnselectedNeurites( false );
+      break;
+    case 2:
+      _scene->paintUnselectedSoma( false );
+      _scene->paintUnselectedNeurites( true );
+      break;
   }
   update( );
 }
 
 void OpenGLWidget::changeSelectedNeuronPiece( int index_ )
 {
-  switch( index_ )
+  if ( !_scene ) return;
+  switch ( index_ )
   {
-  case 0:
-    _scene->paintSelectedSoma( true );
-    _scene->paintSelectedNeurites( true );
-    break;
-  case 1:
-    _scene->paintSelectedSoma( true );
-    _scene->paintSelectedNeurites( false );
-    break;
-  case 2:
-    _scene->paintSelectedSoma( false );
-    _scene->paintSelectedNeurites( true );
-    break;
+    case 0:
+      _scene->paintSelectedSoma( true );
+      _scene->paintSelectedNeurites( true );
+      break;
+    case 1:
+      _scene->paintSelectedSoma( true );
+      _scene->paintSelectedNeurites( false );
+      break;
+    case 2:
+      _scene->paintSelectedSoma( false );
+      _scene->paintSelectedNeurites( true );
+      break;
   }
   update( );
 }
 
-void OpenGLWidget::initializeGL( void )
+void OpenGLWidget::initializeGL( )
 {
   initializeOpenGLFunctions( );
-
   glEnable( GL_DEPTH_TEST );
-  glClearColor(  1.0f, 1.0f, 1.0f, 1.0f );
+  glClearColor( 1.0f , 1.0f , 1.0f , 1.0f );
   glPolygonMode( GL_FRONT_AND_BACK , GL_FILL );
   glEnable( GL_CULL_FACE );
 
@@ -414,35 +349,40 @@ void OpenGLWidget::initializeGL( void )
 
   QOpenGLWidget::initializeGL( );
 
-  const GLubyte* vendor = glGetString(GL_VENDOR); // Returns the vendor
-  const GLubyte* renderer = glGetString(GL_RENDERER); // Returns a hint to the model
-  const GLubyte* version = glGetString(GL_VERSION);
-  const GLubyte* shadingVer = glGetString(GL_SHADING_LANGUAGE_VERSION);
+  const GLubyte* vendor = glGetString( GL_VENDOR ); // Returns the vendor
+  const GLubyte* renderer = glGetString(
+    GL_RENDERER ); // Returns a hint to the model
+  const GLubyte* version = glGetString( GL_VERSION );
+  const GLubyte* shadingVer = glGetString( GL_SHADING_LANGUAGE_VERSION );
 
-  std::cout << "OpenGL Hardware: " << vendor << " (" << renderer << ")" << std::endl;
-  std::cout << "OpenGL Version: " << version << " (shading ver. " << shadingVer << ")" << std::endl;
+  std::cout << "OpenGL Hardware: " << vendor << " (" << renderer << ")"
+            << std::endl;
+  std::cout << "OpenGL Version: " << version << " (shading ver. " << shadingVer
+            << ")" << std::endl;
 
   nlrender::Config::init( );
-  _scene = new neurotessmesh::Scene( _camera );
 }
 
-void OpenGLWidget::paintGL( void )
+void OpenGLWidget::paintGL( )
 {
-  makeCurrent( );
   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 
-  _scene->render( );
+  if ( _scene != nullptr )
+  {
+    _scene->update();
+    _scene->render( );
+  }
 
   glUseProgram( 0 );
   glFlush( );
 
 #define FRAMES_PAINTED_TO_MEASURE_FPS 10
-  if ( _frameCount % FRAMES_PAINTED_TO_MEASURE_FPS  == 0 )
+  if ( _frameCount % FRAMES_PAINTED_TO_MEASURE_FPS == 0 )
   {
     const auto now = std::chrono::system_clock::now( );
 
     const auto duration =
-      std::chrono::duration_cast<std::chrono::milliseconds>( now - _then );
+      std::chrono::duration_cast< std::chrono::milliseconds >( now - _then );
     _then = now;
 
     auto mainWindow = dynamic_cast< MainWindow* >( parent( ));
@@ -450,9 +390,11 @@ void OpenGLWidget::paintGL( void )
     {
       const unsigned int ellapsedMiliseconds = duration.count( );
 
-      const unsigned int fps = roundf( 1000.0f *
-                                 static_cast<float>( FRAMES_PAINTED_TO_MEASURE_FPS ) /
-                                 static_cast<float>( ellapsedMiliseconds ));
+      const auto fps = static_cast<unsigned int>(roundf(
+        1000.0f *
+        static_cast<float>( FRAMES_PAINTED_TO_MEASURE_FPS ) /
+        static_cast<float>( ellapsedMiliseconds ))
+      );
 
       if ( _showFps )
       {
@@ -477,13 +419,12 @@ void OpenGLWidget::paintGL( void )
 
 void OpenGLWidget::resizeGL( int width_ , int height_ )
 {
-  _camera->windowSize(width_, height_);
-  glViewport( 0, 0, width_, height_ );
+  _camera->windowSize( width_ , height_ );
+  glViewport( 0 , 0 , width_ , height_ );
 }
 
 void OpenGLWidget::mousePressEvent( QMouseEvent* event_ )
 {
-
   if ( event_->button( ) == Qt::LeftButton )
   {
     _rotation = true;
@@ -491,49 +432,47 @@ void OpenGLWidget::mousePressEvent( QMouseEvent* event_ )
     _mouseY = event_->y( );
   }
 
-  if ( event_->button( ) ==  Qt::MidButton )
+  if ( event_->button( ) == Qt::MidButton )
   {
     _translation = true;
     _mouseX = event_->x( );
     _mouseY = event_->y( );
   }
-
-  update( );
 }
 
 void OpenGLWidget::mouseReleaseEvent( QMouseEvent* event_ )
 {
-  if ( event_->button( ) == Qt::LeftButton)
+  if ( event_->button( ) == Qt::LeftButton )
   {
     _rotation = false;
   }
 
-  if ( event_->button( ) ==  Qt::MidButton )
+  if ( event_->button( ) == Qt::MidButton )
   {
     _translation = false;
   }
-
-  update( );
 }
 
 void OpenGLWidget::mouseMoveEvent( QMouseEvent* event_ )
 {
-  if( _rotation )
+  if ( _rotation )
   {
-      _camera->rotate( Eigen::Vector3f{ -( _mouseX - event_->x( )) * _rotationScale,
-                                        -( _mouseY - event_->y( )) * _rotationScale,
-                                        0.f } );
+    _camera->rotate(
+      Eigen::Vector3f{ -( _mouseX - event_->x( )) * _rotationScale ,
+                       -( _mouseY - event_->y( )) * _rotationScale ,
+                       0.f } );
 
-      _mouseX = event_->x( );
-      _mouseY = event_->y( );  }
-  if( _translation )
+    _mouseX = event_->x( );
+    _mouseY = event_->y( );
+  }
+  if ( _translation )
   {
-      float xDis = ( event_->x() - _mouseX ) * _translationScale;
-      float yDis = ( event_->y() - _mouseY ) * _translationScale;
+    float xDis = ( event_->x( ) - _mouseX ) * _translationScale;
+    float yDis = ( event_->y( ) - _mouseY ) * _translationScale;
 
-      _camera->translate( Eigen::Vector3f( -xDis, yDis, 0.0f ));
-      _mouseX = event_->x( );
-      _mouseY = event_->y( );
+    _camera->translate( Eigen::Vector3f( -xDis , yDis , 0.0f ));
+    _mouseX = event_->x( );
+    _mouseY = event_->y( );
   }
 
   this->update( );
@@ -541,7 +480,6 @@ void OpenGLWidget::mouseMoveEvent( QMouseEvent* event_ )
 
 void OpenGLWidget::wheelEvent( QWheelEvent* event_ )
 {
-
   int delta = event_->angleDelta( ).y( );
 
   if ( delta > 0 )
@@ -550,7 +488,6 @@ void OpenGLWidget::wheelEvent( QWheelEvent* event_ )
     _camera->radius( _camera->radius( ) * 1.1f );
 
   update( );
-
 }
 
 void OpenGLWidget::keyPressEvent( QKeyEvent* event_ )
@@ -559,15 +496,34 @@ void OpenGLWidget::keyPressEvent( QKeyEvent* event_ )
 
   switch ( event_->key( ))
   {
-  case Qt::Key_C:
-    _camera->position( Eigen::Vector3f( 0.f, 0.f, 0.f ));
-    _camera->radius( 1000.0f );
-    _camera->rotation( Eigen::Vector3f{0.f, 0.f,0.f} );
-    update( );
-    break;
+    case Qt::Key_C:
+      _camera->position( Eigen::Vector3f( 0.f , 0.f , 0.f ));
+      _camera->radius( 1000.0f );
+      _camera->rotation( Eigen::Vector3f{ 0.f , 0.f , 0.f } );
+      update( );
+      break;
   }
 }
 
+void OpenGLWidget::changeClearColor( QColor qColor )
+{
+  makeCurrent( );
+  glClearColor( qColor.redF( ) , qColor.greenF( ) , qColor.blueF( ) , 1.0f );
+  update( );
+}
+
+void OpenGLWidget::changeNeuronColor( QColor qColor )
+{
+  _scene->unselectedNeuronColor( qColor );
+  update( );
+}
+
+void OpenGLWidget::changeSelectedNeuronColor( QColor qColor )
+{
+  _scene->selectedNeuronColor( qColor );
+  update( );
+}
+
 #ifdef NEUROTESSMESH_USE_LEXIS
 void OpenGLWidget::_onSelectionEvent(
   lexis::data::ConstSelectedIDsPtr selectedIndices_ )
@@ -586,4 +542,5 @@ void OpenGLWidget::_onFocusEvent(
   _scene->focusOnIndices( focusedIndices );
   update( );
 }
+
 #endif
diff --git a/neurotessmesh/OpenGLWidget.h b/neurotessmesh/OpenGLWidget.h
index 252459adf739c34042fd779134e4742b1d72a9d0..c86e3a7f831abb81083872a41189284d3a6cc627 100644
--- a/neurotessmesh/OpenGLWidget.h
+++ b/neurotessmesh/OpenGLWidget.h
@@ -16,10 +16,12 @@
 #include <QLabel>
 #include <QTimer>
 #include <QColor>
-#include <chrono>
 
-#include <reto/reto.h>
-#include "Scene.h"
+#include <Eigen/Eigen>
+
+#include <chrono>
+#include <memory>
+#include <iostream>
 
 #ifdef NEUROTESSMESH_USE_LEXIS
 #include <zeroeq/zeroeq.h>
@@ -30,9 +32,25 @@
 #endif
 #endif
 
-struct streamDotSeparator: std::numpunct<char>
+namespace neurotessmesh
+{
+  class Scene;
+}
+
+namespace reto
+{
+  class OrbitalCameraController;
+}
+
+namespace nsol
+{
+  class DataSet;
+}
+
+struct streamDotSeparator : std::numpunct< char >
 {
-    char do_decimal_point() const { return '.'; }
+  char do_decimal_point( ) const override
+  { return '.'; }
 };
 
 /** \class CameraPosition
@@ -41,144 +59,143 @@ struct streamDotSeparator: std::numpunct<char>
  */
 class CameraPosition
 {
-  public:
-    Eigen::Vector3f position; /** position point.  */
-    Eigen::Matrix3f rotation; /** rotation matrix. */
-    float radius;             /** aperture.        */
-
-    /** \brief CameraPosition class constructor.
-     *
-     */
-    CameraPosition()
-    : position{Eigen::Vector3f()}
-    , rotation{Eigen::Matrix3f::Zero()}
-    , radius{0}
-    {};
-
-    /** \brief CameraPosition class constructor.
-     * \param[in] data Camera position serialized data.
-     *
-     */
-    CameraPosition(const QString &data)
-    {
-      const auto separator = std::use_facet<std::numpunct<char>>(std::cout.getloc()).decimal_point();
-      const bool needSubst = (separator == ',');
-
-      auto parts = data.split(";");
-      Q_ASSERT(parts.size() == 3);
-      const auto posData = parts.first();
-      const auto rotData = parts.last();
-      auto radiusData = parts.at(1);
-
-      auto posParts = posData.split(",");
-      Q_ASSERT(posParts.size() == 3);
-      auto rotParts = rotData.split(",");
-      Q_ASSERT(rotParts.size() == 9);
-
-      if(needSubst)
-      {
-        for(auto &part: posParts) part.replace('.', ',');
-        for(auto &part: rotParts) part.replace('.', ',');
-        radiusData.replace('.', ',');
-      }
-
-      position = Eigen::Vector3f(posParts[0].toFloat(), posParts[1].toFloat(), posParts[2].toFloat());
-      radius = radiusData.toFloat();
-      rotation.block<1,3>(0,0) = Eigen::Vector3f{rotParts[0].toFloat(), rotParts[1].toFloat(), rotParts[2].toFloat()};
-      rotation.block<1,3>(1,0) = Eigen::Vector3f{rotParts[3].toFloat(), rotParts[4].toFloat(), rotParts[5].toFloat()};
-      rotation.block<1,3>(2,0) = Eigen::Vector3f{rotParts[6].toFloat(), rotParts[7].toFloat(), rotParts[8].toFloat()};
-    }
+public:
+  Eigen::Vector3f position; /** position point.  */
+  Eigen::Matrix3f rotation; /** rotation matrix. */
+  float radius;             /** aperture.        */
 
-    /** \brief Returns the serialized camera position.
-     *
-     */
-    QString toString() const
+  /** \brief CameraPosition class constructor.
+   *
+   */
+  CameraPosition( )
+    : position{ Eigen::Vector3f( ) }
+    , rotation{ Eigen::Matrix3f::Zero( ) }
+    , radius{ 0 }
+  { };
+
+  /** \brief CameraPosition class constructor.
+   * \param[in] data Camera position serialized data.
+   *
+   */
+  explicit CameraPosition( const QString& data )
+  {
+    const auto separator = std::use_facet< std::numpunct< char>>(
+      std::cout.getloc( )).decimal_point( );
+    const bool needSubst = ( separator == ',' );
+
+    auto parts = data.split( ";" );
+    Q_ASSERT( parts.size( ) == 3 );
+    const auto posData = parts.first( );
+    const auto rotData = parts.last( );
+    auto radiusData = parts.at( 1 );
+
+    auto posParts = posData.split( "," );
+    Q_ASSERT( posParts.size( ) == 3 );
+    auto rotParts = rotData.split( "," );
+    Q_ASSERT( rotParts.size( ) == 9 );
+
+    if ( needSubst )
     {
-      std::stringstream stream;
-      stream.imbue(std::locale(stream.getloc(), new streamDotSeparator()));
-      stream << position << ";" << radius << ";"
-              << rotation(0,0) << "," << rotation(0,1) << "," << rotation(0,2) << ","
-              << rotation(1,0) << "," << rotation(1,1) << "," << rotation(1,2) << ","
-              << rotation(2,0) << "," << rotation(2,1) << "," << rotation(2,2);
-
-      auto serialization = QString::fromStdString(stream.str());
-      serialization.replace('\n',',').remove(' ');
-
-      return serialization;
+      for ( auto& part: posParts ) part.replace( '.' , ',' );
+      for ( auto& part: rotParts ) part.replace( '.' , ',' );
+      radiusData.replace( '.' , ',' );
     }
+
+    position = Eigen::Vector3f( posParts[ 0 ].toFloat( ) ,
+                                posParts[ 1 ].toFloat( ) ,
+                                posParts[ 2 ].toFloat( ));
+    radius = radiusData.toFloat( );
+    rotation.block< 1 , 3 >( 0 , 0 ) = Eigen::Vector3f{
+      rotParts[ 0 ].toFloat( ) , rotParts[ 1 ].toFloat( ) ,
+      rotParts[ 2 ].toFloat( ) };
+    rotation.block< 1 , 3 >( 1 , 0 ) = Eigen::Vector3f{
+      rotParts[ 3 ].toFloat( ) , rotParts[ 4 ].toFloat( ) ,
+      rotParts[ 5 ].toFloat( ) };
+    rotation.block< 1 , 3 >( 2 , 0 ) = Eigen::Vector3f{
+      rotParts[ 6 ].toFloat( ) , rotParts[ 7 ].toFloat( ) ,
+      rotParts[ 8 ].toFloat( ) };
+  }
+
+  /** \brief Returns the serialized camera position.
+   *
+   */
+  QString toString( ) const
+  {
+    std::stringstream stream;
+    stream.imbue( std::locale( stream.getloc( ) , new streamDotSeparator( )));
+    stream << position << ";" << radius << ";"
+           << rotation( 0 , 0 ) << "," << rotation( 0 , 1 ) << ","
+           << rotation( 0 , 2 ) << ","
+           << rotation( 1 , 0 ) << "," << rotation( 1 , 1 ) << ","
+           << rotation( 1 , 2 ) << ","
+           << rotation( 2 , 0 ) << "," << rotation( 2 , 1 ) << ","
+           << rotation( 2 , 2 );
+
+    auto serialization = QString::fromStdString( stream.str( ));
+    serialization.replace( '\n' , ',' ).remove( ' ' );
+
+    return serialization;
+  }
 };
 
 class OpenGLWidget
-  : public QOpenGLWidget
-  , public QOpenGLFunctions
+  : public QOpenGLWidget , public QOpenGLFunctions
 {
 
-  Q_OBJECT;
+Q_OBJECT;
 
 public:
 
-  OpenGLWidget( QWidget* parent_ = nullptr,
-                Qt::WindowFlags windowFlags_ = Qt::WindowFlags() );
+  explicit OpenGLWidget( QWidget* parent_ = nullptr ,
+                         Qt::WindowFlags windowFlags_ = Qt::WindowFlags( ));
 
-  ~OpenGLWidget( void );
+  ~OpenGLWidget( ) override;
 
-  /** \brief Loads a dataset with the given parameters.
-   * \param[in] fileName_ Dataset filename.
-   * \param[in] fileType_ Dataset type.
-   * \param[in] target_ BlueConfig target if Blueconfig or empty otherwise.
-   *
-   */
-  bool loadData( const std::string& fileName_,
-                 const neurotessmesh::Scene::TDataFileType fileType_ =
-                 neurotessmesh::Scene::TDataFileType::BlueConfig,
-                 const std::string& target_ = std::string( "" ));
+  void setScene( std::shared_ptr< neurotessmesh::Scene > scene );
 
   void idleUpdate( bool idleUpdate_ = true );
 
-  const std::vector< unsigned int > neuronIdList( void ) const;
-
-  void neuronToEdit( const unsigned int id_ );
-
-  unsigned int numNeuritesToEdit( void ) const;
-
-  void regenerateNeuronToEdit( const float alphaRadius_,
-                               const std::vector< float >& alphaNeurites_ );
-
-  void home( void );
+  void home( );
 
   void setZeqSession( const std::string& session_ );
 
-  /** \brief Returns the current camera position.
-   *
-   */
-  CameraPosition cameraPosition() const;
+  reto::OrbitalCameraController* getCamera( ) const;
 
-  /** \brief Moves the camera to the given position.
-   * \param[in] pos CameraPosition reference.
+  /** \brief Returns the current camera position.
    *
    */
-  void setCameraPosition(const CameraPosition &pos);
+  CameraPosition cameraPosition( ) const;
 
 public slots:
 
-  void changeClearColor( QColor color );
-  void changeNeuronColor( QColor color );
-  void changeSelectedNeuronColor( QColor color );
-  void toggleUpdateOnIdle( void );
-  void toggleShowFPS( void );
-  void toggleWireframe( void );
-  void timerUpdate( void );
-  void extractEditNeuronMesh( void );
+  void toggleUpdateOnIdle( );
+
+  void toggleShowFPS( );
+
+  void toggleWireframe( );
+
+  void timerUpdate( );
+
+  void extractEditNeuronMesh( );
 
   void onLotValueChanged( int value_ );
+
   void onDistanceValueChanged( int value_ );
 
-  void onHomogeneousClicked( void );
-  void onLinearClicked( void );
+  void onHomogeneousClicked( );
+
+  void onLinearClicked( );
 
   void changeNeuronPiece( int index_ );
+
   void changeSelectedNeuronPiece( int index_ );
 
+  void changeClearColor( QColor );
+
+  void changeNeuronColor( QColor );
+
+  void changeSelectedNeuronColor( QColor );
+
 protected:
 
 #ifdef NEUROTESSMESH_USE_LEXIS
@@ -190,21 +207,27 @@ protected:
 
 #endif
 
-  virtual void initializeGL( void );
-  virtual void paintGL( void );
-  virtual void resizeGL( int width_, int height_ );
+  void initializeGL( ) override;
+
+  void paintGL( ) override;
 
-  virtual void mousePressEvent( QMouseEvent* event_ );
-  virtual void mouseReleaseEvent( QMouseEvent* event_ );
-  virtual void wheelEvent( QWheelEvent* event_ );
-  virtual void mouseMoveEvent( QMouseEvent* event_ );
-  virtual void keyPressEvent( QKeyEvent* event_ );
+  void resizeGL( int width_ , int height_ ) override;
 
+  void mousePressEvent( QMouseEvent* event_ ) override;
+
+  void mouseReleaseEvent( QMouseEvent* event_ ) override;
+
+  void wheelEvent( QWheelEvent* event_ ) override;
+
+  void mouseMoveEvent( QMouseEvent* event_ ) override;
+
+  void keyPressEvent( QKeyEvent* event_ ) override;
+
+  std::shared_ptr< neurotessmesh::Scene > _scene;
   reto::OrbitalCameraController* _camera;
-  neurotessmesh::Scene* _scene;
 
-  int _mouseX, _mouseY;
-  bool _rotation, _translation;
+  int _mouseX , _mouseY;
+  bool _rotation , _translation;
   float _translationScale;
   float _rotationScale;
 
@@ -220,12 +243,10 @@ protected:
 
   QString _lastSavedFileName;
 
-  const static float _colorFactor;
-
 #ifdef NEUROTESSMESH_USE_LEXIS
-    zeroeq::Subscriber* _subscriber;
+  zeroeq::Subscriber* _subscriber;
 
-    std::thread* _subscriberThread;
+  std::thread* _subscriberThread;
 #endif
 
 };
diff --git a/neurotessmesh/Scene.cpp b/neurotessmesh/Scene.cpp
index ce2d386eb8a99aedf694c6437d68dcd4c31a81a4..66ce7f645a3592eb62b26699107537c0c2a3db46 100644
--- a/neurotessmesh/Scene.cpp
+++ b/neurotessmesh/Scene.cpp
@@ -21,37 +21,64 @@
  */
 #include "Scene.h"
 
+#include <QColor>
+#include <QDebug>
+#include <utility>
 #include <nlgenerator/nlgenerator.h>
 
+constexpr float COLOR_FACTOR = 1 / 255.0f;
+
 namespace neurotessmesh
 {
-
-  Scene::Scene( reto::OrbitalCameraController* camera_ )
+  Scene::Scene( reto::OrbitalCameraController* camera ,
+                nsol::DataSet* dataset
+#ifdef NEUROTESSMESH_USE_SIMIL
+                , simil::SpikesPlayer* player
+#endif
+                )
     : _mode( VISUALIZATION )
-    , _camera( camera_ )
-    , _animation{nullptr}
-    , _unselectedColor( 0.5f, 0.5f, 0.8f )
-    , _selectedColor( 0.8f, 0.5f, 0.5f )
+    , _camera( camera )
+    , _animation( nullptr )
+    , _renderer( new nlrender::Renderer( ))
+    , _unselectedColor( 0.5f , 0.5f , 0.8f )
+    , _selectedColor( 0.8f , 0.5f , 0.5f )
+    , _dataSet( dataset )
+#ifdef NEUROTESSMESH_USE_SIMIL
+    , _simulationPlayer( player )
+#endif
     , _paintUnselectedSoma( true )
     , _paintUnselectedNeurites( true )
     , _paintSelectedSoma( true )
     , _paintSelectedNeurites( true )
     , _editNeuron( nullptr )
     , _editMesh( nullptr )
-    , _boundingBox( Eigen::Vector3f::Zero( ), Eigen::Vector3f::Zero( ))
+    , _boundingBox( Eigen::Vector3f::Zero( ) , Eigen::Vector3f::Zero( ))
+    , _activationTimestamps( )
+    , _gradient( {{ 0.0f , Eigen::Vector3f{ 1.0f , 0.0f , 0.0f }} ,
+                  { 1.0f , Eigen::Vector3f{ 0.0f , 0.0f , 1.0f }}} )
+    , _delay( 20.0f )
   {
     _attribsFormat.resize( 3 );
-    _attribsFormat[0] = nlgeometry::TAttribType::POSITION;
-    _attribsFormat[1] = nlgeometry::TAttribType::CENTER;
-    _attribsFormat[2] = nlgeometry::TAttribType::TANGENT;
-    _renderer = new nlrender::Renderer( );
-    _dataSet = new nsol::DataSet( );
+    _attribsFormat[ 0 ] = nlgeometry::TAttribType::POSITION;
+    _attribsFormat[ 1 ] = nlgeometry::TAttribType::CENTER;
+    _attribsFormat[ 2 ] = nlgeometry::TAttribType::TANGENT;
+
+    generateMeshes( );
+    _boundingBox = computeBoundingBox( );
+    _camera->position( _boundingBox.center( ));
+    _camera->radius(
+      _boundingBox.radius( ) / std::sin( _camera->camera( )->fieldOfView( )));
+    conformRenderTuples( );
   }
 
-  Scene::~Scene( void )
+  Scene::~Scene( )
   {
-    if(_renderer) delete _renderer;
-    if(_dataSet)  delete _dataSet;
+    delete _renderer;
+    if ( _dataSet )
+    {
+      _dataSet->close( );
+    }
+    delete _dataSet;
   }
 
   void Scene::mode( const Scene::TSceneMode mode_ )
@@ -59,42 +86,96 @@ namespace neurotessmesh
     _mode = mode_;
   }
 
-  Scene::TSceneMode Scene::mode( void ) const
+  Scene::TSceneMode Scene::mode( ) const
   {
     return _mode;
   }
 
-  void Scene::render( void )
+  void Scene::update( )
   {
-    Eigen::Matrix4f projection( _camera->camera()->projectionMatrix( ));
-    _renderer->projectionMatrix( ) = projection;
-    Eigen::Matrix4f view( _camera->camera()->viewMatrix( ));
-    _renderer->viewMatrix( ) = view;
+#ifdef NEUROTESSMESH_USE_SIMIL
+    static float timeStamp = -1;
 
-    switch( _mode )
+    if ( _simulationPlayer != nullptr && _simulationPlayer->isPlaying( ))
     {
-    case VISUALIZATION:
-      _renderer->render( std::get<0>( _unselectedNeurons ),
-                         std::get<1>( _unselectedNeurons ),
-                         _unselectedColor , true, _paintUnselectedSoma,
-                         _paintUnselectedNeurites );
-      _renderer->render( std::get<0>( _selectedNeurons ),
-                         std::get<1>( _selectedNeurons ),
-                         _selectedColor , true, _paintSelectedSoma,
-                         _paintSelectedNeurites );
-      break;
-    case EDITION:
-      if ( isEditNeuronMeshExtraction( ))
+      const auto currentTime = _simulationPlayer->currentTime();
+
+      if(currentTime - timeStamp > std::numeric_limits<float>::epsilon())
       {
-        _renderer->render( _editMesh, _editNeuron->transform( ),
-                           _unselectedColor, true,
-                           _paintUnselectedSoma, _paintUnselectedNeurites );
+        timeStamp = currentTime;
+
+        auto spikes = _simulationPlayer->spikesNow( );
+
+        for ( auto spike = spikes.first; spike != spikes.second; ++spike )
+        {
+          auto neuronIt = _dataSet->neurons( ).find( spike->second );
+          if ( neuronIt == _dataSet->neurons( ).end( )) continue;
+          auto morphIt = _neuronMeshes.find( neuronIt->second->morphology( ));
+          if ( morphIt == _neuronMeshes.end( )) continue;
+
+          _activationTimestamps[ morphIt->second ] = spike->first;
+        }
       }
-      break;
+    }
+#endif
+  }
+
+  void Scene::render( )
+  {
+    Eigen::Matrix4f projection( _camera->camera( )->projectionMatrix( ));
+    _renderer->projectionMatrix( ) = projection;
+    Eigen::Matrix4f view( _camera->camera( )->viewMatrix( ));
+    _renderer->viewMatrix( ) = view;
+
+    switch ( _mode )
+    {
+      case VISUALIZATION:
+#ifdef NEUROTESSMESH_USE_SIMIL
+        if ( _simulationPlayer != nullptr )
+        {
+          const auto timeStamp = _simulationPlayer->currentTime();
+          _renderer->render( std::get< 0 >( _unselectedNeurons ) ,
+                             std::get< 1 >( _unselectedNeurons ) ,
+                             _unselectedColor,
+                             calculateUnselectedColors(timeStamp) , true ,
+                             _paintUnselectedSoma ,
+                             _paintUnselectedNeurites );
+        }
+        else
+        {
+          _renderer->render( std::get< 0 >( _unselectedNeurons ) ,
+                             std::get< 1 >( _unselectedNeurons ) ,
+                             _unselectedColor, true ,
+                             _paintUnselectedSoma ,
+                             _paintUnselectedNeurites );
+        }
+#else
+        _renderer->render( std::get< 0 >( _unselectedNeurons ) ,
+                           std::get< 1 >( _unselectedNeurons ) ,
+                           _unselectedColor, true ,
+                           _paintUnselectedSoma ,
+                           _paintUnselectedNeurites );
+#endif
+
+        _renderer->render( std::get< 0 >( _selectedNeurons ) ,
+                           std::get< 1 >( _selectedNeurons ) ,
+                           _selectedColor , true , _paintSelectedSoma ,
+                           _paintSelectedNeurites );
+        break;
+      case EDITION:
+        if ( isEditNeuronMeshExtraction( ))
+        {
+          _renderer->render( _editMesh , _editNeuron->transform( ) ,
+                             _unselectedColor , true ,
+                             _paintUnselectedSoma , _paintUnselectedNeurites );
+        }
+        break;
+      default:
+        assert( false );
     }
   }
 
-  void Scene::close( void )
+  void Scene::close( )
   {
     _editNeuron = nullptr;
     _editMesh = nullptr;
@@ -102,35 +183,44 @@ namespace neurotessmesh
       delete neuronMesh.second;
     _neuronMeshes.clear( );
 
-    std::get<0>( _unselectedNeurons ).clear( );
-    std::get<1>( _unselectedNeurons ).clear( );
-    std::get<0>( _selectedNeurons ).clear( );
-    std::get<1>( _selectedNeurons ).clear( );
+    std::get< 0 >( _unselectedNeurons ).clear( );
+    std::get< 1 >( _unselectedNeurons ).clear( );
+    std::get< 0 >( _selectedNeurons ).clear( );
+    std::get< 1 >( _selectedNeurons ).clear( );
 
     _dataSet->close( );
+#ifdef NEUROTESSMESH_USE_SIMIL
+    if ( _simulationPlayer )
+    {
+      delete _simulationPlayer;
+      _simulationPlayer = nullptr;
+    }
+#endif
     mode( Scene::VISUALIZATION );
   }
 
-  void Scene::home( void )
+  void Scene::home( )
   {
     mode( Scene::VISUALIZATION );
     _editNeuron = nullptr;
     _editMesh = nullptr;
 
-    const float FOV = sin( _camera->camera()->fieldOfView() );
-    const auto position = _boundingBox.center();
+    const float FOV = std::sin( _camera->camera( )->fieldOfView( ));
+    const auto position = _boundingBox.center( );
     const auto radius = _boundingBox.radius( ) / FOV;
 
-    animateCamera(position, radius);
+    animateCamera( position , radius );
   }
 
-  void Scene::cameraPosition(const Eigen::Vector3f &position, const float radius, const Eigen::Matrix3f &rotation)
+  void
+  Scene::cameraPosition( const Eigen::Vector3f& position , const float radius ,
+                         const Eigen::Matrix3f& rotation )
   {
-    animateCamera(position, radius, rotation, true);
+    animateCamera( position , radius , rotation , true );
   }
 
   nlgeometry::AxisAlignedBoundingBox Scene::computeBoundingBox(
-    std::vector< unsigned int > indices_ )
+    const std::vector< unsigned int >& indices_ )
   {
     Eigen::Array3f minimum =
       Eigen::Array3f::Constant( std::numeric_limits< float >::max( ));
@@ -149,20 +239,23 @@ namespace neurotessmesh
           auto radius = morphology->soma( )->maxRadius( );
           auto center = morphology->soma( )->center( );
           Eigen::Vector4f position = neuron->transform( ) *
-            nsol::Vec4f( center.x( ) , center.y( ), center.z( ), 1.0f );
-          Eigen::Array3f minVec( position.x( ) - radius, position.y( ) - radius,
+                                     nsol::Vec4f( center.x( ) , center.y( ) ,
+                                                  center.z( ) , 1.0f );
+          Eigen::Array3f minVec( position.x( ) - radius ,
+                                 position.y( ) - radius ,
                                  position.z( ) - radius );
-          Eigen::Array3f maxVec( position.x( ) + radius, position.y( ) + radius,
+          Eigen::Array3f maxVec( position.x( ) + radius ,
+                                 position.y( ) + radius ,
                                  position.z( ) + radius );
           minimum = minimum.min( minVec );
           maximum = maximum.max( maxVec );
         }
       }
     }
-    return nlgeometry::AxisAlignedBoundingBox( minimum, maximum );
+    return { minimum , maximum };
   }
 
-  nlgeometry::AxisAlignedBoundingBox Scene::computeBoundingBox( void )
+  nlgeometry::AxisAlignedBoundingBox Scene::computeBoundingBox( )
   {
     std::vector< unsigned int > indices;
     for ( const auto& neuronIt: _dataSet->neurons( ))
@@ -172,113 +265,33 @@ namespace neurotessmesh
     return computeBoundingBox( indices );
   }
 
-  void Scene::generateMeshes( void )
+  void Scene::generateMeshes( )
   {
     for ( auto neuronIt: _dataSet->neurons( ))
     {
       auto morphology = neuronIt.second->morphology( );
-      if(morphology)
+      if ( morphology )
       {
         if ( _neuronMeshes.find( morphology ) == _neuronMeshes.end( ))
         {
           auto simplifier = nsol::Simplifier::Instance( );
           simplifier->adaptSoma( morphology );
-          simplifier->simplify( morphology, nsol::Simplifier::DIST_NODES_RADIUS );
+          simplifier->simplify( morphology ,
+                                nsol::Simplifier::DIST_NODES_RADIUS );
 
           auto mesh = nlgenerator::MeshGenerator::generateMesh( morphology );
-          mesh->uploadGPU( _attribsFormat, nlgeometry::Facet::PATCHES );
+          mesh->uploadGPU( _attribsFormat , nlgeometry::Facet::PATCHES );
           mesh->clearCPUData( );
           _neuronMeshes[ morphology ] = mesh;
         }
       }
       else
       {
-        throw std::runtime_error("Unable to load neuron morphology");
+        throw std::runtime_error( "Unable to load neuron morphology" );
       }
     }
   }
 
-  std::string Scene::loadData( const std::string& fileName_,
-                        const TDataFileType fileType_,
-#ifdef NSOL_USE_BRION
-                        const std::string& target_
-#else
-                        const std::string& /*target_*/
-#endif
-    )
-  {
-    close( );
-    std::string errorString;
-    try{
-      switch( fileType_ )
-      {
-      case TDataFileType::BlueConfig:
-#ifdef NSOL_USE_BRION
-        _dataSet->loadBlueConfigHierarchy< nsol::Node,
-                                           nsol::NeuronMorphologySection,
-                                           nsol::Dendrite,
-                                           nsol::Axon,
-                                           nsol::Soma,
-                                           nsol::NeuronMorphology,
-                                           nsol::Neuron,
-                                           nsol::MiniColumn,
-                                           nsol::Column >( fileName_,
-                                                           target_ );
-
-        _dataSet->loadAllMorphologies< nsol::Node,
-                                       nsol::NeuronMorphologySection,
-                                       nsol::Dendrite,
-                                       nsol::Axon,
-                                       nsol::Soma,
-                                       nsol::NeuronMorphology,
-                                       nsol::Neuron,
-                                       nsol::MiniColumn,
-                                       nsol::Column >( );
-#else
-        std::cerr << "Error: Brion support not built-in" << std::endl;
-#endif
-        break;
-
-      case TDataFileType::SWC:
-        _dataSet->loadNeuronFromFile< nsol::Node,
-                                      nsol::NeuronMorphologySection,
-                                      nsol::Dendrite,
-                                      nsol::Axon,
-                                      nsol::Soma,
-                                      nsol::NeuronMorphology,
-                                      nsol::Neuron >( fileName_, 1 );
-        break;
-
-      case TDataFileType::NsolScene:
-        _dataSet->loadXmlScene< nsol::Node,
-                                nsol::NeuronMorphologySection,
-                                nsol::Dendrite,
-                                nsol::Axon,
-                                nsol::Soma,
-                                nsol::NeuronMorphology,
-                                nsol::Neuron >( fileName_ );
-        break;
-
-      default:
-        throw std::runtime_error( "Data file type not supported" );
-      }
-
-      generateMeshes( );
-      _boundingBox = computeBoundingBox( );
-      _camera->position( _boundingBox.center( ));
-      _camera->radius( _boundingBox.radius( ) / sin( _camera->camera()->fieldOfView()));
-      conformRenderTuples( );
-    }
-    catch( const std::exception &excep )
-    {
-      std::cerr << "Error: can't load file: " << fileName_ << std::endl;
-      std::cerr << excep.what( ) << std::endl;
-      errorString = std::string(excep.what());
-    }
-
-    return errorString;
-  }
-
   void Scene::paintUnselectedSoma( bool paint_ )
   {
     _paintUnselectedSoma = paint_;
@@ -303,24 +316,45 @@ namespace neurotessmesh
 
   void Scene::unselectedNeuronColor( Eigen::Vector3f color_ )
   {
-    _unselectedColor = color_;
+    _unselectedColor = std::move( color_ );
+
+    _gradient[1] = { 1.0f , { _unselectedColor[0], _unselectedColor[1], _unselectedColor[2] } };
+  }
+
+  void Scene::unselectedNeuronColor( const QColor& color_ )
+  {
+    unselectedNeuronColor( Eigen::Vector3f(
+      float( color_.red( )) * COLOR_FACTOR ,
+      float( color_.green( )) * COLOR_FACTOR ,
+      float( color_.blue( )) * COLOR_FACTOR
+    ));
   }
 
   void Scene::selectedNeuronColor( Eigen::Vector3f color_ )
   {
-    _selectedColor = color_;
+    _selectedColor = std::move( color_ );
+  }
+
+  void Scene::selectedNeuronColor( const QColor& color_ )
+  {
+    selectedNeuronColor( Eigen::Vector3f(
+      float( color_.red( )) * COLOR_FACTOR ,
+      float( color_.green( )) * COLOR_FACTOR ,
+      float( color_.blue( )) * COLOR_FACTOR
+    ));
   }
 
   void Scene::levelOfDetail( float lod_ )
   {
-    if(_renderer)
+    if ( _renderer )
       _renderer->lod( ) = lod_;
   }
 
   void Scene::maximumDistance( float maximumDistance_ )
   {
-    if(_renderer)
-      _renderer->maximumDistance( ) = maximumDistance_ * _camera->camera()->farPlane( );
+    if ( _renderer )
+      _renderer->maximumDistance( ) =
+        maximumDistance_ * _camera->camera( )->farPlane( );
   }
 
   void Scene::subdivisionCriteria(
@@ -329,7 +363,7 @@ namespace neurotessmesh
     _renderer->tessCriteria( subdivisionCriteria_ );
   }
 
-  std::vector< unsigned int > Scene::neuronIndices( void )
+  std::vector< unsigned int > Scene::neuronIndices( )
   {
     std::vector< unsigned int > indices;
 
@@ -348,14 +382,15 @@ namespace neurotessmesh
       _editNeuron = neuronIt->second;
       if ( _editNeuron )
       {
-        auto meshIt = _neuronMeshes.find( _editNeuron->morphology( ) );
+        auto meshIt = _neuronMeshes.find( _editNeuron->morphology( ));
         if ( meshIt != _neuronMeshes.end( ))
         {
           _editMesh = meshIt->second;
           mode( Scene::EDITION );
-          std::vector< unsigned int >indices = { id_ };
+          std::vector< unsigned int > indices = { id_ };
           auto aabb = computeBoundingBox( indices );
-          animateCamera(aabb.center(),  aabb.radius( ) / sin( _camera->camera()->fieldOfView()));
+          animateCamera( aabb.center( ) , aabb.radius( ) / std::sin(
+            _camera->camera( )->fieldOfView( )));
         }
         else
           _editNeuron = nullptr;
@@ -363,7 +398,7 @@ namespace neurotessmesh
     }
   }
 
-  unsigned int Scene::numEditMorphologyNeurites( void ) const
+  unsigned int Scene::numEditMorphologyNeurites( ) const
   {
     if ( _editNeuron )
       return static_cast<unsigned int>(_editNeuron->morphology( )->neurites( ).size( ));
@@ -371,26 +406,26 @@ namespace neurotessmesh
   }
 
   void Scene::regenerateEditNeuronMesh(
-    const float alphaRadius_,
+    const float alphaRadius_ ,
     const std::vector< float >& alphaNeurites_ )
   {
-    if (  isEditNeuronMeshExtraction( ))
+    if ( isEditNeuronMeshExtraction( ))
     {
       auto mesh = nlgenerator::MeshGenerator::generateMesh(
-        _editNeuron->morphology( ), alphaRadius_, alphaNeurites_ );
+        _editNeuron->morphology( ) , alphaRadius_ , alphaNeurites_ );
       if ( mesh )
       {
-        mesh->uploadGPU( _attribsFormat, nlgeometry::Facet::PATCHES );
+        mesh->uploadGPU( _attribsFormat , nlgeometry::Facet::PATCHES );
         mesh->clearCPUData( );
         delete _editMesh;
         _editMesh = mesh;
-        _neuronMeshes[ _editNeuron->morphology( )] = mesh;
+        _neuronMeshes[ _editNeuron->morphology( ) ] = mesh;
         conformRenderTuples( );
       }
     }
   }
 
-  bool Scene::isEditNeuronMeshExtraction( void )
+  bool Scene::isEditNeuronMeshExtraction( )
   {
     return ( _editNeuron != nullptr ) && ( _editMesh != nullptr );
   }
@@ -398,13 +433,13 @@ namespace neurotessmesh
   void Scene::extractEditNeuronMesh( const std::string& path_ )
   {
     auto extractedMesh = _renderer->extract(
-      _editMesh, _editNeuron->transform( ), _paintUnselectedSoma,
+      _editMesh , _editNeuron->transform( ) , _paintUnselectedSoma ,
       _paintUnselectedNeurites );
-    nlgeometry::ObjWriter::writeMesh( extractedMesh, path_ );
+    nlgeometry::ObjWriter::writeMesh( extractedMesh , path_ );
     delete extractedMesh;
   }
 
-  void Scene::conformRenderTuples( void )
+  void Scene::conformRenderTuples( )
   {
     nlgeometry::Meshes unselectedMeshes;
     std::vector< Eigen::Matrix4f > unselectedModels;
@@ -428,56 +463,118 @@ namespace neurotessmesh
         }
       }
     }
-    _unselectedNeurons = std::make_tuple( unselectedMeshes, unselectedModels );
-    _selectedNeurons = std::make_tuple( selectedMeshes, selectedModels );
+    _unselectedNeurons = std::make_tuple( unselectedMeshes , unselectedModels );
+    _selectedNeurons = std::make_tuple( selectedMeshes , selectedModels );
   }
 
   void Scene::changeSelectedIndices(
     const std::vector< unsigned int >& indices_ )
   {
     _selectedIndices = std::set< unsigned int >(
-      indices_.begin( ), indices_.end( ));
+      indices_.begin( ) , indices_.end( ));
     conformRenderTuples( );
   }
 
   void Scene::focusOnIndices( const std::vector< unsigned int >& indices_ )
   {
-    if ( indices_.size( ) > 0 )
+    if ( !indices_.empty( ))
     {
       auto aabb = computeBoundingBox( indices_ );
-      animateCamera( aabb.center( ), aabb.radius( ) / sin( _camera->camera()->fieldOfView()));
+      animateCamera( aabb.center( ) ,
+                     aabb.radius( ) /
+                     std::sin( _camera->camera( )->fieldOfView( )));
     }
     else
     {
-      animateCamera( _boundingBox.center( ),  _boundingBox.radius( ) / sin( _camera->camera()->fieldOfView()));
+      animateCamera( _boundingBox.center( ) , _boundingBox.radius( ) / std::sin(
+        _camera->camera( )->fieldOfView( )));
     }
   }
 
-  void Scene::animateCamera(const Eigen::Vector3f &position, const float radius, const Eigen::Matrix3f &rotation,
-                              bool rotAnimation)
+  void
+  Scene::animateCamera( const Eigen::Vector3f& position , const float radius ,
+                        const Eigen::Matrix3f& rotation ,
+                        bool rotAnimation )
   {
-    if(_camera->isAniming())
+    if ( _camera->isAniming( ))
     {
-      _camera->stopAnim();
-      if(_animation) delete _animation;
+      _camera->stopAnim( );
+      delete _animation;
     }
 
     constexpr float CAMERA_ANIMATION_DURATION = 2.f;
-    const auto rotInterpolation = rotAnimation ? reto::CameraAnimation::LINEAR : reto::CameraAnimation::NONE;
+    const auto rotInterpolation = rotAnimation ? reto::CameraAnimation::LINEAR
+                                               : reto::CameraAnimation::NONE;
 
-    _animation = new reto::CameraAnimation(reto::CameraAnimation::LINEAR,
-                                           rotInterpolation,
-                                           reto::CameraAnimation::LINEAR);
+    _animation = new reto::CameraAnimation( reto::CameraAnimation::LINEAR ,
+                                            rotInterpolation ,
+                                            reto::CameraAnimation::LINEAR );
 
-    auto startCam = new reto::KeyCamera(0.f, _camera->position(),
-                                             _camera->rotation(),
-                                             _camera->radius());
-    _animation->addKeyCamera(startCam);
+    auto startCam = new reto::KeyCamera( 0.f , _camera->position( ) ,
+                                         _camera->rotation( ) ,
+                                         _camera->radius( ));
+    _animation->addKeyCamera( startCam );
 
-    auto targetCam = new reto::KeyCamera(CAMERA_ANIMATION_DURATION,
-                                         position, rotation, radius);
-    _animation->addKeyCamera(targetCam);
+    auto targetCam = new reto::KeyCamera( CAMERA_ANIMATION_DURATION ,
+                                          position , rotation , radius );
+    _animation->addKeyCamera( targetCam );
 
-    _camera->startAnim(_animation);
+    _camera->startAnim( _animation );
+  }
+
+  std::vector< Eigen::Vector3f > Scene::calculateUnselectedColors( float timestamp )
+  {
+    auto calculateGradientColor = [ ]( const Gradient& gradient , float t )
+    {
+      if ( gradient.empty( )) return Eigen::Vector3f( 1.0f , 0.0f , 1.0f );
+      // Return last if t < 0.
+      if ( t < 0 ) return gradient[ gradient.size( ) - 1 ].second;
+      int size = static_cast<int>(gradient.size( ));
+      int first = size - 1;
+      for ( int i = 0; i < size; i++ )
+      {
+        if ( gradient[ i ].first > t )
+        {
+          first = i - 1;
+          break;
+        }
+      }
+
+      if ( first == -1 ) return gradient[ 0 ].second;
+      if ( first == size - 1 ) return gradient[ first ].second;
+
+      float start = gradient[ first ].first;
+      float end = gradient[ first + 1 ].first;
+      float normalizedT = ( t - start ) / ( end - start );
+
+      const Eigen::Vector3f mixedColor = (gradient[ first ].second * (1. - normalizedT)) + (gradient[ first + 1 ].second * normalizedT);
+      return mixedColor;
+    };
+
+    auto& neurons = std::get< 0 >( _unselectedNeurons );
+
+    auto colors = std::vector< Eigen::Vector3f >(neurons.size(), _unselectedColor);
+    if(timestamp < 0
+#ifdef NEUROTESSMESH_USE_SIMIL
+        || !_simulationPlayer
+#endif
+        ) return colors;
+
+    uint32_t index = 0;
+    for ( const auto& mesh: neurons )
+    {
+      auto it = _activationTimestamps.find( mesh );
+      if ( it == _activationTimestamps.end( ))
+      {
+        colors[ index ] = calculateGradientColor( _gradient , INFINITY);
+      }
+      else
+      {
+        colors[ index ] = calculateGradientColor( _gradient ,
+                                                 ( timestamp - it->second ) / _delay );
+      }
+      ++index;
+    }
+    return colors;
   }
 }
diff --git a/neurotessmesh/Scene.h b/neurotessmesh/Scene.h
index 640c037faaa58fee2f0a528222b35653830f8570..ed64517cdd9069af528646ddf6755cb85bf2b9e8 100644
--- a/neurotessmesh/Scene.h
+++ b/neurotessmesh/Scene.h
@@ -28,6 +28,14 @@
 #include <nlrender/nlrender.h>
 
 #include <neurotessmesh/api.h>
+#ifdef NEUROTESSMESH_USE_SIMIL
+  #include <simil/simil.h>
+#endif
+#include <QPalette>
+
+class QColor;
+
+typedef std::vector< std::pair< float , Eigen::Vector3f >> Gradient;
 
 namespace neurotessmesh
 {
@@ -40,69 +48,80 @@ namespace neurotessmesh
 
     typedef enum
     {
-      VISUALIZATION = 0,
+      VISUALIZATION = 0 ,
       EDITION
-    }TSceneMode;
+    } TSceneMode;
 
     typedef enum
     {
-      BlueConfig,
-      SWC,
+      BlueConfig ,
+      SWC ,
       NsolScene
     } TDataFileType;
 
-    typedef std::tuple< nlgeometry::Meshes, std::vector< Eigen::Matrix4f >>
+    typedef std::tuple< nlgeometry::Meshes , std::vector< Eigen::Matrix4f >>
       NeuronMeshes;
 
     /**
      * Default constructor
      */
     NEUROTESSMESH_API
-    Scene( reto::OrbitalCameraController* camera_ );
+    explicit Scene( reto::OrbitalCameraController* camera = nullptr,
+                    nsol::DataSet* dataset = nullptr
+#ifdef NEUROTESSMESH_USE_SIMIL
+                    , simil::SpikesPlayer* player = nullptr
+#endif
+                    );
 
     /**
      * Default destructor
      */
     NEUROTESSMESH_API
-    ~Scene( void );
+    ~Scene( );
 
     /**
      * Method to set the scene mode
      * @param mode_ new scnene mode
      */
     NEUROTESSMESH_API
-    void mode( const TSceneMode mode_ );
+    void mode( TSceneMode mode_ );
 
     /**
      * Method to get the scene mode
      * @return the current scene mode
      */
     NEUROTESSMESH_API
-    TSceneMode mode( void ) const;
+    TSceneMode mode( ) const;
+
+    /**
+     * This method updates the scene with the current spikes.
+     */
+    void update();
 
     /**
-     * Method to renderize the scene based on the current mode
+     * Method to rendering the scene based on the current mode
      */
     NEUROTESSMESH_API
-    void render( void );
+    void render( );
 
     /**
      * Method to close and deleted data from dataSet
      */
     NEUROTESSMESH_API
-    void close( void );
+    void close( );
 
     /**
      * Method to set the scene params to default
      */
     NEUROTESSMESH_API
-    void home( void );
+    void home( );
 
     /**
      * Method to animate the camera to the given position, radius and rotation
      */
     NEUROTESSMESH_API
-    void cameraPosition(const Eigen::Vector3f &position, const float radius, const Eigen::Matrix3f &rotation);
+    void cameraPosition( const Eigen::Vector3f& position , float radius ,
+                         const Eigen::Matrix3f& rotation );
 
     /**
      * Method to compute axis align bounding box
@@ -111,32 +130,20 @@ namespace neurotessmesh
      */
     NEUROTESSMESH_API
     nlgeometry::AxisAlignedBoundingBox
-    computeBoundingBox( std::vector< unsigned int > indices_ );
+    computeBoundingBox( const std::vector< unsigned int >& indices_ );
 
     /**
      * Method to compute axis align bounding box
      * @return axis align bounding box for all the current neurons
      */
     NEUROTESSMESH_API
-    nlgeometry::AxisAlignedBoundingBox computeBoundingBox( void );
+    nlgeometry::AxisAlignedBoundingBox computeBoundingBox( );
 
     /**
      * Method to generate the meshes associated to the loaded neurons
      */
     NEUROTESSMESH_API
-    void generateMeshes( void );
-
-    /**
-     * Method to load neurons data returns an empty string on success
-     * or an error string otherwise.
-     * @param fileName path to the file
-     * @param fileType type of file
-     * @param target to load, specific param to BlueConfig data
-     */
-    NEUROTESSMESH_API
-    std::string loadData( const std::string& fileName_,
-                   const TDataFileType fileType_,
-                   const std::string& target_ = std::string( "" ));
+    void generateMeshes( );
 
     /**
      * Method to set the render options of unseletected and selected neurons
@@ -144,10 +151,13 @@ namespace neurotessmesh
      */
     NEUROTESSMESH_API
     void paintUnselectedSoma( bool paint_ );
+
     NEUROTESSMESH_API
     void paintUnselectedNeurites( bool paint_ );
+
     NEUROTESSMESH_API
     void paintSelectedSoma( bool paint_ );
+
     NEUROTESSMESH_API
     void paintSelectedNeurites( bool paint_ );
 
@@ -158,6 +168,13 @@ namespace neurotessmesh
     NEUROTESSMESH_API
     void unselectedNeuronColor( Eigen::Vector3f color_ );
 
+    /**
+     * Method to change the unselected neuron color
+     * @param color_ color of the unselected neuron
+     */
+    NEUROTESSMESH_API
+    void unselectedNeuronColor( const QColor& color_ );
+
     /**
      * Method to change the selected neuron color
      * @param color_ color of the selected neuron
@@ -165,6 +182,13 @@ namespace neurotessmesh
     NEUROTESSMESH_API
     void selectedNeuronColor( Eigen::Vector3f color_ );
 
+    /**
+     * Method to change the selected neuron color
+     * @param color_ color of the selected neuron
+     */
+    NEUROTESSMESH_API
+    void selectedNeuronColor( const QColor& color_ );
+
     /**
      * Method to set the scene level of subdivision
      * @param lod_ scene level of detail
@@ -188,32 +212,33 @@ namespace neurotessmesh
                               subdivisionCriteria_ );
 
     NEUROTESSMESH_API
-    std::vector< unsigned int > neuronIndices( void );
+    std::vector< unsigned int > neuronIndices( );
 
     NEUROTESSMESH_API
     void setNeuronToEdit( unsigned int id_ );
 
     NEUROTESSMESH_API
-    unsigned int numEditMorphologyNeurites( void ) const;
+    unsigned int numEditMorphologyNeurites( ) const;
 
     NEUROTESSMESH_API
-    void regenerateEditNeuronMesh( const float alphaRadius,
+    void regenerateEditNeuronMesh( float alphaRadius ,
                                    const std::vector< float >& alphaNeurites_ );
 
     NEUROTESSMESH_API
-    bool isEditNeuronMeshExtraction( void );
+    bool isEditNeuronMeshExtraction( );
 
     NEUROTESSMESH_API
     void extractEditNeuronMesh( const std::string& path_ );
 
     NEUROTESSMESH_API
-    void conformRenderTuples( void );
+    void conformRenderTuples( );
 
     NEUROTESSMESH_API
     void changeSelectedIndices( const std::vector< unsigned int >& indices_ );
 
     NEUROTESSMESH_API
     void focusOnIndices( const std::vector< unsigned int >& indices_ );
+
   protected:
     /** \brief Animates the camera to the given position, radius and rotation.
      * \param[in] position Focus position.
@@ -222,17 +247,23 @@ namespace neurotessmesh
      * \param[in] rotAnimation true to animate rotation and false otherwise.
      *
      */
-    void animateCamera(const Eigen::Vector3f &position,
-                       const float radius,
-                       const Eigen::Matrix3f &rotation = Eigen::Matrix3f::Zero(),
-                       bool rotAnimation = false);
+    void animateCamera( const Eigen::Vector3f& position ,
+                        float radius ,
+                        const Eigen::Matrix3f& rotation = Eigen::Matrix3f::Zero( ) ,
+                        bool rotAnimation = false );
+
+    /** \brief Updates the color and time array of the unselected neurons.
+     * \param[in] timestamp Current player time.
+     *
+     */
+    std::vector< Eigen::Vector3f > calculateUnselectedColors( float timestamp );
 
     //! Scene mode
     TSceneMode _mode;
 
     //! Scene camera
     reto::OrbitalCameraController* _camera;
-    reto::CameraAnimation *_animation;
+    reto::CameraAnimation* _animation;
 
     //! Neurolots engine to render morphological data
     nlrender::Renderer* _renderer;
@@ -249,9 +280,14 @@ namespace neurotessmesh
     //! Nsol DataSet, contains neurons
     nsol::DataSet* _dataSet;
 
+#ifdef NEUROTESSMESH_USE_SIMIL
+    // SimIL spikes data.
+    simil::SpikesPlayer* _simulationPlayer;
+#endif
+
     //! Neuron Meshes
-    std::unordered_map< nsol::MorphologyPtr, nlgeometry::MeshPtr >
-    _neuronMeshes;
+    std::unordered_map< nsol::MorphologyPtr , nlgeometry::MeshPtr >
+      _neuronMeshes;
 
     //! Unselected neuron meshes
     NeuronMeshes _unselectedNeurons;
@@ -276,6 +312,11 @@ namespace neurotessmesh
 
     //! Scene bonunding box
     nlgeometry::AxisAlignedBoundingBox _boundingBox;
+
+    //! Activation timestamps.
+    std::unordered_map< nlgeometry::MeshPtr , float > _activationTimestamps;
+    Gradient _gradient;
+    float _delay;
   };
 
 }
diff --git a/neurotessmesh/mainwindow.ui b/neurotessmesh/mainwindow.ui
index 68ed7db7749586dccddf843f88f24f11955a4cc7..9f16aca12530b7ea84b70d02e76bccc2c9493521 100644
--- a/neurotessmesh/mainwindow.ui
+++ b/neurotessmesh/mainwindow.ui
@@ -59,6 +59,7 @@
     <addaction name="actionShowFPSOnIdleUpdate"/>
     <addaction name="actionWireframe"/>
     <addaction name="actionRenderOptions"/>
+    <addaction name="actionSimulation_player_options"/>
     <addaction name="actionEditSave"/>
     <addaction name="actionConfiguration"/>
    </widget>
@@ -94,6 +95,7 @@
    <addaction name="actionWireframe"/>
    <addaction name="actionCloseData"/>
    <addaction name="actionRenderOptions"/>
+   <addaction name="actionSimulation_player_options"/>
    <addaction name="separator"/>
   </widget>
   <action name="actionQuit">
@@ -351,6 +353,21 @@
     <string>Camera positions list.</string>
    </property>
   </action>
+  <action name="actionSimulation_player_options">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/icons/rsc/play.svg</normaloff>:/icons/rsc/play.svg</iconset>
+   </property>
+   <property name="text">
+    <string>Simulation player options</string>
+   </property>
+   <property name="toolTip">
+    <string>Shows/hides the player options.</string>
+   </property>
+  </action>
  </widget>
  <resources>
   <include location="resources.qrc"/>
diff --git a/neurotessmesh/neurotessmesh.cpp b/neurotessmesh/neurotessmesh.cpp
index bc39a29a13c02f9230378d15107113b398185062..c191e78d11f7abfb8fda5215b9f2f4a72331a50f 100644
--- a/neurotessmesh/neurotessmesh.cpp
+++ b/neurotessmesh/neurotessmesh.cpp
@@ -10,13 +10,16 @@
 
 #include <QApplication>
 #include <QDir>
-#include "MainWindow.h"
-#include <QDebug>
 #include <QOpenGLWidget>
 #include <QErrorMessage>
 
+#include "MainWindow.h"
+
 #include <neurotessmesh/version.h>
+
+#include <cstring>
 #include <sstream>
+#include <iostream>
 #include <locale>
 
 #define GL_MINIMUM_REQUIRED_MAJOR 4
@@ -25,7 +28,7 @@
 
 bool setFormat( int ctxOpenGLMajor, int ctxOpenGLMinor,
                 int ctxOpenGLSamples, int ctxOpenGLVSync );
-void usageMessage(  char* progName );
+void usageMessage(const char* progName);
 void dumpVersion( void );
 bool atLeastTwo( bool a, bool b, bool c );
 
@@ -41,6 +44,8 @@ int main( int argc, char** argv )
 
   QApplication application(argc,argv);
 
+  const auto programName = argv[0];
+
   std::string blueConfig;
   std::string swcFile;
   std::string sceneFile;
@@ -61,7 +66,7 @@ int main( int argc, char** argv )
     if ( std::strcmp( argv[i], "--help" ) == 0 ||
          std::strcmp( argv[i], "-h" ) == 0 )
     {
-      usageMessage( argv[0] );
+      usageMessage(programName);
       return 0;
     }
     if ( std::strcmp( argv[i], "--version" ) == 0 )
@@ -88,7 +93,7 @@ int main( int argc, char** argv )
         blueConfig = std::string( argv[ i ]);
       }
       else
-        usageMessage( argv[0] );
+        usageMessage(programName);
 
     }
     if( std::strcmp( argv[ i ], "-swc" ) == 0 )
@@ -98,7 +103,7 @@ int main( int argc, char** argv )
         swcFile = std::string( argv[ i ]);
       }
       else
-        usageMessage( argv[0] );
+        usageMessage(programName);
 
     }
     if( std::strcmp( argv[ i ], "-xml" ) == 0 )
@@ -108,7 +113,7 @@ int main( int argc, char** argv )
         sceneFile = std::string( argv[ i ]);
       }
       else
-        usageMessage( argv[0] );
+        usageMessage(programName);
 
     }
     if( std::strcmp( argv[ i ], "-target" ) == 0 )
@@ -118,7 +123,7 @@ int main( int argc, char** argv )
         target = std::string( argv[ i ]);
       }
       else
-        usageMessage( argv[0] );
+        usageMessage(programName);
 
     }
     if ( strcmp( argv[i], "--fullscreen" ) == 0 ||
@@ -136,7 +141,7 @@ int main( int argc, char** argv )
     {
       initWindowSize = true;
       if ( i + 2 >= argc )
-        usageMessage( argv[0] );
+        usageMessage(programName);
       initWindowWidth = atoi( argv[ ++i ] );
       initWindowHeight = atoi( argv[ ++i ] );
 
@@ -145,7 +150,7 @@ int main( int argc, char** argv )
          strcmp( argv[i],"-cv") == 0 )
     {
       if ( i + 2 >= argc )
-        usageMessage( argv[0] );
+        usageMessage(programName);
       ctxOpenGLMajor = atoi( argv[ ++i ] );
       ctxOpenGLMinor = atoi( argv[ ++i ] );
 
@@ -154,7 +159,7 @@ int main( int argc, char** argv )
          strcmp( argv[i],"-s") == 0 )
     {
       if ( i + 1 >= argc )
-        usageMessage( argv[0] );
+        usageMessage(programName);
       ctxOpenGLSamples = atoi( argv[ ++i ] );
 
     }
@@ -189,7 +194,7 @@ int main( int argc, char** argv )
     {
       std::cerr << "Error: -swc, -xml and -bc options are exclusive"
                 << std::endl;
-      usageMessage( argv[0] );
+      usageMessage(programName);
     }
 
     if ( !blueConfig.empty() )
@@ -223,7 +228,7 @@ int main( int argc, char** argv )
   return returnVal;
 }
 
-void usageMessage( char* progName )
+void usageMessage(const char* progName)
 {
   std::cerr << std::endl
             << "Usage: "
diff --git a/neurotessmesh/resources.qrc b/neurotessmesh/resources.qrc
index 2aa7cbf5663bb4c692efc5c3033dcad9ae612463..535db9d3199d79664d5887f074fd72bcf6c4c016 100644
--- a/neurotessmesh/resources.qrc
+++ b/neurotessmesh/resources.qrc
@@ -14,5 +14,6 @@
     <file>rsc/settings.png</file>
     <file>rsc/neurotessmesh.png</file>
     <file>rsc/eye.svg</file>
+    <file>rsc/play.svg</file>
   </qresource>
 </RCC>
diff --git a/neurotessmesh/rsc/play.svg b/neurotessmesh/rsc/play.svg
new file mode 100644
index 0000000000000000000000000000000000000000..35d12e78d473858a7c89724e22696d4047b973e5
--- /dev/null
+++ b/neurotessmesh/rsc/play.svg
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48"
+   height="48"
+   id="svg7854"
+   sodipodi:version="0.32"
+   inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+   version="1.0"
+   sodipodi:docname="play.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/home/lapo/Desktop/media-icons.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs7856">
+    <linearGradient
+       id="linearGradient7577">
+      <stop
+         style="stop-color:#000000;stop-opacity:0.3137255;"
+         offset="0"
+         id="stop7579" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="1"
+         id="stop7581" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7305">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0"
+         id="stop7307" />
+      <stop
+         id="stop7313"
+         offset="0.20971029"
+         style="stop-color:#ffffff;stop-opacity:0;" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.81065089;"
+         offset="0.34936365"
+         id="stop7329" />
+      <stop
+         id="stop7321"
+         offset="0.42850056"
+         style="stop-color:#ffffff;stop-opacity:0;" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0.52134049"
+         id="stop7323" />
+      <stop
+         id="stop7317"
+         offset="0.55746967"
+         style="stop-color:#ffffff;stop-opacity:0;" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.56804734;"
+         offset="0.71001518"
+         id="stop7319" />
+      <stop
+         id="stop7416"
+         offset="0.74394959"
+         style="stop-color:#ffffff;stop-opacity:0;" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1"
+         id="stop7309" />
+    </linearGradient>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#afafaf"
+     borderopacity="1"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="11.313708"
+     inkscape:cx="11.71144"
+     inkscape:cy="30.327794"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="48px"
+     height="48px"
+     inkscape:showpageshadow="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1018"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     showgrid="false"
+     inkscape:grid-points="true"
+     showborder="true"
+     showguides="false"
+     inkscape:guide-bbox="true"
+     borderlayer="true"
+     inkscape:document-rotation="0"
+     inkscape:window-maximized="1">
+    <sodipodi:guide
+       orientation="horizontal"
+       position="13.125"
+       id="guide7377" />
+    <sodipodi:guide
+       orientation="horizontal"
+       position="5.4800776"
+       id="guide7379" />
+    <sodipodi:guide
+       orientation="horizontal"
+       position="35"
+       id="guide7492" />
+    <sodipodi:guide
+       orientation="horizontal"
+       position="48"
+       id="guide7046" />
+    <sodipodi:guide
+       orientation="horizontal"
+       position="-17.5"
+       id="guide7233" />
+    <sodipodi:guide
+       orientation="horizontal"
+       position="-29"
+       id="guide7235" />
+    <sodipodi:guide
+       orientation="horizontal"
+       position="22.097087"
+       id="guide7556" />
+    <sodipodi:guide
+       orientation="vertical"
+       position="-76.125"
+       id="guide7644" />
+    <sodipodi:guide
+       orientation="vertical"
+       position="-26.125"
+       id="guide7646" />
+    <sodipodi:guide
+       orientation="vertical"
+       position="24"
+       id="guide7648" />
+    <sodipodi:guide
+       orientation="vertical"
+       position="-125.28125"
+       id="guide7665" />
+    <sodipodi:guide
+       orientation="vertical"
+       position="-175.125"
+       id="guide7667" />
+    <sodipodi:guide
+       orientation="vertical"
+       position="-225.83223"
+       id="guide7685" />
+    <sodipodi:guide
+       orientation="vertical"
+       position="-326.06462"
+       id="guide7695" />
+    <inkscape:grid
+       id="GridFromPre046Settings"
+       type="xygrid"
+       originx="0"
+       originy="0"
+       spacingx="0.5"
+       spacingy="0.5"
+       color="#3f3fff"
+       empcolor="#3f3fff"
+       opacity="0.15"
+       empopacity="0.38"
+       empspacing="2" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7859">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Lapo Calamandrei</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:source />
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+        <dc:title>Play</dc:title>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>play</rdf:li>
+            <rdf:li>playback</rdf:li>
+            <rdf:li>start</rdf:li>
+            <rdf:li>begin</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Reproduction" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Distribution" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Notice" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/ShareAlike" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/SourceCode" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       id="path7671"
+       style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0.7;stroke-opacity:1"
+       inkscape:original="M -186.5 10.5 L -186.5 37.5 L -163.5 24 L -186.5 10.5 z "
+       inkscape:radius="1.5026019"
+       sodipodi:type="inkscape:offset"
+       d="M -186.52734,8.9980469 A 1.5027521,1.5027521 0 0 0 -188.00195,10.5 v 27 a 1.5027521,1.5027521 0 0 0 2.26172,1.294922 l 23,-13.5 a 1.5027521,1.5027521 0 0 0 0,-2.589844 l -23,-13.4999999 a 1.5027521,1.5027521 0 0 0 -0.78711,-0.2070312 z"
+       transform="translate(200)" />
+  </g>
+</svg>