diff --git a/config/Sources.cmake b/config/Sources.cmake
index fefdb6d8c8400d50424fdb3c95d732c6c4ce08e2..1b35d798597d0c781d5c4e90679679a83fcedcb2 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -56,9 +56,6 @@ set(vkcv_sources
         
         ${vkcv_source}/vkcv/ImageLayoutTransitions.hpp
         ${vkcv_source}/vkcv/ImageLayoutTransitions.cpp
-        
-        ${vkcv_source}/vkcv/Framebuffer.hpp
-        ${vkcv_source}/vkcv/Framebuffer.cpp
 
 		${vkcv_include}/vkcv/VertexLayout.hpp
 		${vkcv_source}/vkcv/VertexLayout.cpp
diff --git a/include/vkcv/PassConfig.hpp b/include/vkcv/PassConfig.hpp
index b8e80c67c2b70e3a0e6e2732b950ccaed38da3bf..d9a5bcd83acca5f5ba86b4e6ce6973acbed89de6 100644
--- a/include/vkcv/PassConfig.hpp
+++ b/include/vkcv/PassConfig.hpp
@@ -53,7 +53,6 @@ namespace vkcv
 
     struct PassConfig
     {
-        PassConfig() = delete;
         explicit PassConfig(std::vector<AttachmentDescription> attachments) noexcept;
         std::vector<AttachmentDescription> attachments{};
     };
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index ced7867ee26e4b3d9d700eb3a7a46ec326b966e2..6ba3656f6c02077a868c5d99b1331fab5be0abe6 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -60,9 +60,19 @@ int main(int argc, const char** argv) {
 		vkcv::AttachmentLayout::PRESENTATION,
 		vkcv::AttachmentOperation::STORE,
 		vkcv::AttachmentOperation::CLEAR,
-		core.getSwapchainImageFormat());
+		core.getSwapchainImageFormat()
+	);
+	
+	const vkcv::AttachmentDescription depth_attachment(
+			vkcv::AttachmentLayout::UNDEFINED,
+			vkcv::AttachmentLayout::DEPTH_STENCIL_ATTACHMENT,
+			vkcv::AttachmentLayout::DEPTH_STENCIL_ATTACHMENT,
+			vkcv::AttachmentOperation::STORE,
+			vkcv::AttachmentOperation::CLEAR,
+			vk::Format::eD32Sfloat
+	);
 
-	vkcv::PassConfig trianglePassDefinition({ present_color_attachment });
+	vkcv::PassConfig trianglePassDefinition({ present_color_attachment, depth_attachment });
 	vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition);
 
 	if (!trianglePass) {
@@ -98,7 +108,18 @@ int main(int argc, const char** argv) {
 		cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count());
 		const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView();
 
-		core.renderMesh(trianglePass, trianglePipeline, windowWidth, windowHeight, sizeof(mvp), &mvp, vertexBuffer.getHandle(), indexBuffer.getHandle(), mesh.vertexGroups[0].numIndices);
+		core.renderMesh(
+				trianglePass,
+				trianglePipeline,
+				windowWidth,
+				windowHeight,
+				sizeof(mvp),
+				&mvp,
+				vertexBuffer.getHandle(),
+				indexBuffer.getHandle(),
+				mesh.vertexGroups[0].numIndices
+		);
+		
 		core.endFrame();
 	}
 	
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 5c924743c95f67f00095264f9d99308b1403b017..d24282f194e79c36096677b7f13d4b218911c3a1 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -14,7 +14,6 @@
 #include "DescriptorManager.hpp"
 #include "Surface.hpp"
 #include "ImageLayoutTransitions.hpp"
-#include "Framebuffer.hpp"
 
 namespace vkcv
 {
@@ -122,8 +121,7 @@ namespace vkcv
 
     PipelineHandle Core::createGraphicsPipeline(const PipelineConfig &config)
     {
-        const vk::RenderPass &pass = m_PassManager->getVkPass(config.m_PassHandle);
-        return m_PipelineManager->createPipeline(config, pass);
+        return m_PipelineManager->createPipeline(config, *m_PassManager);
     }
 
 
@@ -165,6 +163,13 @@ namespace vkcv
 		m_Context.getDevice().waitIdle();	// FIMXE: this is a sin against graphics programming, but its getting late - Alex
 		destroyTemporaryFramebuffers();
 	}
