diff --git a/src/libRender/RadiumNBR/Passes/WireframePass.cpp b/src/libRender/RadiumNBR/Passes/WireframePass.cpp
index 295ccb0dd0150aa0177fce81b174b6b239eecfbf..6fca85c6d3268c63d74b8b1c4b784978dfdca218 100644
--- a/src/libRender/RadiumNBR/Passes/WireframePass.cpp
+++ b/src/libRender/RadiumNBR/Passes/WireframePass.cpp
@@ -13,10 +13,8 @@ using namespace Ra::Core::Utils; // log
 
 #include <globjects/Framebuffer.h>
 
-#ifdef ADVANCED_WIREFRAME
-#    include <Engine/Data/Mesh.hpp>
-#    include <Engine/Data/ViewingParameters.hpp>
-#endif
+#include <Engine/Data/Mesh.hpp>
+#include <Engine/Data/ViewingParameters.hpp>
 
 namespace RadiumNBR {
 using namespace gl;
@@ -47,96 +45,102 @@ void WireframePass::setOutput( const SharedTextures& colorBuffer ) {
 }
 
 bool WireframePass::update() {
-#ifdef ADVANCED_WIREFRAME
-    // build the wireframe representation of all drawn objects
-    m_wireframes.clear();
-    for ( const auto& ro : *m_objectsToRender )
+    // keep the wireframe cache coherent with the scene
+    if ( m_wireframes.size() > m_objectsToRender->size() ) { m_wireframes.clear(); };
+    return true;
+}
+
+template <typename IndexContainerType>
+void computeIndices( Ra::Core::Geometry::LineMesh::IndexContainerType& indices,
+                     IndexContainerType& other ) {
+
+    for ( const auto& index : other )
     {
-        std::shared_ptr<Ra::Engine::Data::LineMesh> disp;
-
-        using trimesh  = Ra::Engine::Data::IndexedGeometry<Ra::Core::Geometry::TriangleMesh>;
-        using polymesh = Ra::Engine::Data::IndexedGeometry<Ra::Core::Geometry::PolyMesh>;
-
-        auto displayable = ro->getMesh();
-        auto tm          = std::dynamic_pointer_cast<trimesh>( displayable );
-        auto tp          = std::dynamic_pointer_cast<polymesh>( displayable );
-        bool drawable;
-        Ra::Core::Geometry::LineMesh lines;
-        Ra::Core::Geometry::LineMesh::IndexContainerType indices;
-        if ( tm )
+        auto s = index.size();
+        for ( unsigned int i = 0; i < s; ++i )
         {
-            drawable = tm->getRenderMode() ==
-                       Ra::Engine::Data::AttribArrayDisplayable::MeshRenderMode::RM_TRIANGLES;
-            if ( drawable )
-            {
-                lines.setVertices( tm->getCoreGeometry().vertices() );
-                for ( const auto& index : tm->getCoreGeometry().getIndices() )
-                {
-                    for ( unsigned int i = 0; i < 3; ++i )
-                    {
-                        int i1 = index[i];
-                        int i2 = index[( i + 1 ) % 3];
-                        if ( i1 > i2 ) std::swap( i1, i2 );
-                        indices.emplace_back( i1, i2 );
-                    }
-                }
-            }
+            int i1 = index[i];
+            int i2 = index[( i + 1 ) % s];
+            if ( i1 > i2 ) std::swap( i1, i2 );
+            indices.emplace_back( i1, i2 );
         }
-        if ( tp )
-        {
-            drawable = tp->getRenderMode() ==
-                       Ra::Engine::Data::AttribArrayDisplayable::MeshRenderMode::RM_TRIANGLES;
+    }
 
-            if ( drawable )
-            {
-                drawable = tp->getRenderMode() ==
-                           Ra::Engine::Data::AttribArrayDisplayable::MeshRenderMode::RM_TRIANGLES;
-                lines.setVertices( tp->getCoreGeometry().vertices() );
-                for ( const auto& index : tp->getCoreGeometry().getIndices() )
-                {
-                    auto s = index.size();
-                    for ( unsigned int i = 0; i < s; ++i )
-                    {
-                        int i1 = index[i];
-                        int i2 = index[( i + 1 ) % s];
-                        if ( i1 > i2 ) std::swap( i1, i2 );
-                        indices.emplace_back( i1, i2 );
-                    }
-                }
-            }
-        }
-        if ( drawable )
-        {
-            std::sort( indices.begin(),
-                       indices.end(),
-                       []( const Ra::Core::Geometry::LineMesh::IndexType& a,
-                           const Ra::Core::Geometry::LineMesh::IndexType& b ) {
-                           return a[0] < b[0] || ( a[0] == b[0] && a[1] < b[1] );
-                       } );
-            indices.erase( std::unique( indices.begin(), indices.end() ), indices.end() );
-
-            lines.setIndices( std::move( indices ) );
-
-            disp = std::make_shared<Ra::Engine::Data::LineMesh>( std::string( "wireframe" ),
-                                                                 std::move( lines ) );
-            disp->updateGL();
-            m_wireframes[ro.get()] = disp;
-        }
-        else
-        {
-            disp.reset();
-            m_wireframes[ro.get()] = {nullptr};
-        }
+    std::sort( indices.begin(),
+               indices.end(),
+               []( const Ra::Core::Geometry::LineMesh::IndexType& a,
+                   const Ra::Core::Geometry::LineMesh::IndexType& b ) {
+                   return a[0] < b[0] || ( a[0] == b[0] && a[1] < b[1] );
+               } );
+    indices.erase( std::unique( indices.begin(), indices.end() ), indices.end() );
+}
+
+// store LineMesh and Core, define the observer functor to update data one core update for wireframe
+// linemesh
+template <typename CoreGeometry>
+class VerticesUpdater
+{
+  public:
+    VerticesUpdater( std::shared_ptr<Ra::Engine::Data::LineMesh> disp, CoreGeometry& core ) :
+        m_disp{disp}, m_core{core} {};
+
+    void operator()() { m_disp->getCoreGeometry().setVertices( m_core.vertices() ); }
+    std::shared_ptr<Ra::Engine::Data::LineMesh> m_disp;
+    CoreGeometry& m_core;
+};
+
+template <typename CoreGeometry>
+class IndicesUpdater
+{
+  public:
+    IndicesUpdater( std::shared_ptr<Ra::Engine::Data::LineMesh> disp, CoreGeometry& core ) :
+        m_disp{disp}, m_core{core} {};
+
+    void operator()() {
+        auto lineIndices = m_disp->getCoreGeometry().getIndicesWithLock();
+        computeIndices( lineIndices, m_core.getIndices() );
+        m_disp->getCoreGeometry().indicesUnlock();
     }
-#endif
-    return true;
+    std::shared_ptr<Ra::Engine::Data::LineMesh> m_disp;
+    CoreGeometry& m_core;
+};
+
+// create a linemesh to draw wireframe given a core mesh
+template <typename CoreGeometry>
+void setupLineMesh( std::shared_ptr<Ra::Engine::Data::LineMesh>& disp, CoreGeometry& core ) {
+    Ra::Core::Geometry::LineMesh lines;
+    Ra::Core::Geometry::LineMesh::IndexContainerType indices;
+    lines.setVertices( core.vertices() );
+    computeIndices( indices, core.getIndices() );
+    if ( indices.size() > 0 )
+    {
+        lines.setIndices( std::move( indices ) );
+        disp = std::make_shared<Ra::Engine::Data::LineMesh>( std::string( "wireframe" ),
+                                                             std::move( lines ) );
+        disp->updateGL();
+        // add observer
+        auto handle = core.template getAttribHandle<typename CoreGeometry::Point>(
+            Ra::Engine::Data::Mesh::getAttribName( Ra::Engine::Data::Mesh::VERTEX_POSITION ) );
+        core.vertexAttribs().getAttrib( handle ).attach( VerticesUpdater( disp, core ) );
+        core.attach( IndicesUpdater( disp, core ) );
+    }
+    else
+    { disp.reset(); }
+}
+
+template <typename CoreGeometry>
+void processLineMesh( const std::shared_ptr<CoreGeometry>& m,
+                      std::shared_ptr<Ra::Engine::Data::LineMesh>& r ) {
+    if ( m->getRenderMode() ==
+         Ra::Engine::Data::AttribArrayDisplayable::MeshRenderMode::RM_TRIANGLES )
+    { setupLineMesh( r, m->getCoreGeometry() ); }
 }
 
 void WireframePass::resize( size_t width, size_t height ) {
-#ifdef ADVANCED_WIREFRAME
+
     m_width  = width;
     m_height = height;
-#endif
+
     // Only resize the owned textures. Imported one are resized by their owner
     for ( auto& t : m_localTextures )
     {
@@ -161,66 +165,61 @@ void WireframePass::resize( size_t width, size_t height ) {
 }
 
 void WireframePass::execute( const Ra::Engine::Data::ViewingParameters& viewParams ) const {
-
     m_fbo->bind();
     // only draw into 1 buffers (Color)
-    GL_ASSERT( glDrawBuffers( 1, buffers ) );
-    GL_ASSERT( glDepthMask( GL_FALSE ) );
-    GL_ASSERT( glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ) );
-
-    GL_ASSERT( glEnable( GL_DEPTH_TEST ) );
-    GL_ASSERT( glDepthFunc( GL_LESS ) );
-    GL_ASSERT( glEnable( GL_BLEND ) );
-#ifdef ADVANCED_WIREFRAME_SHADER
+    glDrawBuffers( 1, buffers );
+    glDepthMask( GL_FALSE );
+    glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
+    glEnable( GL_DEPTH_TEST );
+    glDepthFunc( GL_LESS );
+    glEnable( GL_BLEND );
+
     glBlendEquationSeparate( GL_FUNC_ADD, GL_FUNC_ADD );
     glBlendFuncSeparate( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO );
     // To prevent z-fighting, remove polygon offset
     glDisable( GL_POLYGON_OFFSET_FILL );
-#else
-    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
-    glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
-    glEnable( GL_LINE_SMOOTH );
-    glLineWidth( 1.f );
-    glDisable( GL_POLYGON_OFFSET_LINE );
-#endif
 
     for ( const auto& ro : *m_objectsToRender )
     {
         if ( ro->isVisible() )
         {
-#ifdef ADVANCED_WIREFRAME
+            std::shared_ptr<Ra::Engine::Data::Displayable> wro;
+
             auto it = m_wireframes.find( ro.get() );
-            if ( it != m_wireframes.end() )
+            if ( it == m_wireframes.end() )
             {
-                auto wro    = it->second;
-                auto shader = m_shaderMngr->getShaderProgram( "WireframePass::WireframeProgram" );
-                if ( wro && shader )
-                {
-                    shader->bind();
-                    Ra::Core::Matrix4 modelMatrix = ro->getTransformAsMatrix();
-                    shader->setUniform( "transform.proj", viewParams.projMatrix );
-                    shader->setUniform( "transform.view", viewParams.viewMatrix );
-                    shader->setUniform( "transform.model", modelMatrix );
-                    shader->setUniform( "viewport", Ra::Core::Vector2{m_width, m_height} );
-                    wro->render( shader );
-                    GL_CHECK_ERROR;
-                }
+                using trimesh = Ra::Engine::Data::IndexedGeometry<Ra::Core::Geometry::TriangleMesh>;
+                using polymesh = Ra::Engine::Data::IndexedGeometry<Ra::Core::Geometry::PolyMesh>;
+                std::shared_ptr<Ra::Engine::Data::LineMesh> disp;
+                auto displayable = ro->getMesh();
+                auto tm          = std::dynamic_pointer_cast<trimesh>( displayable );
+                auto tp          = std::dynamic_pointer_cast<polymesh>( displayable );
+                if ( tm ) { processLineMesh( tm, disp ); }
+                if ( tp ) { processLineMesh( tp, disp ); }
+                m_wireframes[ro.get()] = disp;
+                wro                    = disp;
             }
+            else
+            { wro = it->second; }
 
-#else
-            ro->render( m_passParams, viewParams, passIndex() );
-#endif
+            auto shader = m_shaderMngr->getShaderProgram( "WireframePass::WireframeProgram" );
+            if ( wro && shader )
+            {
+                wro->updateGL();
+                shader->bind();
+                Ra::Core::Matrix4 modelMatrix = ro->getTransformAsMatrix();
+                shader->setUniform( "transform.proj", viewParams.projMatrix );
+                shader->setUniform( "transform.view", viewParams.viewMatrix );
+                shader->setUniform( "transform.model", modelMatrix );
+                shader->setUniform( "viewport", Ra::Core::Vector2{m_width, m_height} );
+                wro->render( shader );
+                GL_CHECK_ERROR;
+            }
         }
     }
-#ifdef ADVANCED_WIREFRAME_SHADER
     // need to maintain global state invariant
     glEnable( GL_POLYGON_OFFSET_FILL );
-#else
-    glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
-    // do we need to enable this ? it is not part of the invariant ...
-    // glEnable( GL_POLYGON_OFFSET_LINE );
-#endif
-    GL_ASSERT( glDisable( GL_BLEND ) );
+    glDisable( GL_BLEND );
 }
 
 bool WireframePass::buildRenderTechnique( const Ra::Engine::Rendering::RenderObject* ro,
@@ -235,7 +234,7 @@ bool WireframePass::buildRenderTechnique( const Ra::Engine::Rendering::RenderObj
     { rt.setConfiguration( *cfg, passIndex() ); }
     else
     {
-#ifdef ADVANCED_WIREFRAME_SHADER
+
         Ra::Engine::Data::ShaderConfiguration theConfig{
             {"WireframePass::WireframeProgram"},
             resourcesRootDir + "Shaders/WireframePass/Advanced/wireframe.vert.glsl",
@@ -243,13 +242,6 @@ bool WireframePass::buildRenderTechnique( const Ra::Engine::Rendering::RenderObj
         theConfig.addShader( Ra::Engine::Data::ShaderType_GEOMETRY,
                              resourcesRootDir +
                                  "Shaders/WireframePass/Advanced/wireframe.geom.glsl" );
-#else
-        // Build the shader configuration
-        Ra::Engine::Data::ShaderConfiguration theConfig{
-            {"WireframePass::WireframeProgram"},
-            resourcesRootDir + "Shaders/WireframePass/Basic/wireframepass.vert.glsl",
-            resourcesRootDir + "Shaders/WireframePass/Basic/wireframepass.frag.glsl"};
-#endif
         // Add to the ShaderConfigManager
         Ra::Engine::Data::ShaderConfigurationFactory::addConfiguration( theConfig );
         // Add to the RenderTechnique
diff --git a/src/libRender/RadiumNBR/Passes/WireframePass.hpp b/src/libRender/RadiumNBR/Passes/WireframePass.hpp
index 919b6fa852061b30c8e744b0134d03d34e14cd44..61305c7c044d13cfdfddbb078856aaf245c7988d 100644
--- a/src/libRender/RadiumNBR/Passes/WireframePass.hpp
+++ b/src/libRender/RadiumNBR/Passes/WireframePass.hpp
@@ -2,13 +2,7 @@
 #include <RadiumNBR/RenderPass.hpp>
 
 #include <Core/Utils/Color.hpp>
-
-// This is the default. The two way of rendering wireframe is kept for illustration only
-#define ADVANCED_WIREFRAME
-#define ADVANCED_WIREFRAME_SHADER
-#ifdef ADVANCED_WIREFRAME
-#    include <Engine/Data/DisplayableObject.hpp>
-#endif
+#include <Engine/Data/DisplayableObject.hpp>
 
 namespace Ra::Engine::Data {
 class ShaderProgram;
@@ -52,15 +46,13 @@ class WireframePass : public RenderPass
     /// The color texture for output.Stored here for easy access.
     SharedTextures m_outputTexture;
 
-#ifdef ADVANCED_WIREFRAME
     using WireMap = std::map<Ra::Engine::Rendering::RenderObject*,
                              std::shared_ptr<Ra::Engine::Data::Displayable>>;
-    WireMap m_wireframes;
+    mutable WireMap m_wireframes;
     bool m_wireframeAa{true};
     Ra::Core::Utils::Color m_wireframeColor{Ra::Core::Utils::Color::White()};
 
     uint m_width{0};
     uint m_height{0};
-#endif
 };
 } // namespace RadiumNBR