diff --git a/CMake/External/External_imgui.cmake b/CMake/External/External_imgui.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..9a7bb0f746ca9f6c5622b2b1031cd68ca1ee930f
--- /dev/null
+++ b/CMake/External/External_imgui.cmake
@@ -0,0 +1,14 @@
+#-----------------------------------------------------------------------------
+# Add External Project
+#-----------------------------------------------------------------------------
+include(imstkAddExternalProject)
+imstk_add_external_project( imgui
+  GIT_REPOSITORY https://github.com/ocornut/imgui.git
+  GIT_TAG v1.65
+  CONFIGURE_COMMAND ${SKIP_STEP_COMMAND}
+  BUILD_COMMAND ${SKIP_STEP_COMMAND}
+  INSTALL_COMMAND ${SKIP_STEP_COMMAND}
+  RELATIVE_INCLUDE_PATH ""
+  DEPENDENCIES ""
+  #VERBOSE
+  )
diff --git a/CMake/Findimgui.cmake b/CMake/Findimgui.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..c543201c42567084a2e0896724a65c2f41e4591d
--- /dev/null
+++ b/CMake/Findimgui.cmake
@@ -0,0 +1,24 @@
+#-----------------------------------------------------------------------------
+# Find path
+#-----------------------------------------------------------------------------
+find_path(imgui_INCLUDE_DIR
+  NAMES
+    imgui.h
+    )
+mark_as_advanced(imgui_INCLUDE_DIR)
+message(STATUS "imgui_INCLUDE_DIR : ${imgui_INCLUDE_DIR}")
+
+#-----------------------------------------------------------------------------
+# Find package
+#-----------------------------------------------------------------------------
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(imgui
+  REQUIRED_VARS
+    imgui_INCLUDE_DIR)
+
+#-----------------------------------------------------------------------------
+# If missing target, create it
+#-----------------------------------------------------------------------------
+if(GLM_FOUND AND NOT TARGET imgui)
+  add_library(imgui INTERFACE IMPORTED)
+endif()
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c42f5729c80b9466d10514ea026bd2e7d92d6213..b9aecc38d0055c66f784bffdfdd730d2c7f03f93 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -126,6 +126,7 @@ if(${PROJECT_NAME}_SUPERBUILD)
   imstk_define_dependency(VTK)
   imstk_define_dependency(VRPN)
   imstk_define_dependency(LibNiFalcon)
+  imstk_define_dependency(imgui)
 
   if(APPLE OR LINUX)
    message("Warning: Building iMSTK WITHOUT audio support!")
@@ -229,16 +230,16 @@ find_package( Assimp REQUIRED )
 include_directories( ${Assimp_INCLUDE_DIRS} )
 
 # glm
-find_package(glm)
+find_package( glm )
 include_directories( ${glm_INCLUDE_DIR} )
 
 if( ${PROJECT_NAME}_USE_Vulkan )
   # glfw
-  find_package(glfw)
+  find_package( glfw )
   include_directories( ${glfw_INCLUDE_DIR} )
 
   # gli
-  find_package(gli)
+  find_package( gli )
   include_directories( ${gli_INCLUDE_DIR} )
 endif()
 
@@ -256,6 +257,10 @@ include_directories( ${g3log_INCLUDE_DIR} )
 find_package( Eigen 3.1.2 REQUIRED )
 include_directories( ${Eigen_INCLUDE_DIR} )
 
+# imgui
+find_package( imgui REQUIRED )
+include_directories( ${imgui_INCLUDE_DIR} )
+
 # SCCD
 find_package( SCCD REQUIRED )
 include_directories( ${SCCD_INCLUDE_DIR} )
@@ -337,6 +342,7 @@ add_subdirectory(Source/Scene)
 add_subdirectory(Source/SimulationManager)
 add_subdirectory(Source/Constraint)
 add_subdirectory(Source/Materials)
+add_subdirectory(Source/GUIOverlay)
 
 #--------------------------------------------------------------------------
 # Export Targets
diff --git a/Examples/GUIOverlay/CMakeLists.txt b/Examples/GUIOverlay/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9ed2ccf21e4f42375af041d232526334eb96579a
--- /dev/null
+++ b/Examples/GUIOverlay/CMakeLists.txt
@@ -0,0 +1,42 @@
+###########################################################################
+#
+# Copyright (c) Kitware, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0.txt
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+###########################################################################
+
+project(Example-GUIOverlay)
+
+#-----------------------------------------------------------------------------
+# Create executable
+#-----------------------------------------------------------------------------
+add_executable(${PROJECT_NAME} GUIOverlayExample.cpp)
+
+#-----------------------------------------------------------------------------
+# Link libraries to executable
+#-----------------------------------------------------------------------------
+target_link_libraries(${PROJECT_NAME} SimulationManager)
+    
+#-----------------------------------------------------------------------------
+# Add shaders
+#-----------------------------------------------------------------------------
+include(imstkCopyAndCompileShaders)
+CopyAndCompileShaders()
+  
+#-----------------------------------------------------------------------------
+# Associate external data
+#-----------------------------------------------------------------------------
+list(APPEND FILE_LIST
+    decals/,REGEX:.*)
+imstk_add_data(${PROJECT_NAME} ${FILE_LIST})
\ No newline at end of file
diff --git a/Examples/GUIOverlay/GUIOverlayExample.cpp b/Examples/GUIOverlay/GUIOverlayExample.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9fe5090797d837cf48a3f4455db36a37b54e9a08
--- /dev/null
+++ b/Examples/GUIOverlay/GUIOverlayExample.cpp
@@ -0,0 +1,129 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#include "imstkSimulationManager.h"
+#include "imstkAPIUtilities.h"
+#include "imstkGUICanvas.h"
+#include "imstkGUIWindow.h"
+#include "imstkGUIShapes.h"
+#include "imstkGUIText.h"
+
+using namespace imstk;
+
+///
+/// \brief This example demonstrates the GUI feature.
+/// NOTE: Requires enabling Vulkan rendering backend
+///
+int main()
+{
+    // SDK and Scene
+    auto sdk = std::make_shared<SimulationManager>();
+    auto scene = sdk->createNewScene("GraphicalUserInterface");
+    auto canvas = sdk->getViewer()->getCanvas();
+
+    // Cube
+    auto cube = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Cube, scene, "cube", 0.5);
+    cube->getVisualGeometry()->translate(0, 0, 0);
+    cube->getVisualGeometry()->rotate(UP_VECTOR, PI_4);
+
+    // Plane
+    auto plane = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Plane, scene, "plane", 10);
+
+    // Window logic
+    auto window = std::make_shared<GUIOverlay::Window>("Test Window", "Test Window", 200.0f, 100.0f, 200.0f, 0.0f);
+    auto windowText = std::make_shared<GUIOverlay::Text>("Window Text", "Window Text", 0.0f, 0.0f);
+    window->addWidget(windowText);
+
+    auto circle = std::make_shared<GUIOverlay::Circle>("Circle", 100.0f, 100.0f, 25.0f, Color::Red, true);
+    auto circleOutline = std::make_shared<GUIOverlay::Circle>("CircleOutline", 100.0f, 100.0f, 25.0f, Color::Black, false);
+
+    // These two rectangles show that the ordering matters
+    auto underRectangle = std::make_shared<GUIOverlay::Rectangle>("UnderRectangle", 100.0f, 100.0f, 100.0f, 100.0f, Color(0.0f, 0.0f, 1.0f, 0.7f), true);
+    auto overRectangle = std::make_shared<GUIOverlay::Rectangle>("OverRectangle", 0.0f, 0.0f, 100.0f, 100.0f, Color(0.7f, 0.0f, 1.0f, 0.7f), true);
+
+    canvas->addWidget(underRectangle);
+    canvas->addWidget(circle);
+    canvas->addWidget(circleOutline);
+    canvas->addWidget(overRectangle);
+    canvas->addWidget(window);
+
+    StopWatch watch;
+    watch.start();
+    auto startTime = watch.getTimeElapsed();
+    auto lastTime = startTime;
+
+    // Update function
+    auto GUIUpdateFunction =
+        [&](InteractorStyle* style) -> bool
+        {
+            auto time = watch.getTimeElapsed();
+            float angle = time / 1000.0f;
+            circle->setPosition(std::sin(angle) * 50.0f + 100.0f, std::cos(angle) * 50.0f + 100.0f);
+            circle->setRadius(std::abs(std::sin(angle)) * 25.0f);
+            circleOutline->setPosition(std::sin(angle) * 50.0f + 100.0f, std::cos(angle) * 50.0f + 100.0f);
+
+            if (time - lastTime > 1000)
+            {
+                auto seconds = (int)((lastTime - startTime) / 1000);
+                windowText->setText("Elapsed Time: " + std::to_string(seconds)+ "s");
+                lastTime = time;
+            }
+
+            return false;
+        };
+    sdk->getViewer()->setOnTimerFunction(GUIUpdateFunction);
+
+    bool canvasVisible = true;
+    auto hideShowCanvasFunction =
+        [&](InteractorStyle* style) -> bool
+        {
+            if (canvasVisible)
+            {
+                canvas->hide();
+            }
+            else
+            {
+                canvas->show();
+            }
+
+            canvasVisible = !canvasVisible;
+            return true;
+        };
+    sdk->getViewer()->setOnCharFunction('c', hideShowCanvasFunction);
+
+    // Position camera
+    auto cam = scene->getCamera();
+    cam->setPosition(0, 3, 6);
+    cam->setFocalPoint(0, 0, 0);
+
+    // Light
+    auto light = std::make_shared<DirectionalLight>("Light");
+    light->setIntensity(7);
+    light->setColor(Color(1.0, 0.95, 0.8));
+    light->setFocalPoint(Vec3d(-1, -1, 0));
+    scene->addLight(light);
+
+    // Run
+    sdk->setActiveScene(scene);
+    sdk->startSimulation(SimulationStatus::PAUSED);
+
+    return 0;
+}
diff --git a/Examples/RenderingBenchmark/RenderingBenchmark.cpp b/Examples/RenderingBenchmark/RenderingBenchmark.cpp
index cfff4b781061b53edfc68a59dac263071676a4e9..47239b8e2399bcac181817d7d251f71bf25631a7 100644
--- a/Examples/RenderingBenchmark/RenderingBenchmark.cpp
+++ b/Examples/RenderingBenchmark/RenderingBenchmark.cpp
@@ -91,7 +91,6 @@ int main()
             object->setVisualGeometry(mesh);
             scene->addSceneObject(object);
         }