+	
+	vk::Framebuffer createFramebuffer(const vk::Device device, const vk::RenderPass& renderpass,
+									  const int width, const int height, const std::vector<vk::ImageView>& attachments) {
+		const vk::FramebufferCreateFlags flags = {};
+		const vk::FramebufferCreateInfo createInfo(flags, renderpass, attachments.size(), attachments.data(), width, height, 1);
+		return device.createFramebuffer(createInfo);
+	}
 
 	void Core::renderMesh(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, 
 		const int width, const int height, const size_t pushConstantSize, const void *pushConstantData,
@@ -175,6 +180,17 @@ namespace vkcv
 		}
 
 		const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle);
+		const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle);
+		
+		ImageHandle depthImage;
+		
+		for (const auto& attachment : passConfig.attachments) {
+			if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) {
+				depthImage = m_ImageManager->createImage(width, height, 1, attachment.format);
+				break;
+			}
+		}
+		
 		const vk::ImageView imageView	= m_swapchainImageViews[m_currentSwapchainImageIndex];
 		const vk::Pipeline pipeline		= m_PipelineManager->getVkPipeline(pipelineHandle);
         const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle);
@@ -182,19 +198,47 @@ namespace vkcv
 		const vk::Buffer vulkanVertexBuffer	= m_BufferManager->getBuffer(vertexBuffer);
 		const vk::Buffer vulkanIndexBuffer	= m_BufferManager->getBuffer(indexBuffer);
 
-		const vk::Framebuffer framebuffer = createFramebuffer(m_Context.getDevice(), renderpass, width, height, imageView);
+		std::vector<vk::ImageView> attachments;
+		attachments.push_back(imageView);
+		
+		if (depthImage) {
+			attachments.push_back(m_ImageManager->getVulkanImageView(depthImage));
+		}
+		
+		const vk::Framebuffer framebuffer = createFramebuffer(
+				m_Context.getDevice(),
+				renderpass,
+				width,
+				height,
+				attachments
+		);
+		
 		m_TemporaryFramebuffers.push_back(framebuffer);
 
 		SubmitInfo submitInfo;
 		submitInfo.queueType = QueueType::Graphics;
 		submitInfo.signalSemaphores = { m_SyncResources.renderFinished };
-		submitCommands(submitInfo, [renderpass, renderArea, imageView, framebuffer, pipeline, pipelineLayout, 
-			pushConstantSize, pushConstantData, vulkanVertexBuffer, indexCount, vulkanIndexBuffer](const vk::CommandBuffer& cmdBuffer) {
-
-			const std::array<float, 4> clearColor = { 0.f, 0.f, 0.f, 1.f };
-			const vk::ClearValue clearValues(clearColor);
-
-			const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, 1, &clearValues);
+		submitCommands(submitInfo, [&](const vk::CommandBuffer& cmdBuffer) {
+			std::vector<vk::ClearValue> clearValues;
+			
+			for (const auto& attachment : passConfig.attachments) {
+				if (attachment.load_operation == AttachmentOperation::CLEAR) {
+					float clear = 0.0f;
+					
+					if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) {
+						clear = 1.0f;
+					}
+					
+					clearValues.emplace_back(std::array<float, 4>{
+							clear,
+							clear,
+							clear,
+							1.f
+					});
+				}
+			}
+
+			const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
 			const vk::SubpassContents subpassContents = {};
 			cmdBuffer.beginRenderPass(beginInfo, subpassContents, {});
 
@@ -205,7 +249,9 @@ namespace vkcv
             cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData);
 			cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {});
 			cmdBuffer.endRenderPass();
