diff --git a/shaders/visualize_grayscale.frag b/shaders/visualize_grayscale.frag
new file mode 100644
index 0000000000000000000000000000000000000000..9e90595ad7010ee3b04d821960baca0f0ae00fd1
--- /dev/null
+++ b/shaders/visualize_grayscale.frag
@@ -0,0 +1,13 @@
+#version 330 core
+
+in vec2 TexCoords;
+
+uniform sampler2D activeTexture;
+
+out vec4 FragColor;
+
+void main()
+{
+    float value = texture(activeTexture, TexCoords).r;
+    FragColor = vec4(vec3(value), 1.0);
+}
diff --git a/shaders/visualize_grayscale.vert b/shaders/visualize_grayscale.vert
new file mode 100644
index 0000000000000000000000000000000000000000..cd27ab7958cfa470a8b60aa7cfab7f5670aea150
--- /dev/null
+++ b/shaders/visualize_grayscale.vert
@@ -0,0 +1,12 @@
+#version 330 core
+
+layout(location = 0) in vec3 aPos;
+layout(location = 1) in vec2 aTexCoords;
+
+out vec2 TexCoords;
+
+void main()
+{
+    TexCoords = aTexCoords;
+    gl_Position = vec4(aPos, 1.0);
+}
diff --git a/src/FluidRenderer.cpp b/src/FluidRenderer.cpp
index 587fba79e588a0c4ef695f345bb280381df30486..c3fa0bbf085a5e1b16ab9555a331e71bf6ba1784 100644
--- a/src/FluidRenderer.cpp
+++ b/src/FluidRenderer.cpp
@@ -16,31 +16,47 @@ FluidRenderer::FluidRenderer(int width, int height, Camera* camera)
         init();
 }
 