-
     }
 
     int frame = 0;
@@ -102,41 +101,41 @@ int main()
     int startupFrame = -1;
 
     sdk->getViewer()->setOnTimerFunction([&](InteractorStyle* c) -> bool
+    {
+        if (dynamicMesh)
         {
-            if (dynamicMesh)
+            for (int j = 0; j < numMeshes; j++)
             {
-                for (int j = 0; j < numMeshes; j++)
-                {
-                    auto object = scene->getSceneObject(std::string("mesh") + std::to_string(j));
-                    auto mesh = std::dynamic_pointer_cast<LineMesh>(object->getVisualGeometry());
-
-                    mesh->setVertexPositions(vertices);
-                    mesh->setLinesVertices(lines);
-                }
-            }
+                auto object = scene->getSceneObject(std::string("mesh") + std::to_string(j));
+                auto mesh = std::dynamic_pointer_cast<LineMesh>(object->getVisualGeometry());
 
-            if (scene->getSceneObject("mesh" + std::to_string(numMeshes - 1)) && startupFrame == -1)
-            {
-                startupFrame = frame;
-                LOG(INFO) << "Start time: " << startWatch->getTimeElapsed();
-            }
-            if (frame == startupFrame + 100)
-            {
-                startFrame = frame;
-                watch->start();
-                watch->reset();
-                LOG(INFO) << "Starting time";
-            }
-            else if (frame == startFrame + 100 && startFrame != -1)
-            {
-                endTime = watch->getTimeElapsed();
-                LOG(INFO) << "Total time: " << endTime;
-                LOG(INFO) << "Frame time: " << endTime / (frame - startFrame);
+                mesh->setVertexPositions(vertices);
+                mesh->setLinesVertices(lines);
             }
-            frame++;
-            return true;
         }
-    );
+
+        if (scene->getSceneObject("mesh" + std::to_string(numMeshes - 1)) && startupFrame == -1)
+        {
+            startupFrame = frame;
+            LOG(INFO) << "Start time: " << startWatch->getTimeElapsed();
+        }
+        if (frame == startupFrame + 100)
+        {
+            startFrame = frame;
+            watch->start();
+            watch->reset();
+            LOG(INFO) << "Starting time";
+        }
+        else if (frame == startFrame + 100 && startFrame != -1)
+        {
+            endTime = watch->getTimeElapsed();
+            LOG(INFO) << "Total time: " << endTime;
+            LOG(INFO) << "Frame time: " << endTime / (frame - startFrame);
+        }
+        frame++;
+        return true;
+        }
+        );
 
     // Start simulation
     startWatch->start();