-		}, nullptr);
+		}, [&]() {
+			m_ImageManager->destroyImage(depthImage);
+		});
 	}
 
 	void Core::endFrame() {
diff --git a/src/vkcv/Framebuffer.cpp b/src/vkcv/Framebuffer.cpp
deleted file mode 100644
index 3b3e8000668e460d476b211984e9e12249f066c0..0000000000000000000000000000000000000000
--- a/src/vkcv/Framebuffer.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "Framebuffer.hpp"
-
-namespace vkcv {
-	vk::Framebuffer createFramebuffer(const vk::Device device, const vk::RenderPass renderpass, 
-		const int width, const int height, const vk::ImageView imageView) {
-		const vk::FramebufferCreateFlags flags = {};
-		const uint32_t attachmentCount = 1;	// TODO: proper value
-		const vk::FramebufferCreateInfo createInfo(flags, renderpass, attachmentCount, &imageView, width, height, 1);
-		return device.createFramebuffer(createInfo, nullptr, {});
-	}
-}
\ No newline at end of file
diff --git a/src/vkcv/Framebuffer.hpp b/src/vkcv/Framebuffer.hpp
deleted file mode 100644
index 7d5d718adbde0c3f8eb8d97c539fb73f7771987f..0000000000000000000000000000000000000000
--- a/src/vkcv/Framebuffer.hpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-#include <vulkan/vulkan.hpp>
-
-namespace vkcv{
-	vk::Framebuffer createFramebuffer(const vk::Device device, const vk::RenderPass renderpass,
-		const int width, const int height, const vk::ImageView imageView);
-}
\ No newline at end of file
diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp
index 6716024e25071db1ca41247179278d342d62c3cd..3896d6bc4abdd24264ad5d468b49ebf08bd20be7 100644
--- a/src/vkcv/ImageManager.cpp
+++ b/src/vkcv/ImageManager.cpp
@@ -67,6 +67,12 @@ namespace vkcv {
 		vk::ImageUsageFlags imageUsageFlags = (
 				vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst
 		);
+		
+		const bool isDepthFormat = isDepthImageFormat(format);
+		
+		if (isDepthFormat) {
+			imageUsageFlags |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
+		}
 
 		const vk::Device& device = m_core->getContext().getDevice();
 
@@ -131,7 +137,7 @@ namespace vkcv {
 
 		vk::ImageAspectFlags aspectFlags;
 		
-		if (isDepthImageFormat(format)) {
+		if (isDepthFormat) {
 			aspectFlags = vk::ImageAspectFlagBits::eDepth;
 		} else {
 			aspectFlags = vk::ImageAspectFlagBits::eColor;
diff --git a/src/vkcv/PassManager.cpp b/src/vkcv/PassManager.cpp
index d69024a805f45cda549365c7cc97fc57f59ef926..26e5f290d04ebaf16940cd99386253b5ab3622cc 100644
--- a/src/vkcv/PassManager.cpp
+++ b/src/vkcv/PassManager.cpp
@@ -49,16 +49,16 @@ namespace vkcv
 
     PassManager::PassManager(vk::Device device) noexcept :
     m_Device{device},
-    m_RenderPasses{},
+    m_Passes{},
     m_NextPassId(0)
     {}
 
     PassManager::~PassManager() noexcept
     {
-        for(const auto &pass : m_RenderPasses)
-            m_Device.destroy(pass);
-
-        m_RenderPasses.clear();
+        for(const auto &pass : m_Passes)
+            m_Device.destroy(pass.m_Handle);
+	
+		m_Passes.clear();
         m_NextPassId = 0;
     }
 
@@ -90,46 +90,74 @@ namespace vkcv
                 colorAttachmentReferences.push_back(attachmentRef);
             }
 
-            vk::AttachmentDescription attachmentDesc({},
-                                                     format,
-                                                     vk::SampleCountFlagBits::e1,
-                                                     getVKLoadOpFromAttachOp(config.attachments[i].load_operation),
-                                                     getVkStoreOpFromAttachOp(config.attachments[i].store_operation),
-                                                     vk::AttachmentLoadOp::eDontCare,
-                                                     vk::AttachmentStoreOp::eDontCare,
-                                                     getVkLayoutFromAttachLayout(config.attachments[i].layout_initial),
-                                                     getVkLayoutFromAttachLayout(config.attachments[i].layout_final));
+            vk::AttachmentDescription attachmentDesc(
+            		{},
+            		format,
+            		vk::SampleCountFlagBits::e1,
+            		getVKLoadOpFromAttachOp(config.attachments[i].load_operation),
+            		getVkStoreOpFromAttachOp(config.attachments[i].store_operation),
+            		vk::AttachmentLoadOp::eDontCare,
+            		vk::AttachmentStoreOp::eDontCare,
+            		getVkLayoutFromAttachLayout(config.attachments[i].layout_initial),
+            		getVkLayoutFromAttachLayout(config.attachments[i].layout_final)
+			);
+            
             attachmentDescriptions.push_back(attachmentDesc);
         }
-        vk::SubpassDescription subpassDescription({},
-                                                  vk::PipelineBindPoint::eGraphics,
-                                                  0,
-                                                  {},
-                                                  static_cast<uint32_t>(colorAttachmentReferences.size()),
-                                                  colorAttachmentReferences.data(),
-                                                  {},
-                                                  pDepthAttachment,
-                                                  0,
-                                                  {});
-
-        vk::RenderPassCreateInfo passInfo({},
-                                          static_cast<uint32_t>(attachmentDescriptions.size()),
-                                          attachmentDescriptions.data(),
-                                          1,
-                                          &subpassDescription,
-                                          0,
-                                          {});
+        
+        const vk::SubpassDescription subpassDescription(
+        		{},
+        		vk::PipelineBindPoint::eGraphics,
+        		0,
+        		{},
+        		static_cast<uint32_t>(colorAttachmentReferences.size()),
+        		colorAttachmentReferences.data(),
+        		{},
+        		pDepthAttachment,
+        		0,
+        		{}
+        );
 
-        vk::RenderPass vkObject{nullptr};
-        if(m_Device.createRenderPass(&passInfo, nullptr, &vkObject) != vk::Result::eSuccess)
-            return PassHandle();
+        const vk::RenderPassCreateInfo passInfo(
+        		{},
+        		static_cast<uint32_t>(attachmentDescriptions.size()),
+        		attachmentDescriptions.data(),
+        		1,
+        		&subpassDescription,
+        		0,
+        		{}
+	  	);
 
-        m_RenderPasses.push_back(vkObject);
+        vk::RenderPass renderPass = m_Device.createRenderPass(passInfo);
+	
+		m_Passes.push_back({ renderPass, config });
 		return PassHandle(m_NextPassId++);
     }
 
     vk::RenderPass PassManager::getVkPass(const PassHandle &handle) const
     {
-        return m_RenderPasses[handle.getId()];
+    	const uint64_t id = handle.getId();
+    	
+    	if (id >= m_Passes.size()) {
+    		return nullptr;
+    	}
+    	
+    	auto& pass = m_Passes[id];
+    	
+        return pass.m_Handle;
+    }
+    
+    const PassConfig& PassManager::getPassConfig(const PassHandle &handle) const {
+		const uint64_t id = handle.getId();
+	
+		if (id >= m_Passes.size()) {
+			static PassConfig emptyConfig = PassConfig({});
+			return emptyConfig;
+		}
+	
+		auto& pass = m_Passes[id];
+	
+		return pass.m_Config;
     }
+    
 }
diff --git a/src/vkcv/PassManager.hpp b/src/vkcv/PassManager.hpp
index b6be2cb13d8d24bdb9759f8878917f99e31afbec..bfc20fe25ace95bd8d94832b953b6b14ab9cadee 100644
--- a/src/vkcv/PassManager.hpp
+++ b/src/vkcv/PassManager.hpp
@@ -10,8 +10,13 @@ namespace vkcv
     class PassManager
     {
     private:
+    	struct Pass {
+			vk::RenderPass m_Handle;
+			PassConfig m_Config;
+    	};
+    	
         vk::Device m_Device;
-        std::vector<vk::RenderPass> m_RenderPasses;
+        std::vector<Pass> m_Passes;
         uint64_t m_NextPassId;
     public:
         PassManager() = delete; // no default ctor
@@ -28,5 +33,9 @@ namespace vkcv
 
         [[nodiscard]]
         vk::RenderPass getVkPass(const PassHandle &handle) const;
+        
+        [[nodiscard]]
+        const PassConfig& getPassConfig(const PassHandle &handle) const;
+        
     };
 }
diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp
index 8b6202eb901f26c84585597e327c297902e54b03..f9c56b41fb60841f19edf294bd9adb739dd19691 100644
--- a/src/vkcv/PipelineManager.cpp
+++ b/src/vkcv/PipelineManager.cpp
@@ -23,8 +23,10 @@ namespace vkcv
         m_NextPipelineId = 0;
     }
 
-    PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, const vk::RenderPass &pass)
+    PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, PassManager& passManager)
     {
+		const vk::RenderPass &pass = passManager.getVkPass(config.m_PassHandle);
+    	
         const bool existsVertexShader = config.m_ShaderProgram.existsShader(ShaderStage::VERTEX);
         const bool existsFragmentShader = config.m_ShaderProgram.existsShader(ShaderStage::FRAGMENT);
         if (!(existsVertexShader && existsFragmentShader))
@@ -170,10 +172,34 @@ namespace vkcv
             m_Device.destroy(fragmentModule);
             return PipelineHandle();
         }
-
-        // graphics pipeline create
+	
+		const vk::PipelineDepthStencilStateCreateInfo depthStencilCreateInfo(
+				vk::PipelineDepthStencilStateCreateFlags(),
+				true,
+				true,
+				vk::CompareOp::eLessOrEqual,
+				false,
+				false,
+				{},
+				{},
+				0.0f,
+				1.0f
+		);
+	
+		const vk::PipelineDepthStencilStateCreateInfo* p_depthStencilCreateInfo = nullptr;
+		
+		const PassConfig& passConfig = passManager.getPassConfig(config.m_PassHandle);
+		
+		for (const auto& attachment : passConfig.attachments) {
+			if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) {
+				p_depthStencilCreateInfo = &depthStencilCreateInfo;
+				break;
+			}
+		}
+	
+		// graphics pipeline create
         std::vector<vk::PipelineShaderStageCreateInfo> shaderStages = { pipelineVertexShaderStageInfo, pipelineFragmentShaderStageInfo };
