diff --git a/config/Sources.cmake b/config/Sources.cmake
index 6cf9c6f4663c4307ee6c9350941cbe6e2f2b5a2c..1b3af31e82a5475d7d0791848fee123d62bf917c 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -54,6 +54,8 @@ set(vkcv_sources
 		${vkcv_include}/vkcv/PipelineConfig.hpp
 		${vkcv_source}/vkcv/PipelineConfig.cpp
 		
+		${vkcv_include}/vkcv/Interpolation.hpp
+		
 		${vkcv_include}/vkcv/Logger.hpp
 		
 		${vkcv_include}/vkcv/ShaderStage.hpp
diff --git a/include/vkcv/Interpolation.hpp b/include/vkcv/Interpolation.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c38a7aa746e36a3a58a0c3dd1c94db549ba101e7
--- /dev/null
+++ b/include/vkcv/Interpolation.hpp
@@ -0,0 +1,121 @@
+#pragma once
+/**
+ * @authors Tobias Frisch
+ * @file vkcv/Interpolation.hpp
+ * @brief Structure for interpolation
+ */
+ 
+#include <algorithm>
+#include <cmath>
+#include <functional>
+#include <vector>
+
+namespace vkcv {
+	
+	template<typename V, typename T = double>
+	struct interpolation_function {
+		typedef std::function<V(const V&, const V&, T)> type;
+	};
+	
+	template<typename V, typename T = double>
+	struct interpolation_state {
+		T time;
+		V value;
+		
+		bool operator<(const interpolation_state& other) const {
+			return time < other.time;
+		}
+	};
+	
+	template<typename V, typename T = double>
+	struct interpolation {
+	private:
+		typename interpolation_function<V, T>::type m_function;
+		std::vector< interpolation_state<V, T> > m_states;
+	
+	public:
+		interpolation(const typename interpolation_function<V, T>::type& function)
+		: m_function(function), m_states() {}
+		
+		interpolation(const interpolation& other) = default;
+		interpolation(interpolation&& other) noexcept = default;
+		
+		~interpolation() = default;
+		
+		interpolation& operator=(const interpolation& other) = default;
+		interpolation& operator=(interpolation&& other) noexcept = default;
+		
+		void clear() {
+			m_states.clear();
+		}
+		
+		void add(T time, const V& value) {
+			interpolation_state<V, T> state;
+			state.time = time;
+			state.value = value;
+			m_states.insert(
+					std::lower_bound(m_states.begin(), m_states.end(), state),
+					state
+			);
+		}
+		
+		V operator()(T time) const {
+			interpolation_state<V, T> state;
+			state.time = time;
+			
+			auto end = std::lower_bound(m_states.begin(), m_states.end(), state);
+			auto start = end != m_states.begin()? (end - 1) : m_states.begin();
+			
+			if (end == m_states.end()) {
+				end = start;
+			}
+			
+			const T ratio = (time - (*start).time) / ((*end).time - (*start).time);
+			
+			return m_function(
+					(*start).value,
+					(*end).value,
+					std::clamp<T>(
+							ratio,
+							static_cast<T>(0),
+							static_cast<T>(1)
+					)
+			);
+		}
+	
+	};
+	
+	template<typename V, typename T = double>
+	interpolation<V, T> linearInterpolation() {
+		return interpolation<V, T>([](const V& start, const V& end, T ratio) {
+			return start * (static_cast<T>(1) - ratio) + end * ratio;
+		});
+	}
+	
+	template<typename V, typename T = double>
+	interpolation<V, T> cubicInterpolation() {
+		return interpolation<V, T>([](const V& start, const V& end, T ratio) {
+			const T r0 = (static_cast<T>(1) - ratio) * (static_cast<T>(1) - ratio);
+			const T r1 = ratio * ratio;
+			
+			return (
+				start * r0 +
+				start * r0 * ratio * static_cast<T>(2) +
+				end * r1 * (static_cast<T>(1) - ratio) * static_cast<T>(2) +
+				end * r1
+			);
+		});
+	}
+	
+	template<typename V, typename T = double>
+	interpolation<V, T> cosInterpolation() {
+		return interpolation<V, T>([](const V& start, const V& end, T ratio) {
+			const T cos_ratio = (static_cast<T>(1) - std::cos(
+					ratio * static_cast<T>(M_PI)
+			)) / static_cast<T>(2);
+			
+			return start * (static_cast<T>(1) - cos_ratio) + end * cos_ratio;
+		});
+	}
+	
+}
\ No newline at end of file
diff --git a/modules/camera/CMakeLists.txt b/modules/camera/CMakeLists.txt
index 0bc5ce6cbbab55abebce376820f2ba398267cdd5..dbe5c85c0ae839a0b0ab8c3de059c442d22f2d59 100644
--- a/modules/camera/CMakeLists.txt
+++ b/modules/camera/CMakeLists.txt
@@ -18,8 +18,6 @@ set(vkcv_camera_sources
 		${vkcv_camera_source}/vkcv/camera/PilotCameraController.cpp
 		${vkcv_camera_include}/vkcv/camera/TrackballCameraController.hpp
 		${vkcv_camera_source}/vkcv/camera/TrackballCameraController.cpp
-		${vkcv_camera_include}/vkcv/camera/InterpolationLinear.hpp
-		${vkcv_camera_source}/vkcv/camera/InterpolationLinear.cpp
 )
 
 # adding source files to the project
diff --git a/modules/camera/include/vkcv/camera/InterpolationLinear.hpp b/modules/camera/include/vkcv/camera/InterpolationLinear.hpp
deleted file mode 100644
index cdcf0af62603b6db642a2db81ec610ab8e48cedc..0000000000000000000000000000000000000000
--- a/modules/camera/include/vkcv/camera/InterpolationLinear.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#include <glm/glm.hpp>
-#include <GLFW/glfw3.h>
-#include <vkcv/camera/Camera.hpp>
-#include <vector>
-
-namespace vkcv::camera {
-
-    class InterpolationLinear{
-
-    private:
-        
-        Camera& m_camera;
-        double m_timeSinceStart; 
-        std::vector<glm::vec3> m_positions;
-
-
-    public:
-
-        InterpolationLinear(Camera &camera);
-        
-        /**
-         * @brief Add position vector to be approached. The positions are approached in the order in which they where added.
-         * 
-         * @param pos 
-         */
-        void addPosition(const glm::vec3& pos);
-        
-        /**
-         * @brief Set the Camera object
-         * 
-         * @param camera 
-         */
-        void setCamera(Camera camera);
-
-        /**
-         * @brief Resets timer
-         * 
-         */
-        void resetTimer();
-        
-        /**
-         * @brief Updates the camera with the interpolated position values
-         * 
-         */
-        void updateCamera();
-    };
-
-}
\ No newline at end of file
diff --git a/modules/camera/src/vkcv/camera/InterpolationLinear.cpp b/modules/camera/src/vkcv/camera/InterpolationLinear.cpp
deleted file mode 100644
index ac73f095f00d5a755dbda34d062e29b11508bd32..0000000000000000000000000000000000000000
--- a/modules/camera/src/vkcv/camera/InterpolationLinear.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "vkcv/camera/InterpolationLinear.hpp"
-#include <vkcv/Logger.hpp>
-#include <iostream>
-
-
-namespace vkcv::camera {
-
-    InterpolationLinear::InterpolationLinear(Camera &camera)
-    : m_camera(camera) {
-        resetTimer();
-    }
-
-    void InterpolationLinear::resetTimer() {
-        m_timeSinceStart = glfwGetTime();
-    }
-
-    void InterpolationLinear::addPosition(const glm::vec3& pos) {
-        m_positions.push_back(pos);
-    }
-
-    glm::vec3 interpolate(glm::vec3 posA, glm::vec3 posB, double time, double duration) {
-        glm::vec3 posDiff = posB - posA;
-        glm::vec3 posInterp = posA + (posDiff * static_cast<float>(time / duration));
-        return posInterp;
-    }
-
-    void InterpolationLinear::updateCamera() {
-
-        if (m_positions.size() < 2) {
-            vkcv_log(LogLevel::ERROR, "At least 2 positions needed for interpolation.");
-            return;
-        }
-        double t = glfwGetTime() - m_timeSinceStart;
-        double segmentDuration = 2.0;
-        int numberOfSegments = m_positions.size()-1;
-        double totalDuration = numberOfSegments * segmentDuration;
-        double modt = fmod(t, totalDuration);
-
-        int currentSegment = static_cast<int>((modt / totalDuration) *  numberOfSegments);
-
-        glm::vec3 posInterp = interpolate(m_positions[currentSegment], m_positions[currentSegment+1], fmod(modt, segmentDuration), segmentDuration);
-
-        // const glm::vec3 front = m_camera.getFront();
-		// const glm::vec3 up = m_camera.getUp();
-
-        // m_camera.lookAt(posInterp, front+posInterp, up);
-
-        m_camera.setPosition(posInterp); // always look at center
-    }
-}
\ No newline at end of file
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index cc6d93a2efa37f3b3f1d6a45fe03a28ace686226..0070b51eb51f81422af49b641a860f75ec832b3f 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -1,11 +1,10 @@
 #include <iostream>
 #include <vkcv/Core.hpp>
 #include <vkcv/Image.hpp>
+#include <vkcv/Interpolation.hpp>
 #include <vkcv/Pass.hpp>
 #include <vkcv/Sampler.hpp>
 #include <vkcv/camera/CameraManager.hpp>
-#include <vkcv/camera/InterpolationLinear.hpp>
-#include <chrono>
 
 #include <vkcv/asset/asset_loader.hpp>
 #include <vkcv/shader/GLSLCompiler.hpp>
@@ -115,14 +114,14 @@ int main(int argc, const char** argv) {
 	cameraManager.getCamera(camHandle1).setPosition(glm::vec3(0, 0, -3));
 	cameraManager.getCamera(camHandle2).setPosition(glm::vec3(0, 0, -3));
 	
-	vkcv::camera::InterpolationLinear interp (cameraManager.getCamera(camHandle0));
+	auto interp = vkcv::linearInterpolation<glm::vec3, float>();
 	
-	interp.addPosition(glm::vec3(5,5,-5));
-	interp.addPosition(glm::vec3(0,5,-5));
-	interp.addPosition(glm::vec3(0,-3,-3));
-	interp.addPosition(glm::vec3(3,0,-6));
-	interp.addPosition(glm::vec3(5,5,5));
-	interp.addPosition(glm::vec3(5,5,-5));
+	interp.add( 0.0f, glm::vec3(+5, +5, -5));
+	interp.add( 2.0f, glm::vec3(+0, +5, -5));
+	interp.add( 4.0f, glm::vec3(+0, -3, -3));
+	interp.add( 6.0f, glm::vec3(+3, +0, -6));
+	interp.add( 8.0f, glm::vec3(+5, +5, +5));
+	interp.add(10.0f, glm::vec3(+5, +5, -5));
 	
 	core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt,
 				 uint32_t swapchainWidth, uint32_t swapchainHeight) {
@@ -139,7 +138,9 @@ int main(int argc, const char** argv) {
 		}
 		
 		cameraManager.update(dt);
-		interp.updateCamera();
+		cameraManager.getCamera(camHandle0).setPosition(
+				interp(static_cast<float>(std::fmod<double>(t, 10.0)))
+		);
 		
         glm::mat4 mvp = cameraManager.getActiveCamera().getMVP();