diff --git a/Source/GUIOverlay/CMakeLists.txt b/Source/GUIOverlay/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cc5866b1e6d04856233aaa4b9594535b5aea9143
--- /dev/null
+++ b/Source/GUIOverlay/CMakeLists.txt
@@ -0,0 +1,45 @@
+#-----------------------------------------------------------------------------
+# Create target
+#-----------------------------------------------------------------------------
+include(imstkAddLibrary)
+
+file (GLOB_RECURSE GUI_h_files "${CMAKE_CURRENT_SOURCE_DIR}/imstk*.h")
+file (GLOB_RECURSE GUI_cpp_files "${CMAKE_CURRENT_SOURCE_DIR}/imstk*.cpp")
+
+if( iMSTK_USE_VULKAN )
+  set (IMPLEMENTATION_H_FILES
+    ${imgui_INCLUDE_DIR}/examples/imgui_impl_vulkan.h
+    ${imgui_INCLUDE_DIR}/examples/imgui_impl_glfw.h)
+  set (IMPLENTATION_CPP_FILES
+    ${imgui_INCLUDE_DIR}/examples/imgui_impl_vulkan.cpp
+    ${imgui_INCLUDE_DIR}/examples/imgui_impl_glfw.cpp)
+endif()
+
+imstk_add_library( GUIOverlay
+  H_FILES
+    ${imgui_INCLUDE_DIR}/imconfig.h
+    ${imgui_INCLUDE_DIR}/imgui.h
+    ${imgui_INCLUDE_DIR}/imgui_internal.h
+    ${imgui_INCLUDE_DIR}/imstb_rectpack.h
+    ${imgui_INCLUDE_DIR}/imstb_textedit.h
+    ${imgui_INCLUDE_DIR}/imstb_truetype.h
+    ${IMPLEMENTATION_H_FILES}
+    ${GUI_h_files}
+  CPP_FILES
+    ${imgui_INCLUDE_DIR}/imgui.cpp
+    ${imgui_INCLUDE_DIR}/imgui_demo.cpp
+    ${imgui_INCLUDE_DIR}/imgui_draw.cpp
+    ${imgui_INCLUDE_DIR}/imgui_widgets.cpp
+    ${IMPLEMENTATION_CPP_FILES}
+    ${GUI_cpp_files}
+  DEPENDS
+    Core
+    imgui
+  )
+
+#-----------------------------------------------------------------------------
+# Testing
+#-----------------------------------------------------------------------------
+if( iMSTK_BUILD_TESTING )
+  add_subdirectory( Testing )
+endif()
diff --git a/Source/GUIOverlay/imstkGUICanvas.cpp b/Source/GUIOverlay/imstkGUICanvas.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f2041759854d3d988ee5d7fba1140b0dcc4076d0
--- /dev/null
+++ b/Source/GUIOverlay/imstkGUICanvas.cpp
@@ -0,0 +1,106 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#include "imstkGUICanvas.h"
+
+namespace imstk
+{
+namespace GUIOverlay
+{
+Canvas::~Canvas()
+{
+    this->clear();
+}
+
+void
+Canvas::clear()
+{
+    m_widgets.clear();
+}
+
+void
+Canvas::render()
+{
+    if (!m_visible)
+    {
+        return;
+    }
+
+    for (int i = 0; i < m_widgets.getSize(); i++)
+    {
+        auto type = m_widgets[i]->getType();
+
+        if (!m_widgets[i]->isVisible())
+        {
+            continue;
+        }
+
+        bool needsWindow = (type == Widget::Type::None);
+
+        if (needsWindow)
+        {
+            ImGui::SetNextWindowPos(ImVec2(0,0));
+            ImGui::SetNextWindowBgAlpha(0.0);
+            ImGui::Begin("", nullptr, ImGuiWindowFlags_NoInputs
+                | ImGuiWindowFlags_NoTitleBar
+                | ImGuiWindowFlags_NoResize);
+        }
+
+        m_widgets[i]->render(needsWindow);
+
+        if (needsWindow)
+        {
+            ImGui::End();
+        }
+    }
+}
+
+void
+Canvas::addWidget(std::shared_ptr<Widget> widget)
+{
+    m_widgets.addWidget(widget);
+}
+
+void
+Canvas::removeWidget(std::string name)
+{
+    m_widgets.removeWidget(name);
+}
+
+std::shared_ptr<Widget>
+Canvas::getWidget(std::string name)
+{
+    return m_widgets.getWidget(name);
+}
+
+void
+Canvas::show()
+{
+    m_visible = true;
+}
+
+void
+Canvas::hide()
+{
+    m_visible = false;
+}
+} // GUI
+} // imstk
diff --git a/Source/GUIOverlay/imstkGUICanvas.h b/Source/GUIOverlay/imstkGUICanvas.h
new file mode 100644
index 0000000000000000000000000000000000000000..d2fbe5e87188a2a5e38525446379d95d0f61e8ee
--- /dev/null
+++ b/Source/GUIOverlay/imstkGUICanvas.h
@@ -0,0 +1,100 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#ifndef imstkCanvas_h
+#define imstkCanvas_h
+
+#include "imgui.h"
+
+#include <map>
+#include <string>
+#include <memory>
+
+#include "imstkGUIWidget.h"
+#include "imstkGUIWidgetList.h"
+
+namespace imstk
+{
+namespace GUIOverlay
+{
+///
+/// \class Canvas
+///
+/// \brief Base class for GUI
+///
+class Canvas
+{
+public:
+
+    ///
+    /// \brief Protected constructor
+    ///
+    Canvas() {};
+
+    ///
+    /// \brief Destructor
+    ///
+    ~Canvas();
+
+    ///
+    /// \brief Clears all the widgets
+    ///
+    void clear();
+
+    ///
+    /// \brief Render the widgets
+    ///
+    void render();
+
+    ///
+    /// \brief Add widget
+    ///
+    void addWidget(std::shared_ptr<Widget> widget);
+
+    ///
+    /// \brief Remove widget
+    ///
+    void removeWidget(std::string name);
+
+    ///
+    /// \brief Get widget
+    ///
+    std::shared_ptr<Widget> getWidget(std::string name);
+
+    ///
+    /// \brief Show canvas
+    ///
+    void show();
+
+    ///
+    /// \brief Hide canvas
+    ///
+    void hide();
+
+protected:
+
+    WidgetList m_widgets;
+    bool m_visible = true;
+};
+} // GUI
+} // imstk
+
+#endif // ifndef imstkCanvas_h
diff --git a/Source/GUIOverlay/imstkGUIShapes.h b/Source/GUIOverlay/imstkGUIShapes.h
new file mode 100644
index 0000000000000000000000000000000000000000..384dd6b42b4d6bbe3315e109f2686f273be9fc1a
--- /dev/null
+++ b/Source/GUIOverlay/imstkGUIShapes.h
@@ -0,0 +1,232 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#ifndef imstkShapes_h
+#define imstkShapes_h
+
+#include "imgui.h"
+
+#include <string>
+
+#include "imstkGUIWidget.h"
+#include "imstkColor.h"
+#include "imstkGUIUtilities.h"
+
+namespace imstk
+{
+namespace GUIOverlay
+{
+///
+/// \class Shape
+///
+/// \brief Abstract shape class
+///
+class Shape : public Widget
+{
+protected:
+    ///
+    /// \brief Constructor
+    ///
+    Shape(std::string name, float x, float y, Color color, bool filled)
+        : Widget(name, x, y)
+    {
+        m_color = color;
+        m_filled = filled;
+        m_type = Widget::Type::Shape;
+    }
+
+    Shape() = delete;
+    Color m_color;
+    bool m_filled;
+};
+
+///
+/// \class Circle
+///
+/// \brief Circle widget
+///
+class Circle : public Shape
+{
+public:
+    ///
+    /// \brief Protected constructor
+    ///
+    Circle(std::string name,
+           float x,
+           float y,
+           float radius,
+           Color color,
+           bool filled = false)
+        : Shape(name, x, y, color, filled)
+    {
+        m_radius = radius;
+    }
+
+    ///
+    /// \brief Render
+    ///
+    virtual void render(const bool inWindow)
+    {
+        ImDrawList * drawList;
+
+        if (inWindow)
+        {
+            drawList = ImGui::GetWindowDrawList();
+        }
+        else
+        {
+            drawList = ImGui::GetOverlayDrawList();
+        }
+
+        if (m_filled)
+        {
+            drawList->AddCircleFilled(ImVec2(m_position[0], m_position[1]),
+                m_radius,
+                GUIOverlay::Utilities::convertToGUIColor(m_color),
+                24);
+        }
+        else
+        {
+            drawList->AddCircle(ImVec2(m_position[0], m_position[1]),
+                m_radius,
+                GUIOverlay::Utilities::convertToGUIColor(m_color),
+                24);
+        }
+    }
+
+    ///
+    /// \brief Set radius
+    ///
+    void setRadius(const float radius)
+    {
+        m_radius = radius;
+    }
+
+    ///
+    /// \brief Get radius
+    ///
+    const float getRadius()
+    {
+        return m_radius;
+    }
+
+protected:
+    Circle() = delete;
+    float m_radius;
+};
+
+///
+/// \class Rectangle
+///
+/// \brief Rectangle widget
+///
+class Rectangle : public Shape
+{
+public:
+    ///
+    /// \brief Protected constructor
+    ///
+    Rectangle(std::string name,
+              float x,
+              float y,
+              float width,
+              float height,
+              Color color,
+              bool filled = false)
+        : Shape(name, x, y, color, filled)
+    {
+        m_height = height;
+        m_width = width;
+    }
+
+    ///
+    /// \brief Render
+    ///
+    virtual void render(const bool inWindow)
+    {
+        ImDrawList * drawList;
+
+        if (inWindow)
+        {
+            drawList = ImGui::GetWindowDrawList();
+        }
+        else
+        {
+            drawList = ImGui::GetOverlayDrawList();
+        }
+
+        if (m_filled)
+        {
+            drawList->AddRectFilled(ImVec2(m_position[0], m_position[1]),
+                ImVec2(m_width + m_position[0], m_height + m_position[1]),
+                GUIOverlay::Utilities::convertToGUIColor(m_color),
+                0);
+        }
+        else
+        {
+            drawList->AddRect(ImVec2(m_position[0], m_position[1]),
+                ImVec2(m_width + m_position[0], m_height +m_position[1]),
+                GUIOverlay::Utilities::convertToGUIColor(m_color),
+                0);
+        }
+    }
+
+    ///
+    /// \brief Set width
+    ///
+    void setWidth(const float width)
+    {
+        m_width = width;
+    }
+
+    ///
+    /// \brief Set height
+    ///
+    void setHeight(const float height)
+    {
+        m_height = height;
+    }
+
+    ///
+    /// \brief Get width
+    ///
+    const float getWidth()
+    {
+        return m_width;
+    }
+
+    ///
+    /// \brief Get height
+    ///
+    const float getHeight()
+    {
+        return m_height;
+    }
+
+protected:
+    Rectangle() = delete;
+    float m_height;
+    float m_width;
+};
+}
+} // imstk
+
+#endif // ifndef imstkWidget_h
diff --git a/Source/GUIOverlay/imstkGUIText.h b/Source/GUIOverlay/imstkGUIText.h
new file mode 100644
index 0000000000000000000000000000000000000000..7fc72557a8784230ca318d643ac5cd791e6fcacd
--- /dev/null
+++ b/Source/GUIOverlay/imstkGUIText.h
@@ -0,0 +1,109 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#ifndef imstkText_h
+#define imstkText_h
+
+#include "imgui.h"
+
+#include <string>
+
+#include "imstkGUIWidget.h"
+#include "imstkColor.h"
+#include "imstkGUIUtilities.h"
+
+namespace imstk
+{
+namespace GUIOverlay
+{
+///
+/// \class Text
+///
+/// \brief Text widget
+///
+class Text : public Widget
+{
+public:
+    ///
+    /// \brief Protected constructor
+    ///
+    Text(std::string name,
+         std::string value,
+         float x,
+         float y,
+         float fontSize = 14.0f)
+        : Widget(name, x, y)
+    {
+        m_value = value;
+        m_fontSize = fontSize;
+        m_type = Widget::Type::Text;
+    }
+
+    ///
+    /// \brief Render
+    ///
+    virtual void render(const bool inWindow)
+    {
+        if (inWindow)
+        {
+            ImGui::Text(m_value.c_str(),
+                ImVec2(m_position[0], m_position[1]),
+                m_fontSize,
+                GUIOverlay::Utilities::convertToGUIColor(m_color));
+        }
+        else
+        {
+            auto drawList = ImGui::GetOverlayDrawList();
+            drawList->AddText(ImGui::GetFont(),
+                m_fontSize,
+                ImVec2(m_position[0], m_position[1]),
+                GUIOverlay::Utilities::convertToGUIColor(m_color),
+                m_value.c_str());
+        }
+    }
+
+    ///
+    /// \brief Set text
+    ///
+    void setText(const std::string text)
+    {
+        m_value = text;
+    }
+
+    ///
+    /// \brief Get text
+    ///
+    const std::string& getText()
+    {
+        return m_value;
+    }
+
+protected:
+    Text() = delete;
+
+    std::string m_value;
+    float m_fontSize = 10;
+    Color m_color = Color::White;
+};
+} // GUI
+} // imstk
+
+#endif // ifndef imstkWidget_h
diff --git a/Source/GUIOverlay/imstkGUIUtilities.h b/Source/GUIOverlay/imstkGUIUtilities.h
new file mode 100644
index 0000000000000000000000000000000000000000..59cbfaf77dc10d99cb5a1cc009a05ba806d55a48
--- /dev/null
+++ b/Source/GUIOverlay/imstkGUIUtilities.h
@@ -0,0 +1,58 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#ifndef imstkGUIUtilities_h
+#define imstkGUIUtilities_h
+
+#include "imgui.h"
+
+namespace imstk
+{
+namespace GUIOverlay
+{
+///
+/// \class GUIUtilities
+///
+/// \brief Utility functions for GUI management
+///
+class Utilities
+{
+public:
+    ///
+    /// \brief Initializes the GUI system with a theme
+    ///
+    static void
+    initializeGUISystem()
+    {
+        auto io = ImGui::GetIO();
+        io.IniFilename = nullptr; // resets the GUI layout on application restart
+    }
+
+    static ImU32
+    convertToGUIColor(const Color& color)
+    {
+        return ImGui::ColorConvertFloat4ToU32(ImVec4(color.r, color.g, color.b, color.a));
+    }
+}; // GUIUtilities
+} // GUI
+} // imstk
+
+#endif // ifndef imstkGUIUtilities_h
diff --git a/Source/GUIOverlay/imstkGUIWidget.cpp b/Source/GUIOverlay/imstkGUIWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8ce571787c26d09dbef55e76941134323f87d3a7
--- /dev/null
+++ b/Source/GUIOverlay/imstkGUIWidget.cpp
@@ -0,0 +1,95 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#include "imstkGUIWidget.h"
+
+namespace imstk
+{
+namespace GUIOverlay
+{
+Widget::Widget(std::string name, float x, float y)
+{
+    m_name = name;
+    m_position[0] = x;
+    m_position[1] = y;
+}
+
+Widget::~Widget()
+{
+}
+
+std::string
+Widget::getName()
+{
+    return m_name;
+}
+
+Widget::Type
+Widget::getType()
+{
+    return m_type;
+}
+
+
+const Vec2f&
+Widget::getPosition()
+{
+    return m_position;
+}
+
+void
+Widget::setPosition(const float x, const float y)
+{
+    m_position[0] = x;
+    m_position[1] = y;
+}
+
+void
+Widget::setPosition(const Vec2f& position)
+{
+    m_position[0] = position[0];
+    m_position[1] = position[1];
+}
+
+void
+Widget::hide()
+{
+    m_visible = false;
+}
+
+void
+Widget::show()
+{
+    m_visible = true;
+}
+
+const bool
+Widget::isVisible()
+{
+    return m_visible;
+}
+
+void
+Widget::render(const bool inWindow)
+{
+}
+} // GUI
+} // imstk
diff --git a/Source/GUIOverlay/imstkGUIWidget.h b/Source/GUIOverlay/imstkGUIWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..31016b1f405bf77ecb4cff132f5472a8d457a273
--- /dev/null
+++ b/Source/GUIOverlay/imstkGUIWidget.h
@@ -0,0 +1,115 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#ifndef imstkWidget_h
+#define imstkWidget_h
+
+#include <string>
+#include "imstkMath.h"
+
+namespace imstk
+{
+namespace GUIOverlay
+{
+///
+/// \class Widget
+///
+/// \brief Base class for all GUI elements
+///
+class Widget
+{
+public:
+    ///
+    /// \enum Type
+    ///
+    /// \brief Quick identifier for GUI element type
+    ///
+    enum class Type
+    {
+        None,
+        Window,
+        Shape,
+        Text
+    };
+
+    ///
+    /// \brief Protected constructor
+    ///
+    Widget(std::string name, float x = 0.0f, float y = 0.0f);
+
+    ///
+    /// \brief Destructor
+    ///
+    ~Widget();
+
+    ///
+    /// \brief Get name
+    ///
+    std::string getName();
+
+    ///
+    /// \brief Get type
+    ///
+    Widget::Type getType();
+
+    ///
+    /// \brief Get position
+    ///
+    const Vec2f& getPosition();
+
+    ///
+    /// \brief Set position
+    ///
+    void setPosition(const float x, const float y);
+    void setPosition(const Vec2f& position);
+
+    ///
+    /// \brief Hide
+    ///
+    void hide();
+
+    ///
+    /// \brief Show
+    ///
+    void show();
+
+    ///
+    /// \brief Get visibility
+    ///
+    const bool isVisible();
+
+    ///
+    /// \brief Render
+    ///
+    virtual void render(const bool inWindow = false);
+
+protected:
+    Widget() = delete;
+
+    std::string m_name;
+    Vec2f m_position;
+    Widget::Type m_type = Widget::Type::None;
+    bool m_visible = true;
+};
+} // GUI
+} // imstk
+
+#endif // ifndef imstkWidget_h
diff --git a/Source/GUIOverlay/imstkGUIWidgetList.cpp b/Source/GUIOverlay/imstkGUIWidgetList.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ed3119621737e6c3f219a1f9e9bec5f441c4488d
--- /dev/null
+++ b/Source/GUIOverlay/imstkGUIWidgetList.cpp
@@ -0,0 +1,90 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#include "imstkGUIWidgetList.h"
+
+namespace imstk
+{
+namespace GUIOverlay
+{
+WidgetList::WidgetList()
+{
+}
+
+void
+WidgetList::addWidget(std::shared_ptr<Widget> widget)
+{
+    if (!this->getWidget(widget->getName()))
+    {
+        m_widgets.push_back(widget);
+    }
+}
+
+bool
+WidgetList::removeWidget(std::string name)
+{
+    int index = 0;
+
+    for (auto widget : m_widgets)
+    {
+        if (widget->getName() == name)
+        {
+            m_widgets.erase(m_widgets.begin() + index);
+            return true;
+        }
+        index++;
+    }
+    return false;
+}
+
+std::shared_ptr<Widget>
+WidgetList::getWidget(std::string name)
+{
+    for (auto widget : m_widgets)
+    {
+        if (widget->getName() == name)
+        {
+            return widget;
+        }
+    }
+
+    return nullptr;
+}
+
+std::shared_ptr<Widget>
+WidgetList::operator[](size_t index)
+{
+    return m_widgets[index];
+}
+
+size_t
+WidgetList::getSize()
+{
+    return m_widgets.size();
+}
+
+void
+WidgetList::clear()
+{
+    m_widgets.clear();
+}
+} // GUI
+} // imstk
\ No newline at end of file
diff --git a/Source/GUIOverlay/imstkGUIWidgetList.h b/Source/GUIOverlay/imstkGUIWidgetList.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9eaeb36ce260eb198c1378a72eef8e0d7e6fc13
--- /dev/null
+++ b/Source/GUIOverlay/imstkGUIWidgetList.h
@@ -0,0 +1,87 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#ifndef imstkWidgetList_h
+#define imstkWidgetList_h
+
+#include "g3log/g3log.hpp"
+
+#include <vector>
+#include <map>
+#include <memory>
+
+#include "imstkGUIWidget.h"
+
+namespace imstk
+{
+namespace GUIOverlay
+{
+///
+/// \class WidgetList
+///
+/// \brief Ordered list for Widget objects
+///        The ordering matters, but we also want to have uniquely named
+///        widgets.
+///
+class WidgetList
+{
+public:
+    ///
+    /// \brief Default constructor
+    ///
+    WidgetList();
+
+    ///
+    /// \brief Add widget
+    ///
+    void addWidget(std::shared_ptr<Widget> widget);
+
+    ///
+    /// \brief Remove widget
+    ///
+    bool removeWidget(std::string name);
+
+    ///
+    /// \brief Get widget
+    ///
+    std::shared_ptr<Widget> getWidget(std::string name);
+
+    ///
+    /// \brief Get number of widgets
+    ///
+    size_t getSize();
+
+    ///
+    /// \brief Clear widgets
+    ///
+    void clear();
+
+    ///
+    /// \brief Access operator
+    ///
+    std::shared_ptr<Widget> operator[] (size_t index);
+
+protected:
+    std::vector<std::shared_ptr<Widget>> m_widgets;
+};
+} // GUI
+} // imstk
+#endif
\ No newline at end of file
diff --git a/Source/GUIOverlay/imstkGUIWindow.cpp b/Source/GUIOverlay/imstkGUIWindow.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..589c7139f01e16330234325f6c26d9ceb1eacee3
--- /dev/null
+++ b/Source/GUIOverlay/imstkGUIWindow.cpp
@@ -0,0 +1,85 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#include "imstkGUIWindow.h"
+
+namespace imstk
+{
+namespace GUIOverlay
+{
+Window::Window(std::string name,
+               std::string title,
+               float width,
+               float height,
+               float x,
+               float y) : Widget(name, x, y)
+{
+    m_type = Widget::Type::Window;
+    m_title = title;
+    m_width = width;
+    m_height = height;
+}
+
+Window::~Window()
+{
+    this->clear();
+}
+
+void
+Window::clear()
+{
+    m_widgets.clear();
+}
+
+void
+Window::render(const bool inWindow)
+{
+    ImGui::SetNextWindowPos(ImVec2(m_position[0], m_position[1]));
+    ImGui::SetNextWindowSize(ImVec2(m_width, m_height));
+    ImGui::SetNextWindowBgAlpha(0.5f);
+    ImGui::Begin(m_title.c_str(), nullptr, ImGuiWindowFlags_NoResize
+        | ImGuiWindowFlags_NoMove
+        | ImGuiWindowFlags_NoCollapse
+        | ImGuiWindowFlags_NoBringToFrontOnFocus);
+    for (int i = 0; i < m_widgets.getSize(); i++)
+    {
+        if (!m_widgets[i]->isVisible())
+        {
+            continue;
+        }
+        m_widgets[i]->render(true);
+    }
+    ImGui::End();
+}
+
+void
+Window::addWidget(std::shared_ptr<Widget> widget)
+{
+    m_widgets.addWidget(widget);
+}
+
+std::shared_ptr<Widget>
+Window::getWidget(std::string name)
+{
+    return m_widgets.getWidget(name);
+}
+} // GUI
+} // imstk
diff --git a/Source/GUIOverlay/imstkGUIWindow.h b/Source/GUIOverlay/imstkGUIWindow.h
new file mode 100644
index 0000000000000000000000000000000000000000..8663e4d5d8a108d6b8de9f0d3cf7dfc8fca37d0d
--- /dev/null
+++ b/Source/GUIOverlay/imstkGUIWindow.h
@@ -0,0 +1,94 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#ifndef imstkWindow_h
+#define imstkWindow_h
+
+#include "g3log/g3log.hpp"
+#include "imgui.h"
+
+#include <string>
+#include <map>
+#include <memory>
+
+#include "imstkGUIWidget.h"
+#include "imstkGUIWidgetList.h"
+
+namespace imstk
+{
+namespace GUIOverlay
+{
+///
+/// \class PointSet
+///
+/// \brief Base class for all geometries represented by discrete points and elements
+///
+class Window : public Widget
+{
+public:
+
+    ///
+    /// \brief Protected constructor
+    ///
+    Window(std::string name,
+           std::string title = "",
+           float width = 100,
+           float height = 50,
+           float x = 0,
+           float y = 0);
+
+    ///
+    /// \brief Destructor
+    ///
+    ~Window();
+
+    ///
+    /// \brief Clears all the widgets
+    ///
+    void clear();
+
+    ///
+    /// \brief Render
+    ///
+    virtual void render(const bool inWindow);
+
+    ///
+    /// \brief Add widget
+    ///
+    void addWidget(std::shared_ptr<Widget> widget);
+
+    ///
+    /// \brief Get widget
+    ///
+    std::shared_ptr<Widget> getWidget(std::string name);
+
+protected:
+    Window() = delete;
+
+    std::string m_title = "";
+    float m_width;
+    float m_height;
+    WidgetList m_widgets;
+};
+} // GUI
+} // imstk
+
+#endif // ifndef imstkWindow_h
diff --git a/Source/Rendering/CMakeLists.txt b/Source/Rendering/CMakeLists.txt
index e3f89154d7edd50b36d0f6d19b4cbe4e9582a1ab..6139f8de19a216faa3a6deb1dffb35a9c214cf39 100644
--- a/Source/Rendering/CMakeLists.txt
+++ b/Source/Rendering/CMakeLists.txt
@@ -83,7 +83,8 @@ if( NOT iMSTK_USE_Vulkan )
   set(RENDERING_SUBDIR
     VTKRenderer
     VTKRenderer/RenderDelegate)