-// Destructor
-FluidRenderer::~FluidRenderer() {
-    // Cleanup Normal Render Program
-    if (m_normalRenderProgram.fboTexture != 0) {
-        glDeleteTextures(1, &m_normalRenderProgram.fboTexture);
+void FluidRenderer::deleteFramebufferResources(ShaderProgram& shaderProgram) {
+    if (shaderProgram.fboTexture != 0) {
+        glDeleteTextures(1, &shaderProgram.fboTexture);
+        shaderProgram.fboTexture = 0;
     }
-    if (m_normalRenderProgram.depthRBO != 0) {
-        glDeleteRenderbuffers(1, &m_normalRenderProgram.depthRBO);
+    if (shaderProgram.depthRBO != 0) {
+        glDeleteRenderbuffers(1, &shaderProgram.depthRBO);
+        shaderProgram.depthRBO = 0;
     }
-    if (m_normalRenderProgram.fbo != 0) {
-        glDeleteFramebuffers(1, &m_normalRenderProgram.fbo);
+    if (shaderProgram.fbo != 0) {
+        glDeleteFramebuffers(1, &shaderProgram.fbo);
+        shaderProgram.fbo = 0;
     }
+}
+
+// Destructor
+FluidRenderer::~FluidRenderer() {
+    // Cleanup Normal Render Program
+    deleteFramebufferResources(m_normalRenderProgram);
 
     // Cleanup Depth Render Program
-    if (m_depthRenderProgram.fboTexture != 0) {
-        glDeleteTextures(1, &m_depthRenderProgram.fboTexture);
+    deleteFramebufferResources(m_depthRenderProgram);
+
+    // Cleanup Visualization Render Program
+    deleteFramebufferResources(m_visualizationProgram);
+
+    // Cleanup Shader Programs
+    if (m_visualizationProgram.programID != 0) {
+        glDeleteProgram(m_visualizationProgram.programID);
+        m_visualizationProgram.programID = 0;
     }
-    if (m_depthRenderProgram.depthRBO != 0) {
-        glDeleteRenderbuffers(1, &m_depthRenderProgram.depthRBO);
+    if (m_depthRenderProgram.programID != 0) {
+        glDeleteProgram(m_depthRenderProgram.programID);
+        m_depthRenderProgram.programID = 0;
     }
-    if (m_depthRenderProgram.fbo != 0) {
-        glDeleteFramebuffers(1, &m_depthRenderProgram.fbo);
+    if (m_normalRenderProgram.programID != 0) {
+        glDeleteProgram(m_normalRenderProgram.programID);
+        m_normalRenderProgram.programID = 0;
     }
 
-    std::cout << "FluidRenderer destroyed." << std::endl;
+    std::cout << "FluidRenderer destroyed and all resources cleaned up." << std::endl;
 }
 
 // Initialization
@@ -50,6 +66,7 @@ void FluidRenderer::init() {
     initShaders();
     initShaderUniforms();
     initFBOs();
+    initFullscreenQuad();
 }
 
 // Initialize GLEW
@@ -74,9 +91,8 @@ void FluidRenderer::initOpenGLSettings() {
     //glDebugMessageCallback(MessageCallback, 0);
 
     // Create and bind a Vertex Array Object (VAO) - mandatory for OpenGL 3.3+
-    GLuint vao;
-    glGenVertexArrays(1, &vao);
-    glBindVertexArray(vao);
+    glGenVertexArrays(1, &particles_vao);
+    glBindVertexArray(particles_vao);
 
     std::cout << "OpenGL settings initialized." << std::endl;
 }
@@ -115,6 +131,15 @@ void FluidRenderer::initShaders() {
     }
     glUseProgram(m_depthRenderProgram.programID);
     std::cout << "Depth Render Shaders initialized successfully." << std::endl;
+
+    // Visualization Shader
+    m_visualizationProgram.programID = loadShaders("../shaders/visualize_grayscale.vert", "../shaders/visualize_grayscale.frag");
+    if (m_visualizationProgram.programID == 0) {
+        std::cerr << "Failed to load Visualization Shaders." << std::endl;
+        exit(1);
+    }
+    glUseProgram(m_visualizationProgram.programID);
+    std::cout << "Visualization Shaders initialized successfully." << std::endl;
 }
 
 // Initialize Shader Uniforms
@@ -187,88 +212,96 @@ void FluidRenderer::initShaderUniforms() {
     glUniformMatrix4fv(m_depthRenderProgram.modelMatrixLoc, 1, GL_TRUE, modelMatrix.m);
 
     std::cout << "Depth Render Shader uniforms initialized." << std::endl;
-}
-
-// Initialize Framebuffers
-void FluidRenderer::initFBOs() {
-    // Initialize Normal Render Shader FBO
-    glGenFramebuffers(1, &m_normalRenderProgram.fbo);
-    glBindFramebuffer(GL_FRAMEBUFFER, m_normalRenderProgram.fbo);
 
-    glGenTextures(1, &m_normalRenderProgram.fboTexture);
-    glBindTexture(GL_TEXTURE_2D, m_normalRenderProgram.fboTexture);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_fbWidth, m_fbHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_normalRenderProgram.fboTexture, 0);
+    // Visualization Shader Uniforms
+    glUseProgram(m_visualizationProgram.programID);
 
-    glGenRenderbuffers(1, &m_normalRenderProgram.depthRBO);
-    glBindRenderbuffer(GL_RENDERBUFFER, m_normalRenderProgram.depthRBO);
-    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, m_fbWidth, m_fbHeight);
-    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_normalRenderProgram.depthRBO);
-
-    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
-        fprintf(stderr, "Normal Render Shader FBO not complete: 0x%X\n", glCheckFramebufferStatus(GL_FRAMEBUFFER));
+    m_visualizationProgram.positionAttribLoc = glGetAttribLocation(m_visualizationProgram.programID, "aPos");
+    if (m_visualizationProgram.positionAttribLoc == -1) {
+        fprintf(stderr, "Visualization Shader: Could not find attribute 'aPos'\n");
+    } else {
+        printf("Visualization Shader: Attribute 'aPos' location: %d\n", m_visualizationProgram.positionAttribLoc);
     }
 
-    // Initialize Depth Render Shader FBO
-    /*
-    glGenFramebuffers(1, &m_depthRenderProgram.fbo);
-    glBindFramebuffer(GL_FRAMEBUFFER, m_depthRenderProgram.fbo);
+    std::cout << "Visualization Shader uniforms initialized." << std::endl;
+}
 
-    glGenTextures(1, &m_depthRenderProgram.fboTexture);
-    glBindTexture(GL_TEXTURE_2D, m_depthRenderProgram.fboTexture);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, m_fbWidth, m_fbHeight, 0, GL_RED, GL_FLOAT, NULL); // Use GL_R32F for depth storage
+void FluidRenderer::initializeFramebuffer(ShaderProgram& shaderProgram, GLenum textureInternalFormat, GLenum textureFormat, GLenum textureType) {
+    // Generate and bind the framebuffer
+    glGenFramebuffers(1, &shaderProgram.fbo);
+    glBindFramebuffer(GL_FRAMEBUFFER, shaderProgram.fbo);
+
+    // Generate and bind the texture
+    glGenTextures(1, &shaderProgram.fboTexture);
+    glBindTexture(GL_TEXTURE_2D, shaderProgram.fboTexture);
+    glTexImage2D(GL_TEXTURE_2D, 0, textureInternalFormat, m_fbWidth, m_fbHeight, 0, textureFormat, textureType, NULL);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Ensure magnification filtering is set
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_depthRenderProgram.fboTexture, 0);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, shaderProgram.fboTexture, 0);
 
-    glGenRenderbuffers(1, &m_depthRenderProgram.depthRBO);
-    glBindRenderbuffer(GL_RENDERBUFFER, m_depthRenderProgram.depthRBO);
+    // Generate and bind the renderbuffer for depth
+    glGenRenderbuffers(1, &shaderProgram.depthRBO);
+    glBindRenderbuffer(GL_RENDERBUFFER, shaderProgram.depthRBO);
     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, m_fbWidth, m_fbHeight);
-    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthRenderProgram.depthRBO);
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, shaderProgram.depthRBO);
 
-    // Specify which color attachments will be used for rendering
+    // Specify the list of draw buffers
     GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
     glDrawBuffers(1, drawBuffers);
 
-    // Check if the Depth Render Shader FBO is complete
+    // Check framebuffer completeness
     if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
-        fprintf(stderr, "Depth Render Shader FBO not complete: 0x%X\n", glCheckFramebufferStatus(GL_FRAMEBUFFER));
+        fprintf(stderr, "Framebuffer not complete for shader program ID %d: 0x%X\n", shaderProgram.programID, glCheckFramebufferStatus(GL_FRAMEBUFFER));
+    } else {
+        std::cout << "Framebuffer initialized successfully for shader program ID " << shaderProgram.programID << "." << std::endl;
     }
 
-    // Unbind the framebuffer to return to default framebuffer
+    // Unbind the framebuffer to return to default
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
-    */
-   // Initialize Depth Render Shader FBO with RGB format
-    glGenFramebuffers(1, &m_depthRenderProgram.fbo);
-    glBindFramebuffer(GL_FRAMEBUFFER, m_depthRenderProgram.fbo);
-
-    glGenTextures(1, &m_depthRenderProgram.fboTexture);
-    glBindTexture(GL_TEXTURE_2D, m_depthRenderProgram.fboTexture);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_fbWidth, m_fbHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // RGB format
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_depthRenderProgram.fboTexture, 0);
+}
 
-    glGenRenderbuffers(1, &m_depthRenderProgram.depthRBO);
-    glBindRenderbuffer(GL_RENDERBUFFER, m_depthRenderProgram.depthRBO);
-    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, m_fbWidth, m_fbHeight);
-    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthRenderProgram.depthRBO);
+// Initialize Framebuffers
+void FluidRenderer::initFBOs() {
+    // Initialize Normal Render Shader FBO with GL_RGBA8
+    initializeFramebuffer(m_normalRenderProgram, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
 
-    // Specify which color attachments will be used for rendering
-    GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
-    glDrawBuffers(1, drawBuffers);
+    // Initialize Depth Render Shader FBO with GL_R32F
+    initializeFramebuffer(m_depthRenderProgram, GL_R32F, GL_RED, GL_FLOAT);
 
-    // Check if the Depth Render Shader FBO is complete
-    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
-        fprintf(stderr, "Depth Render Shader FBO not complete: 0x%X\n", glCheckFramebufferStatus(GL_FRAMEBUFFER));
-    }
+    // Initialize Visualization Render Shader FBO with GL_RGBA8
+    initializeFramebuffer(m_visualizationProgram, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
 
-    // Unbind the framebuffer to return to default framebuffer
-    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    std::cout << "All Framebuffers for Normal, Depth, and Visualization shaders initialized successfully." << std::endl;
+}
 
 
-    std::cout << "Framebuffers for both shaders initialized successfully." << std::endl;
+void FluidRenderer::initFullscreenQuad() {
+    float quadVertices[] = {
+        // positions   // texCoords
+        -1.0f,  1.0f, 0.0f,  0.0f, 1.0f,
+        -1.0f, -1.0f, 0.0f,  0.0f, 0.0f,
+         1.0f, -1.0f, 0.0f,  1.0f, 0.0f,
+
+        -1.0f,  1.0f, 0.0f,  0.0f, 1.0f,
+         1.0f, -1.0f, 0.0f,  1.0f, 0.0f,
+         1.0f,  1.0f, 0.0f,  1.0f, 1.0f
+    };
+
+    glGenVertexArrays(1, &quadVAO);
+    GLuint quadVBO;
+    glGenBuffers(1, &quadVBO);
+    glBindVertexArray(quadVAO);
+    glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
+    // Position attribute
+    glEnableVertexAttribArray(0);
+    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
+    // Texture Coord attribute
+    glEnableVertexAttribArray(1);
+    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
+    glBindVertexArray(0);
+
+    std::cout << "Fullscreen quad initialized." << std::endl;
 }
 
 // Resize Framebuffers
@@ -394,6 +427,8 @@ void FluidRenderer::renderNormalFrame(size_t particleCount, size_t boundaryCount
 
     // Use the Normal Render Shader program
     glUseProgram(m_normalRenderProgram.programID);
+    glBindVertexArray(particles_vao);
+
 
     // Update shader with camera projection matrix
     mat4 projectionMatrix = m_camera->getProjectionMatrix();
@@ -435,6 +470,7 @@ void FluidRenderer::renderDepthFrame(size_t particleCount, size_t boundaryCount)
 
     // Use the Depth Render Shader program
     glUseProgram(m_depthRenderProgram.programID);
+    glBindVertexArray(particles_vao);
 
     // Update shader with camera projection matrix
     mat4 projectionMatrix = m_camera->getProjectionMatrix();
@@ -472,6 +508,47 @@ void FluidRenderer::renderDepthFrame(size_t particleCount, size_t boundaryCount)
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
 }
 
+// Visualize Buffer
+void FluidRenderer::visualizeBuffer(RenderStage stage)
+{
+    // Bind the Visualization FBO
+    glBindFramebuffer(GL_FRAMEBUFFER, m_visualizationProgram.fbo);
+    glViewport(0, 0, m_fbWidth, m_fbHeight);
+    glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // White background for visualization
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    // Disable depth testing for visualization
+    glDisable(GL_DEPTH_TEST);
+
+    // Use the Visualization Shader Program
+    glUseProgram(m_visualizationProgram.programID);
+
+    // Retrieve the appropriate texture based on RenderStage
+    GLuint textureToBind = getTexture(stage);
+
+    if (textureToBind != 0) {
+        // Bind the texture to texture unit 0
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, textureToBind);
+        glUniform1i(glGetUniformLocation(m_visualizationProgram.programID, "activeTexture"), 0);
+
+        // Render the fullscreen quad
+        glBindVertexArray(quadVAO);
+        glDrawArrays(GL_TRIANGLES, 0, 6);
+        glBindVertexArray(0);
+    }
+    else {
+        // Handle the case where no valid texture is bound
+        std::cerr << "Invalid RenderStage selected for visualization." << std::endl;
+    }
+
+    // Re-enable depth testing
+    glEnable(GL_DEPTH_TEST);
+
+    // Unbind the framebuffer
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
 // Retrieve Texture Based on RenderStage
 GLuint FluidRenderer::getTexture(RenderStage stage) const {
     switch (stage) {
@@ -485,4 +562,9 @@ GLuint FluidRenderer::getTexture(RenderStage stage) const {
     }
 }
 
+// Getter for Visualization Texture
+GLuint FluidRenderer::getVisualizationTexture() const {
+    return m_visualizationProgram.fboTexture;
+}
+
 } // namespace FluidSimulation
\ No newline at end of file
diff --git a/src/FluidSimulationApp.cpp b/src/FluidSimulationApp.cpp
index 07fb536c94260b9f8e827bb44cf999c6823e177f..11d82f9826e3dca2db41081c52b9c6e5254f02a6 100644
--- a/src/FluidSimulationApp.cpp
+++ b/src/FluidSimulationApp.cpp
@@ -18,7 +18,7 @@ namespace FluidSimulation {
             45.0f,
             appSettings->width / (float)appSettings->height,
             0.1f,
-            30.0f
+            25.0f
         );
 
         m_fluidRenderer = new FluidRenderer(appSettings->width, appSettings->height, m_camera);
@@ -192,7 +192,6 @@ namespace FluidSimulation {
 
     void FluidSimulatorApp::RenderFluidView()
     {
-        // Render fluid simulation to FBO
         if (m_updatePhysics)
         {
             m_fluidSimulation->updateSimulation();
@@ -203,30 +202,37 @@ namespace FluidSimulation {
                     m_fluidSimulation->getBoundaryParticleCount()
                 );
             }
-            else 
+            else
             {
                 m_fluidRenderer->renderDepthFrame(
                     m_fluidSimulation->getParticleCount(),
                     m_fluidSimulation->getBoundaryParticleCount()
                 );
+
+                // After rendering the depth frame, perform visualization
+                m_fluidRenderer->visualizeBuffer(selectedStage);
             }
         }
-        
-        /*
+
         // Display FBO texture in ImGui window
         ImGui::Begin("Simulation");
 
         ImVec2 availableSize = ImGui::GetContentRegionAvail();
-        //ImGui::Image(()(intptr_)m_fluidRenderer->getFBOTexture(),
-        //             ImVec2(m_appsettings->width, m_appsettings->height));
-        ImGui::Image((ImTextureID)(uintptr_t)m_fluidRenderer->getFBOTexture(), availableSize, ImVec2(0, 1), ImVec2(1, 0)); // Flip Y-axis
+        GLuint textureID = 0;
 
-        ImGui::End();
-        */
-        ImGui::Begin("Simulation");
-
-        ImVec2 availableSize = ImGui::GetContentRegionAvail();
-        GLuint textureID = m_fluidRenderer->getTexture(selectedStage);
+        if (selectedStage == RenderStage::FinalOutput)
+        {
+            textureID = m_fluidRenderer->getTexture(selectedStage); // RGBA8
+        }
+        else if (selectedStage == RenderStage::DepthBuffer /* || other grayscale stages */)
+        {
+            // Use the visualization texture
+            textureID = m_fluidRenderer->getVisualizationTexture();
+        }
+        else
+        {
+            textureID = 0; // Handle other stages if needed
+        }
 
         if (textureID != 0)
         {
@@ -238,7 +244,6 @@ namespace FluidSimulation {
         }
 
         ImGui::End();
-
     }
 
     // Render function
diff --git a/src/include/FluidRenderer.h b/src/include/FluidRenderer.h
index cc6643a444f30650c9757e0ed1f221a850692927..40d20c2646aa855c51701e8042642d7d777656cf 100644
--- a/src/include/FluidRenderer.h
+++ b/src/include/FluidRenderer.h
@@ -21,8 +21,7 @@ enum class RenderStage {
 // Structure to encapsulate shader program details
 struct ShaderProgram {
     // Shader program ID
-    GLuint programID;
-
+    GLuint programID; 
     // Attribute locations
     GLuint positionAttribLoc;
 
@@ -62,12 +61,12 @@ struct ShaderProgram {
           depthRBO(0) {}
 };
 
-
 class FluidRenderer {
 private:
     // Shader programs
-    ShaderProgram m_normalRenderProgram; // For particle shaders
-    ShaderProgram m_depthRenderProgram;  // For depth shaders
+    ShaderProgram m_normalRenderProgram;     // For particle shaders
+    ShaderProgram m_depthRenderProgram;      // For depth shaders
+    ShaderProgram m_visualizationProgram;    // For visualization shaders
 
     // VBOs for particles and boundaries
     GLuint m_particleVBO;
@@ -80,12 +79,21 @@ private:
     // Pointer to the Camera object
     Camera* m_camera;
 
+    GLuint particles_vao;
+
+    // Fullscreen quad VAO
+    GLuint quadVAO;
+
     // Initialization helper methods
-    void initGLEW();               // Initialize GLEW
-    void initOpenGLSettings();     // Set up OpenGL state
-    void initShaders();            // Load and configure shaders
-    void initShaderUniforms();     // Configure shader uniforms
-    void initFBOs();               // Set up framebuffers for each shader program
+    void initGLEW();                    // Initialize GLEW
+    void initOpenGLSettings();          // Set up OpenGL state
+    void initShaders();                 // Load and configure shaders
+    void initShaderUniforms();          // Configure shader uniforms
+    void initializeFramebuffer(ShaderProgram& shaderProgram, GLenum textureInternalFormat, GLenum textureFormat, GLenum textureType);
+    void initFBOs();                    // Set up framebuffers for each shader program
+    void initFullscreenQuad();          // Set up fullscreen quad for visualization
+
+    void deleteFramebufferResources(ShaderProgram& shaderProgram);
 
     // Rendering helper methods
     void renderParticles(size_t particleCount, const ShaderProgram& shader);
@@ -97,16 +105,18 @@ public:
     ~FluidRenderer();
 
     // Public methods
-    void init();                               // Consolidated initialization function
+    void init();                                // Consolidated initialization function
     void resizeFBO(int newWidth, int newHeight); // Resize framebuffers
     void setVBOs(GLuint particleVBO, GLuint boundaryVBO); // Set VBOs
 
     // Separate rendering functions
     void renderNormalFrame(size_t particleCount, size_t boundaryCount); // Render using Normal Shaders
     void renderDepthFrame(size_t particleCount, size_t boundaryCount);  // Render using Depth Shaders
+    void visualizeBuffer(RenderStage stage);                           // Visualize selected render stage
 
-    // Method to retrieve textures based on RenderStage
-    GLuint getTexture(RenderStage stage) const;
+    // Methods to retrieve textures based on RenderStage
+    GLuint getTexture(RenderStage stage) const;            // Get original FBO texture
+    GLuint getVisualizationTexture() const;                // Get visualization FBO texture
 };
 
 } // namespace FluidSimulation