-        vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo(
+        const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo(
                 {},
                 static_cast<uint32_t>(shaderStages.size()),
                 shaderStages.data(),
@@ -183,7 +209,7 @@ namespace vkcv
                 &pipelineViewportStateCreateInfo,
                 &pipelineRasterizationStateCreateInfo,
                 &pipelineMultisampleStateCreateInfo,
-                nullptr,
+				p_depthStencilCreateInfo,
                 &pipelineColorBlendStateCreateInfo,
                 nullptr,
                 vkPipelineLayout,
diff --git a/src/vkcv/PipelineManager.hpp b/src/vkcv/PipelineManager.hpp
index b5c0948efa13a4021f424cc576f1403a1ec26ebe..896d0df1ce10f56d291ef1accf93f9783cdd9db4 100644
--- a/src/vkcv/PipelineManager.hpp
+++ b/src/vkcv/PipelineManager.hpp
@@ -4,6 +4,7 @@
 #include <vector>
 #include "vkcv/Handles.hpp"
 #include "vkcv/PipelineConfig.hpp"
+#include "PassManager.hpp"
 
 namespace vkcv
 {
@@ -25,7 +26,7 @@ namespace vkcv
         PipelineManager & operator=(const PipelineManager &other) = delete; // copy-assign op
         PipelineManager & operator=(PipelineManager &&other) = delete; // move-assign op
 
-        PipelineHandle createPipeline(const PipelineConfig &config, const vk::RenderPass &pass);
+        PipelineHandle createPipeline(const PipelineConfig &config, PassManager& passManager);
 
         [[nodiscard]]
         vk::Pipeline getVkPipeline(const PipelineHandle &handle) const;