-  set(RENDERING_DEPENDENCIES)
+  set(RENDERING_DEPENDENCIES
+    GUIOverlay)
 else()
   set(RENDERING_H_FILES ${VULKAN_H_FILES})
   set(RENDERING_CPP_FILES ${VULKAN_CPP_FILES})
@@ -94,7 +95,8 @@ else()
   set(RENDERING_DEPENDENCIES
     ${VulkanSDK_LIBRARIES}
     glfw
-    gli)
+    gli
+    GUIOverlay)
 endif()
 
 include(imstkAddLibrary)
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.cpp
index 9b333b02988af45ce1b5008d2424ce6f4091b5fd..01d088784659b1a6d2de93eccb65a3a1819bdad2 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.cpp
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.cpp
@@ -24,8 +24,8 @@
 namespace imstk
 {
 VulkanCapsuleRenderDelegate::VulkanCapsuleRenderDelegate(std::shared_ptr<Capsule> capsule,
-    SceneObject::Type type,
-    VulkanMemoryManager& memoryManager)
+                                                         SceneObject::Type type,
+                                                         VulkanMemoryManager& memoryManager)
     : m_geometry(capsule)
 {
     auto source = vtkSmartPointer<vtkCapsuleSource>::New();
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.h
index 677fa2b1b0f466c201e70bc6ce265be75ffb2021..7cd9948e370300294039a199eb42c74bb5188e00 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.h
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.h
@@ -45,8 +45,8 @@ public:
     /// \brief Default constructor
     ///
     VulkanCapsuleRenderDelegate(std::shared_ptr<Capsule> capsule,
-        SceneObject::Type type,
-        VulkanMemoryManager& memoryManager);
+                                SceneObject::Type type,
+                                VulkanMemoryManager& memoryManager);
 
     ///
     /// \brief Update render geometry
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.cpp
index df778cb95a56d275b20185f76b1a0bc54048eaab..879603c4c20a5f14aad240f0593e9124bc654853 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.cpp
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.cpp
@@ -24,8 +24,8 @@
 namespace imstk
 {
 VulkanCubeRenderDelegate::VulkanCubeRenderDelegate(std::shared_ptr<Cube> cube,
-    SceneObject::Type type,
-    VulkanMemoryManager& memoryManager)
+                                                   SceneObject::Type type,
+                                                   VulkanMemoryManager& memoryManager)
     : m_geometry(cube)
 {
     auto width = m_geometry->getWidth();
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.h
index 136e7f22b16c17b1c20270fa733ad5e4e651ac76..2e7627eed01aa6c915a5a4059eda53078844e1b4 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.h
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.h
@@ -45,8 +45,8 @@ public:
     /// \brief Default constructor
     ///
     VulkanCubeRenderDelegate(std::shared_ptr<Cube> cube,
-        SceneObject::Type type,
-        VulkanMemoryManager& memoryManager);
+                             SceneObject::Type type,
+                             VulkanMemoryManager& memoryManager);
 
     ///
     /// \brief Update render geometry
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanDecalRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanDecalRenderDelegate.cpp
index 223ce39ae6840de9426f76b0750fee190e2f2db8..442e9ee2f0b786f21dda869d9c934af857626a93 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanDecalRenderDelegate.cpp
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanDecalRenderDelegate.cpp
@@ -24,8 +24,8 @@
 namespace imstk
 {
 VulkanDecalRenderDelegate::VulkanDecalRenderDelegate(std::shared_ptr<DecalPool> decalPool,
-    SceneObject::Type type,
-    VulkanMemoryManager& memoryManager)
+                                                     SceneObject::Type type,
+                                                     VulkanMemoryManager& memoryManager)
     : m_geometry(decalPool)
 {
     m_numVertices = 8;
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanDecalRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanDecalRenderDelegate.h
index 0b85dd79ed5505e133d6f169cab0c710003d914e..9a2d4f714b1b5c52300fc895f95231636bc03b47 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanDecalRenderDelegate.h
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanDecalRenderDelegate.h
@@ -40,8 +40,8 @@ public:
     /// \brief Default constructor
     ///
     VulkanDecalRenderDelegate(std::shared_ptr<DecalPool> decalPool,
-        SceneObject::Type type,
-        VulkanMemoryManager& memoryManager);
+                              SceneObject::Type type,
+                              VulkanMemoryManager& memoryManager);
 
     ///
     /// \brief Update render geometry
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanLineMeshRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanLineMeshRenderDelegate.cpp
index 13705671eef01ee11588a4e313bb684fbb6e0548..092f7b3ec5e0c3a4665e9ca65fa694e38c69de31 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanLineMeshRenderDelegate.cpp
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanLineMeshRenderDelegate.cpp
@@ -24,8 +24,8 @@
 namespace imstk
 {
 VulkanLineMeshRenderDelegate::VulkanLineMeshRenderDelegate(std::shared_ptr<LineMesh> lineMesh,
-    SceneObject::Type type,
-    VulkanMemoryManager& memoryManager)
+                                                           SceneObject::Type type,
+                                                           VulkanMemoryManager& memoryManager)
     : m_geometry(lineMesh)
 {
     m_numVertices = (uint32_t)m_geometry->getNumVertices();
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanLineMeshRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanLineMeshRenderDelegate.h
index da752f7bd2ef50150b851dcbee9c27ba714dd870..779ae06ce337c4f1355dbeb1820e4f646ea5db8a 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanLineMeshRenderDelegate.h
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanLineMeshRenderDelegate.h
@@ -43,8 +43,8 @@ public:
     /// \brief Default constructor
     ///
     VulkanLineMeshRenderDelegate(std::shared_ptr<LineMesh> LineMesh,
-        SceneObject::Type type,
-        VulkanMemoryManager& memoryManager);
+                                 SceneObject::Type type,
+                                 VulkanMemoryManager& memoryManager);
 
     ///
     /// \brief Update render geometry
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.cpp
index 2afede163ed338496835770fa9fead7e46e5cf8f..f9f013a1b985fdbc081555e0e71e8bc630799fc2 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.cpp
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.cpp
@@ -24,8 +24,8 @@
 namespace imstk
 {
 VulkanPlaneRenderDelegate::VulkanPlaneRenderDelegate(std::shared_ptr<Plane> plane,
-    SceneObject::Type type,
-    VulkanMemoryManager& memoryManager)
+                                                     SceneObject::Type type,
+                                                     VulkanMemoryManager& memoryManager)
     : m_geometry(plane)
 {
     auto width = m_geometry->getWidth();
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.h
index 77be0d644497771c200fc978d9892c3dc5998b53..85c1baca38f076a955da88d5a5865ae56bb77e2b 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.h
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.h
@@ -46,8 +46,8 @@ public:
     /// \brief Default constructor
     ///
     VulkanPlaneRenderDelegate(std::shared_ptr<Plane> plane,
-        SceneObject::Type type,
-        VulkanMemoryManager& memoryManager);
+                              SceneObject::Type type,
+                              VulkanMemoryManager& memoryManager);
 
     ///
     /// \brief Update render geometry
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp
index ee9f73e2bf9104b5846bf8f626ec5e9f1a74600b..0612015da1b5685c6681a5303e6ec02c92561dc7 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp
@@ -44,8 +44,8 @@ namespace imstk
 {
 std::shared_ptr<VulkanRenderDelegate>
 VulkanRenderDelegate::make_delegate(std::shared_ptr<Geometry> geom,
-    SceneObject::Type type,
-    VulkanMemoryManager& memoryManager)
+                                    SceneObject::Type type,
+                                    VulkanMemoryManager& memoryManager)
 {
     geom->m_renderDelegateCreated = true;
     switch (geom->getType())
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.cpp
index 22ac28b370aeafd85db74005e55ad28a48f0df9c..82b1c0b77e594f3fd4d1275e7095decc42a76d93 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.cpp
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.cpp
@@ -24,8 +24,8 @@
 namespace imstk
 {
 VulkanSphereRenderDelegate::VulkanSphereRenderDelegate(std::shared_ptr<Sphere> sphere,
-    SceneObject::Type type,
-    VulkanMemoryManager& memoryManager)
+                                                       SceneObject::Type type,
+                                                       VulkanMemoryManager& memoryManager)
     : m_geometry(sphere)
 {
     auto radius = m_geometry->getRadius();
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.h
index fa5a8023620f2182236cb57c51732e34a150e0d5..9802e5539eb0a7db24a8ab3f60e4e13f019b63c9 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.h
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.h
@@ -45,8 +45,8 @@ public:
     /// \brief Default constructor
     ///
     VulkanSphereRenderDelegate(std::shared_ptr<Sphere> sphere,
-        SceneObject::Type type,
-        VulkanMemoryManager& memoryManager);
+                               SceneObject::Type type,
+                               VulkanMemoryManager& memoryManager);
 
     ///
     /// \brief Update render geometry
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.cpp
index 73295c9a89f10f422d5e524c26afa818f179f8af..7ec2cf642c7fe6cdec8f05b034f72576ae9ace2b 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.cpp
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.cpp
@@ -24,8 +24,8 @@
 namespace imstk
 {
 VulkanSurfaceMeshRenderDelegate::VulkanSurfaceMeshRenderDelegate(std::shared_ptr<SurfaceMesh> surfaceMesh,
-    SceneObject::Type type,
-    VulkanMemoryManager& memoryManager)
+                                                                 SceneObject::Type type,
+                                                                 VulkanMemoryManager& memoryManager)
     : m_geometry(surfaceMesh)
 {
     m_numVertices = (uint32_t)m_geometry->getNumVertices();
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.h
index 658b8186d6da1ccb6afaa7abbc6b404bc91de3d3..8a4b5c5464a50ed9727b75f282db046d47ecd64e 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.h
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.h
@@ -40,8 +40,8 @@ public:
     /// \brief Default constructor
     ///
     VulkanSurfaceMeshRenderDelegate(std::shared_ptr<SurfaceMesh> surfaceMesh,
-        SceneObject::Type type,
-        VulkanMemoryManager& memoryManager);
+                                    SceneObject::Type type,
+                                    VulkanMemoryManager& memoryManager);
 
     ///
     /// \brief Update render geometry
diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanRenderPassGenerator.cpp b/Source/Rendering/VulkanRenderer/imstkVulkanRenderPassGenerator.cpp
index 87c04d370c9a5f10f43800b74ba588bea43a3755..3b5637402f0299edd36dc8e4d79e58c9b44a9a85 100644
--- a/Source/Rendering/VulkanRenderer/imstkVulkanRenderPassGenerator.cpp
+++ b/Source/Rendering/VulkanRenderer/imstkVulkanRenderPassGenerator.cpp
@@ -376,4 +376,74 @@ VulkanRenderPassGenerator::generateShadowRenderPass(
 
     vkCreateRenderPass(device, &renderPassInfo[0], nullptr, &renderPass);
 }
+
+
+void
+VulkanRenderPassGenerator::generateGUIRenderPass(
+    VkDevice& device, VkRenderPass& renderPass, VkSampleCountFlagBits& samples)
+{
+    VkAttachmentDescription attachments[1];
+
+    // Color attachment
+    attachments[0].flags = 0;
+    attachments[0].format = VK_FORMAT_B8G8R8A8_SRGB;
+    attachments[0].samples = samples;
+    attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+    attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+    attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+    attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+    attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    attachments[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+    // Color attachment
+    VkAttachmentReference diffuseReference;
+    diffuseReference.attachment = 0;
+    diffuseReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+    // Render subpasses
+    VkSubpassDescription subpassInfo[2];
+
+    // First pass: geometry
+    VkAttachmentReference colorAttachments[] = { diffuseReference };
+    subpassInfo[0].flags = 0;
+    subpassInfo[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+    subpassInfo[0].inputAttachmentCount = 0;
+    subpassInfo[0].pInputAttachments = nullptr;
+    subpassInfo[0].colorAttachmentCount = 1;
+    subpassInfo[0].pColorAttachments = colorAttachments;
+    subpassInfo[0].pResolveAttachments = nullptr;
+    subpassInfo[0].pDepthStencilAttachment = nullptr;
+    subpassInfo[0].preserveAttachmentCount = 0;
+    subpassInfo[0].pPreserveAttachments = nullptr;
+
+    VkSubpassDependency dependencies[2];
+    dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
+    dependencies[0].dstSubpass = 0;
+    dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+    dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
+    dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+    dependencies[0].dependencyFlags = 0;
+
+    dependencies[1].srcSubpass = 0;
+    dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
+    dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+    dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+    dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
+    dependencies[1].dependencyFlags = 0;
+
+    VkRenderPassCreateInfo renderPassInfo[1];
+    renderPassInfo[0].sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+    renderPassInfo[0].pNext = nullptr;
+    renderPassInfo[0].flags = 0;
+    renderPassInfo[0].attachmentCount = 1;
+    renderPassInfo[0].pAttachments = attachments;
+    renderPassInfo[0].subpassCount = 1;
+    renderPassInfo[0].pSubpasses = &subpassInfo[0];
+    renderPassInfo[0].dependencyCount = 2;
+    renderPassInfo[0].pDependencies = dependencies;
+
+    vkCreateRenderPass(device, &renderPassInfo[0], nullptr, &renderPass);
+}
 }
\ No newline at end of file
diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanRenderPassGenerator.h b/Source/Rendering/VulkanRenderer/imstkVulkanRenderPassGenerator.h
index 876dc0fff462883bb7a5273743fe9424d4e86789..3d6f4eb462cea430303ae5a19869b935fbed9283 100644
--- a/Source/Rendering/VulkanRenderer/imstkVulkanRenderPassGenerator.h
+++ b/Source/Rendering/VulkanRenderer/imstkVulkanRenderPassGenerator.h
@@ -33,6 +33,7 @@ public:
     static void generateOpaqueRenderPass(VkDevice& device, VkRenderPass& renderPass, VkSampleCountFlagBits& samples);
     static void generateDecalRenderPass(VkDevice& device, VkRenderPass& renderPass, VkSampleCountFlagBits& samples);
     static void generateShadowRenderPass(VkDevice& device, VkRenderPass& renderPass, VkSampleCountFlagBits& samples);
+    static void generateGUIRenderPass(VkDevice& device, VkRenderPass& renderPass, VkSampleCountFlagBits& samples);
 };
 }
 
diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.cpp b/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.cpp
index 814ddbd19cfcd18c872e9e289d578d63c35082b4..6d7ee5c81b426172be9d7fd526a8e90e7d455855 100644
--- a/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.cpp
+++ b/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.cpp
@@ -107,6 +107,8 @@ VulkanRenderer::initialize(unsigned int width, unsigned int height)
     pipelineCacheCreateInfo.pInitialData = nullptr;
 
     vkCreatePipelineCache(m_renderDevice, &pipelineCacheCreateInfo, nullptr, &m_pipelineCache);
+
+    this->setupGUI();
 }
 
 void
@@ -267,6 +269,7 @@ VulkanRenderer::setupRenderPasses()
     VulkanRenderPassGenerator::generateOpaqueRenderPass(m_renderDevice, m_opaqueRenderPass, m_samples);
     VulkanRenderPassGenerator::generateDecalRenderPass(m_renderDevice, m_decalRenderPass, m_samples);
     VulkanRenderPassGenerator::generateDepthRenderPass(m_renderDevice, m_depthRenderPass, m_samples);
+    VulkanRenderPassGenerator::generateGUIRenderPass(m_renderDevice, m_GUIRenderPass, m_samples);
 }
 
 void
@@ -969,6 +972,18 @@ VulkanRenderer::renderFrame()
         vkCmdEndRenderPass(m_postProcessingCommandBuffer[nextImageIndex]);
     }
 
+    // GUI renderpass
+    {
+        auto postProcessRenderPassBeginInfo = opaqueRenderPassBeginInfo;
+        postProcessRenderPassBeginInfo.renderPass = m_GUIRenderPass;
+        postProcessRenderPassBeginInfo.framebuffer = m_HDRTonemaps[nextImageIndex]->m_framebuffer->m_framebuffer;
+        postProcessRenderPassBeginInfo.clearValueCount = (uint32_t)m_HDRTonemaps[nextImageIndex]->m_framebuffer->m_attachments.size();
+
+        vkCmdBeginRenderPass(m_postProcessingCommandBuffer[nextImageIndex], &postProcessRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+        ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), m_postProcessingCommandBuffer[nextImageIndex]);
+        vkCmdEndRenderPass(m_postProcessingCommandBuffer[nextImageIndex]);
+    }
+
     vkEndCommandBuffer(m_postProcessingCommandBuffer[nextImageIndex]);
 
     VkCommandBuffer commandBuffers[2];
@@ -1441,6 +1456,73 @@ VulkanRenderer::setCommandBufferState(VkCommandBuffer * commandBuffer, uint32_t
     vkCmdSetScissor(*commandBuffer, 0, 1, &scissor);
 }
 
+void
+VulkanRenderer::setupGUI()
+{
+    std::array<VkDescriptorPoolSize, 11> descriptorPoolSizes;
+    descriptorPoolSizes[0] = { VK_DESCRIPTOR_TYPE_SAMPLER, 1024 };
+    descriptorPoolSizes[1] = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1024 };
+    descriptorPoolSizes[2] = { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1024 };
+    descriptorPoolSizes[3] = { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1024 };
+    descriptorPoolSizes[4] = { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1024 };
+    descriptorPoolSizes[5] = { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1024 };
+    descriptorPoolSizes[6] = { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1024 };
+    descriptorPoolSizes[7] = { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1024 };
+    descriptorPoolSizes[8] = { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1024 };
+    descriptorPoolSizes[9] = { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1024 };
+    descriptorPoolSizes[10] = { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1024 };
+
+    VkDescriptorPoolCreateInfo info;
+    info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+    info.pNext = nullptr;
+    info.flags = 0;
+    info.poolSizeCount = (uint32_t)descriptorPoolSizes.size();
+    info.pPoolSizes = &descriptorPoolSizes[0];
+    info.maxSets = 1024;
+    vkCreateDescriptorPool(m_renderDevice, &info, nullptr, &m_GUIDescriptorPool);
+
+    ImGui_ImplVulkan_InitInfo GUIInfo;
+    GUIInfo.Allocator = nullptr;
+    GUIInfo.CheckVkResultFn = nullptr;
+    GUIInfo.DescriptorPool = m_GUIDescriptorPool;
+    GUIInfo.Device = m_renderDevice;
+    GUIInfo.Instance = *m_instance;
+    GUIInfo.PhysicalDevice = m_physicalDevices[0];
+    GUIInfo.PipelineCache = m_pipelineCache;
+    GUIInfo.Queue = m_renderQueue;
+    GUIInfo.QueueFamily = m_renderQueueFamily;
+    ImGui_ImplVulkan_Init(&GUIInfo, m_GUIRenderPass);
+
+    VkCommandBufferBeginInfo commandBufferBeginInfo;
+    commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    commandBufferBeginInfo.pNext = nullptr;
+    commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+    commandBufferBeginInfo.pInheritanceInfo = nullptr;
+
+    vkBeginCommandBuffer(*m_memoryManager.m_transferCommandBuffer, &commandBufferBeginInfo);
+    ImGui_ImplVulkan_CreateFontsTexture(*m_memoryManager.m_transferCommandBuffer);
+    vkEndCommandBuffer(*m_memoryManager.m_transferCommandBuffer);
+
+    VkCommandBuffer commandBuffers[] = { *m_memoryManager.m_transferCommandBuffer };
+
+    VkPipelineStageFlags stageWaitFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+    VkSubmitInfo submitInfo[1];
+    submitInfo[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submitInfo[0].pNext = nullptr;
+    submitInfo[0].waitSemaphoreCount = 0;
+    submitInfo[0].pWaitSemaphores = nullptr;
+    submitInfo[0].pWaitDstStageMask = &stageWaitFlags;
+    submitInfo[0].commandBufferCount = 1;
+    submitInfo[0].pCommandBuffers = commandBuffers;
+    submitInfo[0].signalSemaphoreCount = 0;
+    submitInfo[0].pSignalSemaphores = nullptr;
+
+    vkQueueSubmit(m_renderQueue, 1, submitInfo, nullptr);
+
+    vkQueueWaitIdle(m_renderQueue);
+    ImGui_ImplVulkan_InvalidateFontUploadObjects();
+}
+
 VulkanRenderer::~VulkanRenderer()
 {
     // Delete devices
@@ -1464,6 +1546,8 @@ VulkanRenderer::~VulkanRenderer()
         // Delete framebuffers
         this->deleteFramebuffers();
 
+        vkDestroyDescriptorPool(m_renderDevice, m_GUIDescriptorPool, nullptr);
+
         // Delete shadows
         for (auto imageView : m_shadowMapsViews)
         {
diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.h b/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.h
index 218a97d7f91e1a39b6817f8104db061a0a3ebc29..78db21b3e6e02581ae971ac67c0e35f0bd50f574 100644
--- a/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.h
+++ b/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.h
@@ -33,6 +33,9 @@
 #include "glm/glm.hpp"
 #include "glm/gtc/matrix_transform.hpp"
 
+#include "imgui.h"
+#include "examples/imgui_impl_vulkan.h"
+
 #include "imstkScene.h"
 #include "imstkRenderer.h"
 #include "imstkDecalPool.h"
@@ -180,6 +183,11 @@ protected:
     ///
     void setCommandBufferState(VkCommandBuffer * commandBuffer, uint32_t width, uint32_t height);
 
+    ///
+    /// \brief Sets up GUI
+    ///
+    void setupGUI();
+
     unsigned int m_width = 1000;
     unsigned int m_height = 800;
     float m_fov = PI;
@@ -230,9 +238,12 @@ protected:
     std::vector<VkDescriptorSetLayout> m_globalDescriptorSetLayouts;
     std::vector<VkWriteDescriptorSet> m_globalWriteDescriptorSets;
 
+    VkDescriptorPool m_GUIDescriptorPool;
+
     VkRenderPass m_depthRenderPass;
     VkRenderPass m_opaqueRenderPass;
     VkRenderPass m_decalRenderPass;
+    VkRenderPass m_GUIRenderPass;
 
     // Swapchain
     VkSwapchainKHR * m_swapchain = nullptr;
diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanVertexBuffer.cpp b/Source/Rendering/VulkanRenderer/imstkVulkanVertexBuffer.cpp
index afcc4bfe7a736d9f55074f5fb40fe17d12cd9261..571a04915eef7f1c99ea2fdf64b33724323a223b 100644
--- a/Source/Rendering/VulkanRenderer/imstkVulkanVertexBuffer.cpp
+++ b/Source/Rendering/VulkanRenderer/imstkVulkanVertexBuffer.cpp
@@ -66,7 +66,6 @@ VulkanVertexBuffer::VulkanVertexBuffer(VulkanMemoryManager& memoryManager,
         {
             m_vertexBuffer = m_vertexStagingBuffer;
         }
-
     }
 
     // Index buffer
@@ -98,7 +97,6 @@ VulkanVertexBuffer::VulkanVertexBuffer(VulkanMemoryManager& memoryManager,
         {
             m_indexBuffer = m_indexStagingBuffer;
         }
-
     }
 }
 
@@ -239,5 +237,4 @@ VulkanVertexBuffer::getMode()
 {
     return m_mode;
 }
-
 }
\ No newline at end of file
diff --git a/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp b/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp
index 805c0e21d9098b9e24c0fe4f1790270ec7ea486b..4d642189794eab633d9fabb8a97bb1d8b4bd9b9f 100644
--- a/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp
+++ b/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp
@@ -32,10 +32,13 @@ VulkanViewer::VulkanViewer(SimulationManager * manager)
     interactor->m_simManager = m_simManager;
 
     m_interactorStyle = interactor;
+
+    // Create GUI
+    ImGui::CreateContext();
 }
 
 void
-VulkanViewer::setActiveScene(std::shared_ptr<Scene>scene)
+VulkanViewer::setActiveScene(std::shared_ptr<Scene> scene)
 {
     m_renderer = std::make_shared<VulkanRenderer>(scene);
     m_renderer->m_backgroundColor = m_backgroundColor;
@@ -97,10 +100,20 @@ VulkanViewer::startRenderingLoop()
 
     m_renderer->loadAllGeometry();
 
+    GUIOverlay::Utilities::initializeGUISystem();
+
     while (!glfwWindowShouldClose(m_window))
     {
-        m_renderer->renderFrame();
         glfwPollEvents();
+        ImGui_ImplVulkan_NewFrame();
+        ImGui_ImplGlfw_NewFrame();
+        ImGui::NewFrame();
+
+        m_canvas->render();
+
+        ImGui::Render();
+
+        m_renderer->renderFrame();
         std::dynamic_pointer_cast<VulkanInteractorStyle>(m_interactorStyle)->OnTimer();
     }
 
@@ -135,6 +148,12 @@ VulkanViewer::setupWindow()
         m_renderer->m_extensions.push_back((char*)tempExtensions[i]);
     }
 
+    // Keep resolution if not fullscreen
+    if (!m_fullscreen)
+    {
+        return;
+    }
+
     // find appropriate resolution
     int numMonitors;
     auto monitors = glfwGetMonitors(&numMonitors);
@@ -182,8 +201,10 @@ VulkanViewer::createWindow()
         m_window = glfwCreateWindow(m_width, m_height, "iMSTK", monitors[0], nullptr);
     }
 
+    // Wire window into GUI
+    ImGui_ImplGlfw_InitForVulkan(m_window, false);
+
     VkResult status = glfwCreateWindowSurface(*m_renderer->m_instance, m_window, nullptr, &m_surface);
-    std::cout << status << std::endl;
 
     std::dynamic_pointer_cast<VulkanInteractorStyle>(m_interactorStyle)->setWindow(m_window, this);
 }
diff --git a/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.h b/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.h
index 28cee677f78d740e458096fad2e7ea480bc7f4c5..40eda8861a6426f127499b8885abdde4ffdfcc02 100644
--- a/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.h
+++ b/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.h
@@ -25,12 +25,16 @@
 #include "vulkan/vulkan.h"
 #include "GLFW/glfw3.h"
 #include "g3log/g3log.hpp"
+#include "imgui.h"
+#include "examples/imgui_impl_glfw.h"
+
 #include <climits>
 
 #include "imstkVulkanRenderer.h"
 #include "imstkViewer.h"
 #include "imstkTimer.h"
 #include "imstkVulkanInteractorStyle.h"
+#include "imstkGUIUtilities.h"
 
 namespace imstk
 {
diff --git a/Source/SimulationManager/imstkViewer.cpp b/Source/SimulationManager/imstkViewer.cpp
index 1981a06923e992b0c09b79ce9b09a2f30861ae08..c3052d5e7eb4deade079fa82e9dae771e247dd20 100644
--- a/Source/SimulationManager/imstkViewer.cpp
+++ b/Source/SimulationManager/imstkViewer.cpp
@@ -47,6 +47,12 @@ Viewer::getScreenCaptureUtility() const
     return m_screenCapturer;
 }
 
+std::shared_ptr<GUIOverlay::Canvas>
+Viewer::getCanvas()
+{
+    return m_canvas;
+}
+
 void
 Viewer::setOnCharFunction(char c, EventHandlerFunction func)
 {
diff --git a/Source/SimulationManager/imstkViewer.h b/Source/SimulationManager/imstkViewer.h
index 636d1b7f978a69555120499007338e76abb2d2d1..6ae1c055038056eb1b946ad606dc97950c3ed433 100644
--- a/Source/SimulationManager/imstkViewer.h
+++ b/Source/SimulationManager/imstkViewer.h
@@ -28,6 +28,7 @@
 #include "imstkRenderer.h"
 #include "imstkScreenCaptureUtility.h"
 #include "imstkInteractorStyle.h"
+#include "imstkGUICanvas.h"
 
 namespace imstk
 {
@@ -42,7 +43,7 @@ class Viewer
 {
 public:
 
-    Viewer(){};
+    Viewer() {};
 
     Viewer(SimulationManager * manager){};
 
@@ -98,6 +99,11 @@ public:
     ///
     virtual void setBackgroundColors(const Vec3d color1, const Vec3d color2 = Vec3d::Zero(), const bool gradientBackground = false) = 0;
 
+    ///
+    /// \brief Get canvas
+    ///
+    std::shared_ptr<GUIOverlay::Canvas> getCanvas();
+
     ///
     /// \brief Set custom event handlers on interactor style
     ///
@@ -128,6 +134,7 @@ protected:
     std::shared_ptr<InteractorStyle> m_interactorStyle;
 
     bool m_running = false;
+    std::shared_ptr<GUIOverlay::Canvas> m_canvas = std::make_shared<GUIOverlay::Canvas>();;
 };
 }