diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..29c5e400
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,5 @@
+root = true
+
+[*.{c,cpp,h,hpp}]
+indent_style = space
+indent_size = 2
\ No newline at end of file
diff --git a/Assets/Cube.003.shmesh.shmeta b/Assets/Cube.003.shmesh.shmeta
index d41be546..207f3999 100644
--- a/Assets/Cube.003.shmesh.shmeta
+++ b/Assets/Cube.003.shmesh.shmeta
@@ -1,3 +1,3 @@
 Name: Cube.003
 ID: 110152941
-Type: 
+Type: 6
diff --git a/Assets/Cube.012.shmesh.shmeta b/Assets/Cube.012.shmesh.shmeta
index d5cd1090..3af04f93 100644
--- a/Assets/Cube.012.shmesh.shmeta
+++ b/Assets/Cube.012.shmesh.shmeta
@@ -1,3 +1,3 @@
 Name: Cube.012
 ID: 107348815
-Type: 
+Type: 6
diff --git a/Assets/Editor/Layouts/Default.ini b/Assets/Editor/Layouts/Default.ini
index 4ddc46c2..d7a7bf69 100644
--- a/Assets/Editor/Layouts/Default.ini
+++ b/Assets/Editor/Layouts/Default.ini
@@ -4,13 +4,13 @@ Size=1920,20
 Collapsed=0
 
 [Window][SHEditorMenuBar]
-Pos=0,24
-Size=1920,1036
+Pos=0,48
+Size=1920,1012
 Collapsed=0
 
 [Window][Hierarchy Panel]
-Pos=0,120
-Size=225,940
+Pos=0,197
+Size=308,863
 Collapsed=0
 DockId=0x00000004,0
 
@@ -20,29 +20,96 @@ Size=400,400
 Collapsed=0
 
 [Window][Inspector]
-Pos=1686,24
-Size=234,1036
+Pos=1528,48
+Size=392,1012
 Collapsed=0
 DockId=0x00000006,0
 
 [Window][Profiler]
-Pos=0,24
-Size=225,94
+Pos=0,48
+Size=308,147
 Collapsed=0
 DockId=0x00000003,0
 
 [Window][Viewport]
-Pos=227,24
-Size=1457,1036
+Pos=227,48
+Size=1457,1012
 Collapsed=0
-DockId=0x00000002,0
+DockId=0x0000000B,0
+
+[Window][�������������������������������������������������������������������������������������������������������������������������������������������������������������������o�]
+Pos=60,60
+Size=32,64
+Collapsed=0
+
+[Window][��������������������������������������������������������������������������������������������������������������������������������������������������������������������]
+Pos=60,60
+Size=999,581
+Collapsed=0
+
+[Window][���o�]
+Pos=60,60
+Size=32,64
+Collapsed=0
+
+[Window][����]
+Pos=60,60
+Size=553,422
+Collapsed=0
+
+[Window][]
+Pos=60,60
+Size=770,394
+Collapsed=0
+
+[Window][ Viewport]
+Pos=227,48
+Size=1457,1012
+Collapsed=0
+DockId=0x0000000B,0
+
+[Window][ Viewport]
+Pos=227,48
+Size=1457,1012
+Collapsed=0
+DockId=0x0000000B,0
+
+[Window][ Viewport]
+Pos=310,48
+Size=1216,715
+Collapsed=0
+DockId=0x0000000B,0
+
+[Window][V]
+Pos=310,722
+Size=1501,338
+Collapsed=0
+DockId=0x00000008,0
+
+[Window][p����]
+Pos=310,750
+Size=1501,310
+Collapsed=0
+DockId=0x0000000A,0
+
+[Window][ Asset Browser]
+Pos=310,765
+Size=1216,295
+Collapsed=0
+DockId=0x0000000C,0
 
 [Docking][Data]
-DockSpace       ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,55 Size=1920,1036 Split=X
-  DockNode      ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1684,1036 Split=X
-    DockNode    ID=0x00000001 Parent=0x00000005 SizeRef=225,1036 Split=Y Selected=0x1E6EB881
-      DockNode  ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881
-      DockNode  ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE
-    DockNode    ID=0x00000002 Parent=0x00000005 SizeRef=1293,1036 CentralNode=1 Selected=0x13926F0B
-  DockNode      ID=0x00000006 Parent=0xC5C9B8AB SizeRef=234,1036 Selected=0xE7039252
+DockSpace           ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
+  DockNode          ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1526,1036 Split=X
+    DockNode        ID=0x00000001 Parent=0x00000005 SizeRef=308,1036 Split=Y Selected=0x1E6EB881
+      DockNode      ID=0x00000003 Parent=0x00000001 SizeRef=225,147 Selected=0x1E6EB881
+      DockNode      ID=0x00000004 Parent=0x00000001 SizeRef=225,863 Selected=0xE096E5AE
+    DockNode        ID=0x00000002 Parent=0x00000005 SizeRef=1216,1036 Split=Y Selected=0xB41284E7
+      DockNode      ID=0x00000007 Parent=0x00000002 SizeRef=1501,672 Split=Y Selected=0xB41284E7
+        DockNode    ID=0x00000009 Parent=0x00000007 SizeRef=1501,700 Split=Y Selected=0xB41284E7
+          DockNode  ID=0x0000000B Parent=0x00000009 SizeRef=1501,715 CentralNode=1 Selected=0xB41284E7
+          DockNode  ID=0x0000000C Parent=0x00000009 SizeRef=1501,295 Selected=0xB128252A
+        DockNode    ID=0x0000000A Parent=0x00000007 SizeRef=1501,310 Selected=0xD446F7B6
+      DockNode      ID=0x00000008 Parent=0x00000002 SizeRef=1501,338 Selected=0xD9F31532
+  DockNode          ID=0x00000006 Parent=0xC5C9B8AB SizeRef=392,1036 Selected=0xE7039252
 
diff --git a/Assets/Editor/Layouts/UserLayout.ini b/Assets/Editor/Layouts/UserLayout.ini
index 4d608401..e27f5cca 100644
--- a/Assets/Editor/Layouts/UserLayout.ini
+++ b/Assets/Editor/Layouts/UserLayout.ini
@@ -10,9 +10,9 @@ Collapsed=0
 
 [Window][Hierarchy Panel]
 Pos=0,142
-Size=494,918
+Size=494,690
 Collapsed=0
-DockId=0x00000004,0
+DockId=0x00000007,0
 
 [Window][Debug##Default]
 Pos=60,60
@@ -43,12 +43,20 @@ Size=1151,1012
 Collapsed=0
 DockId=0x00000002,0
 
-[Docking][Data]
-DockSpace       ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
-  DockNode      ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1992,1036 Split=X
-    DockNode    ID=0x00000001 Parent=0x00000005 SizeRef=494,1036 Split=Y Selected=0x1E6EB881
-      DockNode  ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881
-      DockNode  ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE
-    DockNode    ID=0x00000002 Parent=0x00000005 SizeRef=1151,1036 CentralNode=1 Selected=0xB41284E7
-  DockNode      ID=0x00000006 Parent=0xC5C9B8AB SizeRef=271,1036 Selected=0xE7039252
+[Window][ Asset Browser]
+Pos=0,834
+Size=494,226
+Collapsed=0
+DockId=0x00000008,0
+
+[Docking][Data]
+DockSpace         ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
+  DockNode        ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1992,1036 Split=X
+    DockNode      ID=0x00000001 Parent=0x00000005 SizeRef=494,1036 Split=Y Selected=0x1E6EB881
+      DockNode    ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881
+      DockNode    ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Split=Y Selected=0xE096E5AE
+        DockNode  ID=0x00000007 Parent=0x00000004 SizeRef=494,690 Selected=0xE096E5AE
+        DockNode  ID=0x00000008 Parent=0x00000004 SizeRef=494,226 Selected=0xB128252A
+    DockNode      ID=0x00000002 Parent=0x00000005 SizeRef=1151,1036 CentralNode=1 Selected=0xB41284E7
+  DockNode        ID=0x00000006 Parent=0xC5C9B8AB SizeRef=271,1036 Selected=0xE7039252
 
diff --git a/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta b/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta
index f8c267d9..3905aa4f 100644
--- a/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta
+++ b/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta
@@ -1,3 +1,3 @@
 Name: RaccoonPreTexturedVer1_Base9
 ID: 91918845
-Type: 
+Type: 4
diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp
index e33bdf8a..54dc0ccf 100644
--- a/SHADE_Application/src/Application/SBApplication.cpp
+++ b/SHADE_Application/src/Application/SBApplication.cpp
@@ -56,8 +56,8 @@ namespace Sandbox
     _In_      INT       nCmdShow
   )
   {
-	  // Set working directory
-	  SHFileUtilities::SetWorkDirToExecDir();
+    // Set working directory
+    SHFileUtilities::SetWorkDirToExecDir();
 
     window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
 
@@ -83,11 +83,13 @@ namespace Sandbox
     SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::LateUpdateRoutine>();
     SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::FrameCleanUpRoutine>();
 
+    SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostLogicUpdate>();
+
     SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>();
     SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>();
     SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
 
-    SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformUpdateRoutine>();
+    SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
 
     SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>();
     SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>();
@@ -150,16 +152,16 @@ namespace Sandbox
         SHSceneManager::SceneUpdate(0.016f);
 #endif
       SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f);
-      //editor->PollPicking();
+      editor->PollPicking();
     }
     // Finish all graphics jobs first
-	  graphicsSystem->AwaitGraphicsExecution();
+    graphicsSystem->AwaitGraphicsExecution();
   }
 
 
   void SBApplication::Exit(void)
   {
-	#ifdef SHEDITOR
+  #ifdef SHEDITOR
     SDL_DestroyWindow(sdlWindow);
     SDL_Quit();
   #endif
diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp
index 9c178429..a06e68c2 100644
--- a/SHADE_Application/src/Scenes/SBTestScene.cpp
+++ b/SHADE_Application/src/Scenes/SBTestScene.cpp
@@ -53,7 +53,7 @@ namespace Sandbox
           if (asset.name == "Cube.012")
           handles.emplace_back(SHResourceManager::LoadOrGet<SHMesh>(asset.id));
           break;
-        case AssetType::TEXTURE:
+        case AssetType::IMAGE:
           texHandles.emplace_back(SHResourceManager::LoadOrGet<SHTexture>(asset.id));
           break;
       }
@@ -68,9 +68,9 @@ namespace Sandbox
     customMat->SetProperty("data.alpha", 0.1f);
 
     // Create Stress Test Objects
-    static const SHVec3 TEST_OBJ_SCALE = SHVec3::One * 0.5f;
-    constexpr int NUM_ROWS = 0;
-    constexpr int NUM_COLS = 0;
+    static const SHVec3 TEST_OBJ_SCALE = SHVec3::One;
+    constexpr int NUM_ROWS = 3;
+    constexpr int NUM_COLS = 1;
     static const SHVec3 TEST_OBJ_SPACING = { 0.1f, 0.1f, 0.1f };
     static const SHVec3 TEST_OBJ_START_POS = { -(NUM_COLS / 2 * TEST_OBJ_SPACING.x) + 1.0f, -2.0f, -1.0f };
 
@@ -92,13 +92,13 @@ namespace Sandbox
         //Set initial positions
         transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ x * TEST_OBJ_SPACING.x, y * TEST_OBJ_SPACING.y, SHMath::GenerateRandomNumber(-3.5f, -5.0f) });
         //transform.SetWorldPosition({-1.0f, -1.0f, -1.0f});
-        transform.SetWorldRotation(SHMath::GenerateRandomNumber(), SHMath::GenerateRandomNumber(), SHMath::GenerateRandomNumber());
+        transform.SetWorldRotation(SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f));
         transform.SetWorldScale(TEST_OBJ_SCALE);
 
-        if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN)
+        //if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN)
           collider.AddBoundingBox(SHVec3::One * 0.5f, SHVec3::Zero);
-        else
-          collider.AddBoundingSphere(0.5f, SHVec3::Zero);
+        //else
+        //  collider.AddBoundingSphere(0.5f, SHVec3::Zero);
 
         stressTestObjects.emplace_back(entity);
       }
diff --git a/SHADE_Engine/SHAnimationAsset.h b/SHADE_Engine/SHAnimationAsset.h
new file mode 100644
index 00000000..d8d0ffb1
--- /dev/null
+++ b/SHADE_Engine/SHAnimationAsset.h
@@ -0,0 +1,30 @@
+/*************************************************************************//**
+ * \file    SHAnimationAsset.h
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+#pragma once
+
+#include <vector>
+#include <assimp/anim.h>
+#include "SH_API.power h"
+
+namespace SHADE
+{
+	struct SH_API SHAnimationAsset
+	{
+		std::string name;
+
+		std::vector<aiNodeAnim*> nodeChannels;
+		std::vector<aiMeshAnim*> meshChannels;
+		std::vector<aiMeshMorphAnim*> morphMeshChannels;
+
+		double duration;
+		double ticksPerSecond;
+	};
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAnimationAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHAnimationAsset.h
new file mode 100644
index 00000000..b411a11e
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Asset Types/SHAnimationAsset.h	
@@ -0,0 +1,30 @@
+/*************************************************************************//**
+ * \file    SHAnimationAsset.h
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+#pragma once
+
+#include <vector>
+#include <assimp/anim.h>
+#include "SHAssetData.h"
+
+namespace SHADE
+{
+	struct SH_API SHAnimationAsset : SHAssetData
+	{
+		std::string name;
+
+		std::vector<aiNodeAnim*> nodeChannels;
+		std::vector<aiMeshAnim*> meshChannels;
+		std::vector<aiMeshMorphAnim*> morphMeshChannels;
+
+		double duration;
+		double ticksPerSecond;
+	};
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAssetData.h b/SHADE_Engine/src/Assets/Asset Types/SHAssetData.h
new file mode 100644
index 00000000..8db9824c
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Asset Types/SHAssetData.h	
@@ -0,0 +1,19 @@
+/*************************************************************************//**
+ * \file    SHAssetDataBase.h
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+#pragma once
+
+namespace SHADE
+{
+	struct SHAssetData
+	{
+		virtual ~SHAssetData(){}
+	};
+}
diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAssetIncludes.h b/SHADE_Engine/src/Assets/Asset Types/SHAssetIncludes.h
new file mode 100644
index 00000000..1c1ed44a
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Asset Types/SHAssetIncludes.h	
@@ -0,0 +1,4 @@
+#pragma once
+
+#include "SHMeshAsset.h"
+#include "SHTextureAsset.h"
\ No newline at end of file
diff --git a/SHADE_Engine/src/Assets/Asset Types/SHInternalAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHInternalAsset.h
new file mode 100644
index 00000000..8bef34e9
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Asset Types/SHInternalAsset.h	
@@ -0,0 +1,21 @@
+/*************************************************************************//**
+ * \file    SHInternalAsset.h
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+#pragma once
+
+#include "SHAsset.h"
+
+namespace SHADE
+{
+	struct SHInternalAsset : SHAsset
+	{
+		
+	};
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h
index 68c0d150..20b442ba 100644
--- a/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h	
+++ b/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h	
@@ -14,7 +14,7 @@
 
 #include <vector>
 #include "Math/SHMath.h"
-#include "SH_API.h"
+#include "SHAssetData.h"
 
 namespace SHADE
 {
@@ -22,10 +22,10 @@ namespace SHADE
 	{
 		uint32_t vertexCount;
 		uint32_t indexCount;
-		std::string meshName;
+		std::string name;
 	};
 
-	struct SH_API SHMeshAsset
+	struct SH_API SHMeshAsset : SHAssetData
 	{
 		bool compiled;
 		bool changed;
diff --git a/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h
index d24b6c02..d26a2c30 100644
--- a/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h	
+++ b/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h	
@@ -2,10 +2,11 @@
 
 #include "tinyddsloader.h"
 #include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h"
+#include "SHAssetData.h"
 
 namespace SHADE
 {
-	struct SHTextureAsset
+	struct SHTextureAsset : SHAssetData
 	{
 		bool compiled;
 
diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssetLoader.h b/SHADE_Engine/src/Assets/Libraries/SHAssetLoader.h
new file mode 100644
index 00000000..41595519
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Libraries/SHAssetLoader.h
@@ -0,0 +1,21 @@
+/*************************************************************************//**
+ * \file    SHAssetLoader.h
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+#pragma once
+
+#include "Assets/Asset Types/SHAssetData.h"
+
+namespace SHADE
+{
+	struct SHAssetLoader
+	{
+		virtual SHAssetData* Load(AssetPath path) = 0;
+	};
+}
diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp
new file mode 100644
index 00000000..f4be0b68
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp
@@ -0,0 +1,141 @@
+/*************************************************************************//**
+ * \file    SHAssimpLibrary.cpp
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+#include "SHpch.h"
+#include "SHAssimpLibrary.h"
+#include <assimp/postprocess.h>
+
+namespace SHADE
+{
+	Assimp::Importer SHAssimpLibrary::aiImporter;
+
+	void SHAssimpLibrary::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept
+	{
+    for (size_t i {0}; i < node.mNumMeshes; ++i)
+    {
+      aiMesh* mesh = scene.mMeshes[node.mMeshes[i]];
+      meshes.push_back(ProcessMesh(*mesh));
+    }
+
+    for (size_t i{ 0 }; i < node.mNumChildren; ++i)
+    {
+      ProcessNode(*node.mChildren[i], scene, meshes);
+    }
+	}
+
+	void SHAssimpLibrary::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept
+	{
+		if (scene.HasAnimations())
+    {
+			std::vector<SHAnimationAsset> anims(scene.mNumAnimations);
+	    for (auto i{0}; i < scene.mNumAnimations; ++i)
+	    {
+		    auto const& anim {*scene.mAnimations[i]};
+
+        anims[i].name = anim.mName.C_Str();
+
+        anims[i].duration = anim.mDuration;
+        anims[i].ticksPerSecond = anim.mTicksPerSecond;
+
+        std::copy_n(anim.mChannels, anim.mNumChannels, anims[i].nodeChannels.data());
+        std::copy_n(anim.mMeshChannels, anim.mNumMeshChannels, anims[i].meshChannels.data());
+        std::copy_n(anim.mMorphMeshChannels, anim.mNumMorphMeshChannels, anims[i].morphMeshChannels.data());
+	    }
+    }
+	}
+
+	SHMeshAsset* SHAssimpLibrary::ProcessMesh(aiMesh const& mesh) noexcept
+	{
+    SHMeshAsset* result = new SHMeshAsset();
+    result->compiled = false;
+    result->changed = false;
+
+    for (size_t i{0}; i < mesh.mNumVertices; ++i)
+    {
+      // Vertex position
+      SHVec3 vertex;
+      vertex.x = mesh.mVertices[i].x;
+      vertex.y = mesh.mVertices[i].y;
+      vertex.z = mesh.mVertices[i].z;
+      result->vertexPosition.push_back(vertex);
+
+      // Tex coords
+      SHVec2 texCoord{0.f, 0.f};
+      if (mesh.mTextureCoords[0])
+      {
+        texCoord.x = mesh.mTextureCoords[0][i].x;
+        texCoord.y = mesh.mTextureCoords[0][i].y;
+      }
+      result->texCoords.push_back(texCoord);
+
+      // Normals
+      SHVec3 normal{0.f, 0.f, 0.f};
+      if (mesh.mNormals)
+      {
+        normal.x = mesh.mNormals[i].x;
+        normal.y = mesh.mNormals[i].y;
+        normal.z = mesh.mNormals[i].z;
+      }
+      result->vertexNormal.push_back(normal);
+
+      // Tangent
+      SHVec3 tangent{0.f, 0.f, 0.f};
+      if (mesh.mTangents)
+      {
+        tangent.x = mesh.mTangents[i].x;
+        tangent.y = mesh.mTangents[i].y;
+        tangent.z = mesh.mTangents[i].z;
+      }
+      result->vertexTangent.push_back(tangent);
+    }
+
+    for (size_t i {0}; i < mesh.mNumFaces; ++i)
+    {
+      aiFace face = mesh.mFaces[i];
+      for (size_t j{0}; j < face.mNumIndices; ++j)
+      {
+        result->indices.push_back(face.mIndices[j]);
+      }
+    }
+
+    result->header.vertexCount = static_cast<uint32_t>(result->vertexPosition.size());
+    result->header.indexCount = static_cast<uint32_t>(result->indices.size());
+    result->header.name = mesh.mName.C_Str();
+
+    return result;
+	}
+
+	void SHAssimpLibrary::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept
+	{
+    const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
+      aiProcess_Triangulate                 // Make sure we get triangles rather than nvert polygons
+      | aiProcess_GenUVCoords               // Convert any type of mapping to uv mapping
+      | aiProcess_TransformUVCoords         // preprocess UV transformations (scaling, translation ...)
+      | aiProcess_FindInstances             // search for instanced meshes and remove them by references to one master
+      | aiProcess_CalcTangentSpace          // calculate tangents and bitangents if possible
+      | aiProcess_JoinIdenticalVertices     // join identical vertices/ optimize indexing
+      | aiProcess_RemoveRedundantMaterials  // remove redundant materials
+      | aiProcess_FindInvalidData           // detect invalid model data, such as invalid normal vectors
+      | aiProcess_FlipUVs                   // flip the V to match the Vulkans way of doing UVs
+    );
+
+    if (!scene || !scene->HasMeshes())
+    {
+      SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string());
+      return;
+    }
+
+    ExtractAnimations(*scene, anims);
+
+    ProcessNode(*scene->mRootNode, *scene, meshes);
+
+    aiImporter.FreeScene();
+	}
+}
diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h
new file mode 100644
index 00000000..83755b4c
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h
@@ -0,0 +1,36 @@
+/*************************************************************************//**
+ * \file    SHAssimpLibrary.h
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+
+#pragma once
+#include <assimp/Importer.hpp>
+#include <assimp/scene.h>
+#include <vector>
+#include "../SHAssetMacros.h"
+#include "../Asset Types/SHMeshAsset.h"
+#include "../Asset Types/SHAnimationAsset.h"
+
+namespace SHADE
+{
+	class SHAssimpLibrary
+	{
+	private:
+		using MeshVectorRef = std::vector<SHMeshAsset*>&;
+		using AnimVectorRef = std::vector<SHAnimationAsset*>&;
+
+		static Assimp::Importer aiImporter;
+		static void ProcessNode(aiNode const& node, aiScene const& scene,MeshVectorRef meshes) noexcept;
+		static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept;
+		static SHMeshAsset* ProcessMesh(aiMesh const& mesh) noexcept;
+
+	public:
+		static void LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept;
+	};
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp
index 8026f0e1..2346714e 100644
--- a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp
+++ b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp
@@ -20,7 +20,7 @@ std::string SHADE::SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, A
 {
 	std::string newPath{ path.string() };
 	newPath = newPath.substr(0, newPath.find_last_of('/') + 1);
-	newPath += asset.header.meshName + MESH_EXTENSION;
+	newPath += asset.header.name + MESH_EXTENSION.data();
 
 	std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc };
 	if (!file.is_open())
diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp
index 4bfa2d9b..90dd58d4 100644
--- a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp
+++ b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp
@@ -12,129 +12,11 @@
  *****************************************************************************/
 #include "SHpch.h"
 #include "SHMeshLoader.h"
-#include <assimp/postprocess.h>
 #include <fstream>
 
 namespace SHADE
 {
-	Assimp::Importer SHMeshLoader::aiImporter;
-
-	void SHMeshLoader::ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes) noexcept
-	{
-    for (size_t i {0}; i < node.mNumMeshes; ++i)
-    {
-      aiMesh* mesh = scene.mMeshes[node.mMeshes[i]];
-      meshes.push_back(ProcessMesh(*mesh, scene));
-    }
-
-    for (size_t i{ 0 }; i < node.mNumChildren; ++i)
-    {
-      ProcessNode(*node.mChildren[i], scene, meshes);
-    }
-	}
-
-	SHMeshAsset SHMeshLoader::ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept
-	{
-    (void)scene;
-
-    SHMeshAsset result
-    {
-      .compiled { false},
-      .changed { false }
-    };
-
-    for (size_t i{0}; i < mesh.mNumVertices; ++i)
-    {
-      // Vertex position
-      SHVec3 vertex;
-      vertex.x = mesh.mVertices[i].x;
-      vertex.y = mesh.mVertices[i].y;
-      vertex.z = mesh.mVertices[i].z;
-      result.vertexPosition.push_back(vertex);
-
-      // Tex coords
-      SHVec2 texCoord{0.f, 0.f};
-      if (mesh.mTextureCoords[0])
-      {
-        texCoord.x = mesh.mTextureCoords[0][i].x;
-        texCoord.y = mesh.mTextureCoords[0][i].y;
-      }
-      result.texCoords.push_back(texCoord);
-
-      // Normals
-      SHVec3 normal{0.f, 0.f, 0.f};
-      if (mesh.mNormals)
-      {
-        normal.x = mesh.mNormals[i].x;
-        normal.y = mesh.mNormals[i].y;
-        normal.z = mesh.mNormals[i].z;
-      }
-      result.vertexNormal.push_back(normal);
-
-      // Tangent
-      SHVec3 tangent{0.f, 0.f, 0.f};
-      if (mesh.mTangents)
-      {
-        tangent.x = mesh.mTangents[i].x;
-        tangent.y = mesh.mTangents[i].y;
-        tangent.z = mesh.mTangents[i].z;
-      }
-      result.vertexTangent.push_back(tangent);
-    }
-
-    for (size_t i {0}; i < mesh.mNumFaces; ++i)
-    {
-      aiFace face = mesh.mFaces[i];
-      for (size_t j{0}; j < face.mNumIndices; ++j)
-      {
-        result.indices.push_back(face.mIndices[j]);
-      }
-    }
-
-    result.header.vertexCount = static_cast<uint32_t>(result.vertexPosition.size());
-    result.header.indexCount = static_cast<uint32_t>(result.indices.size());
-    result.header.meshName = mesh.mName.C_Str();
-
-    return result;
-	}
-
-	void SHMeshLoader::LoadExternal(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept
-	{
-    const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
-      aiProcess_Triangulate                 // Make sure we get triangles rather than nvert polygons
-      | aiProcess_GenUVCoords               // Convert any type of mapping to uv mapping
-      | aiProcess_TransformUVCoords         // preprocess UV transformations (scaling, translation ...)
-      | aiProcess_FindInstances             // search for instanced meshes and remove them by references to one master
-      | aiProcess_CalcTangentSpace          // calculate tangents and bitangents if possible
-      | aiProcess_JoinIdenticalVertices     // join identical vertices/ optimize indexing
-      | aiProcess_RemoveRedundantMaterials  // remove redundant materials
-      | aiProcess_FindInvalidData           // detect invalid model data, such as invalid normal vectors
-      | aiProcess_FlipUVs                   // flip the V to match the Vulkans way of doing UVs
-    );
-
-    if (!scene || !scene->HasMeshes())
-    {
-      SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string());
-      return;
-    }
-
-    //TODO MATERIALS FROM MESHES
-    //if (scene->HasMaterials())
-    //{
-    //  for (int i{0}; i < scene->mNumMaterials; ++i)
-    //  {
-    //    if (scene->mMaterials[i]->mNumProperties > 0)
-    //    {
-     //     for (int j{0}; j < scene->mMaterials[i]->mProperties[j].)
-    //    }
-        //std::cout << scene->mMaterials[i]->;
-    //  }
-    //}
-
-    ProcessNode(*scene->mRootNode, *scene, meshes);
-	}
-
-	void SHMeshLoader::LoadSHMesh(SHMeshAsset& mesh, AssetPath path) noexcept
+	void SHMeshLoader::LoadSHMesh(AssetPath path, SHMeshAsset& mesh) noexcept
 	{
     std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
     if (!file.is_open())
@@ -168,45 +50,13 @@ namespace SHADE
     file.read(reinterpret_cast<char *>(vertNorm.data()), vertexVec3Byte);
     file.read(reinterpret_cast<char *>(texCoord.data()), vertexVec2Byte);
     file.read(reinterpret_cast<char *>(indices.data()), sizeof(uint32_t) * indexCount);
-    
-    //for (auto i{ 0 }; i < vertCount; ++i)
-    //{
-    //  file >> vertPos[i].x;
-    //  file >> vertPos[i].y;
-    //  file >> vertPos[i].z;
-    //}
-    //
-    //for (auto i{ 0 }; i < vertCount; ++i)
-    //{
-    //  file >> vertTan[i].x;
-    //  file >> vertTan[i].y;
-    //  file >> vertTan[i].z;
-    //}
-
-    //for (auto i{ 0 }; i < vertCount; ++i)
-    //{
-    //  file >> vertNorm[i].x;
-    //  file >> vertNorm[i].y;
-    //  file >> vertNorm[i].z;
-    //}
-
-    //for (auto i{ 0 }; i < vertCount; ++i)
-    //{
-    //  file >> texCoord[i].x;
-    //  file >> texCoord[i].y;
-    //}
-
-    //for (auto i{ 0 }; i < indexCount; ++i)
-    //{
-    //  file >> indices[i];
-    //}
 
     mesh.compiled = true;
     mesh.changed  = false;
 
     mesh.header.indexCount  = indexCount;
     mesh.header.vertexCount = vertCount;
-    mesh.header.meshName    = name;
+    mesh.header.name = name;
 
     mesh.vertexPosition = std::move(vertPos);
     mesh.vertexTangent  = std::move(vertTan);
@@ -217,15 +67,12 @@ namespace SHADE
     file.close();
 	}
 
-	void SHMeshLoader::LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept
-  {
-    if (path.extension().string() == GLTF_EXTENSION)
-    {
-      LoadExternal(meshes, path);
-      return;
-    }
+	SHAssetData* SHMeshLoader::Load(AssetPath path)
+	{
+    auto result = new SHMeshAsset();
 
-    meshes.emplace_back();
-    LoadSHMesh(meshes.back(), path);
+    LoadSHMesh(path, *result);
+
+    return result;
 	}
 }
diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h
index a27d63ea..34c4e5d2 100644
--- a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h
+++ b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h
@@ -10,27 +10,15 @@
  * of DigiPen Institute of Technology is prohibited.
  *****************************************************************************/
 #pragma once
-#include <assimp/Importer.hpp>
-#include <assimp/scene.h>
 #include "../SHAssetMacros.h"
 #include "../Asset Types/SHMeshAsset.h"
-#include <vector>
+#include "SHAssetLoader.h"
 
 namespace SHADE
 {
-	class SHMeshLoader
+	struct SHMeshLoader : public SHAssetLoader
 	{
-	private:
-		static Assimp::Importer aiImporter;
-
-		static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes) noexcept;
-
-		static SHMeshAsset ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept;
-
-		static void LoadExternal(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept;
-
-	public:
-		static void LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept;
-		static void LoadSHMesh(SHMeshAsset& meshes, AssetPath path) noexcept;
+		void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept;
+		SHAssetData* Load(AssetPath path) override;
 	};
 }
\ No newline at end of file
diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp
index 5147562a..8b986524 100644
--- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp
+++ b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp
@@ -133,6 +133,15 @@ namespace SHADE
 		file.close();
 	}
 
+	SHAssetData* SHTextureLoader::Load(AssetPath path)
+	{
+		auto result = new SHTextureAsset();
+
+		LoadImageAsset(path, *result);
+
+		return result;
+	}
+
 	void SHTextureLoader::LoadImageAsset(AssetPath path, SHTextureAsset& asset)
 	{
 		if (path.extension().string() == DDS_EXTENSION)
diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h
index eb61ea91..8bdf91b1 100644
--- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h
+++ b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h
@@ -15,19 +15,20 @@
 #include "../SHAssetMacros.h"
 #include "../Asset Types/SHTextureAsset.h"
 #include "tinyddsloader.h"
+#include "SHAssetLoader.h"
 
 namespace SHADE
 {
-	class SHTextureLoader
+	class SHTextureLoader : public SHAssetLoader
 	{
 	private:
-		static std::string TinyDDSResultToString(tinyddsloader::Result value);
-		static vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
-
-
-		static void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
+		std::string TinyDDSResultToString(tinyddsloader::Result value);
+		vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
+		
+		void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
 	public:
-		static void LoadImageAsset(AssetPath paths, SHTextureAsset& image);
-		static void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
+		void LoadImageAsset(AssetPath paths, SHTextureAsset& image);
+		void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
+		SHAssetData* Load(AssetPath path) override;
 	};
 }
diff --git a/SHADE_Engine/src/Assets/SHAsset.h b/SHADE_Engine/src/Assets/SHAsset.h
index 8d7b55d1..86e8a722 100644
--- a/SHADE_Engine/src/Assets/SHAsset.h
+++ b/SHADE_Engine/src/Assets/SHAsset.h
@@ -12,11 +12,12 @@
 #pragma once
 
 #include "Filesystem/SHFileSystem.h"
-#include "SHAssetMacros.h"
+#include "Assets/SHAssetMacros.h"
+#include "SH_API.h"
 
 namespace SHADE
 {
-	struct SHAsset
+	struct SH_API SHAsset
 	{
 		AssetName name;
 		AssetID id;
diff --git a/SHADE_Engine/src/Assets/SHAssetMacros.h b/SHADE_Engine/src/Assets/SHAssetMacros.h
index 61c5879d..0fdfa04e 100644
--- a/SHADE_Engine/src/Assets/SHAssetMacros.h
+++ b/SHADE_Engine/src/Assets/SHAssetMacros.h
@@ -32,12 +32,12 @@ typedef std::filesystem::path AssetPath;
 typedef unsigned char*				AssetData;
 typedef std::string						AssetMetaVersion;
 typedef std::string						AssetExtension;
-typedef unsigned char					AssetTypeMeta;
+typedef size_t					AssetTypeMeta;
 
 typedef FMOD::Sound*					SHSound;
 
 // Asset Meta Version
-#define ASSET_META_VER "1.0"
+constexpr std::string_view ASSET_META_VER { "1.0" };
 
 // Asset type enum
 enum class AssetType : AssetTypeMeta
@@ -53,34 +53,35 @@ enum class AssetType : AssetTypeMeta
 	SCENE,
 	PREFAB,
 	AUDIO_WAV,
-	DDS
+	DDS,
+	MAX_COUNT
 };
 
 //Directory
 #ifdef _PUBLISH
-#define ASSET_ROOT "Assets"
+constexpr std::string_view ASSET_ROOT {"Assets"};
 #else
-#define ASSET_ROOT "../../Assets"
+constexpr std::string_view ASSET_ROOT {"../../Assets"};
 #endif
 
 
 // ASSET EXTENSIONS
-#define META_EXTENSION ".shmeta"
-#define IMAGE_EXTENSION ".png"
-#define AUDIO_EXTENSION ".ogg"
-#define AUDIO_WAV_EXTENSION ".wav"
-#define SHADER_EXTENSION ".glsl"
-#define SCRIPT_EXTENSION ".cs"
-#define SCENE_EXTENSION ".SHADE"
-#define PREFAB_EXTENSION ".SHPrefab"
-#define MATERIAL_EXTENSION ".SHMat"
-#define TEXTURE_EXTENSION ".shtex"
-#define DDS_EXTENSION ".dds"
-#define FBX_EXTENSION ".fbx"
-#define GLTF_EXTENSION ".gltf"
-#define MESH_EXTENSION ".shmesh"
+constexpr std::string_view META_EXTENSION {".shmeta"};
+constexpr std::string_view IMAGE_EXTENSION {".png"};
+constexpr std::string_view AUDIO_EXTENSION {".ogg"};
+constexpr std::string_view AUDIO_WAV_EXTENSION {".wav"};
+constexpr std::string_view SHADER_EXTENSION {".glsl"};
+constexpr std::string_view SCRIPT_EXTENSION {".cs"};
+constexpr std::string_view SCENE_EXTENSION {".SHADE"};
+constexpr std::string_view PREFAB_EXTENSION {".SHPrefab"};
+constexpr std::string_view MATERIAL_EXTENSION {".SHMat"};
+constexpr std::string_view TEXTURE_EXTENSION {".shtex"};
+constexpr std::string_view DDS_EXTENSION {".dds"};
+constexpr std::string_view FBX_EXTENSION {".fbx"};
+constexpr std::string_view GLTF_EXTENSION {".gltf"};
+constexpr std::string_view MESH_EXTENSION {".shmesh"};
 
-std::string const EXTENSIONS[] = {
+constexpr std::string_view EXTENSIONS[] = {
 	AUDIO_EXTENSION,
 	SHADER_EXTENSION,
 	MATERIAL_EXTENSION,
@@ -96,10 +97,12 @@ std::string const EXTENSIONS[] = {
 	GLTF_EXTENSION
 };
 
+constexpr size_t TYPE_COUNT {static_cast<size_t>(AssetType::MAX_COUNT) };
+
 // Error flags
-#define FILE_NOT_FOUND_ERR "FILE NOT FOUND"
-#define META_NOT_FOUND_ERR "META NOT FOUND"
-#define ASSET_NOT_FOUND_ERR "ASSET NOT FOUND"
-#define EXT_DOES_NOT_EXIST "TYPE DOES NOT HAVE EXTENSION DEFINED"
+constexpr std::string_view FILE_NOT_FOUND_ERR {"FILE NOT FOUND"};
+constexpr std::string_view META_NOT_FOUND_ERR {"META NOT FOUND"};
+constexpr std::string_view ASSET_NOT_FOUND_ERR {"ASSET NOT FOUND"};
+constexpr std::string_view EXT_DOES_NOT_EXIST {"TYPE DOES NOT HAVE EXTENSION DEFINED"};
 
 #endif // !SH_ASSET_MACROS_H
diff --git a/SHADE_Engine/src/Assets/SHAssetManager.cpp b/SHADE_Engine/src/Assets/SHAssetManager.cpp
index 956d52e8..3032ba51 100644
--- a/SHADE_Engine/src/Assets/SHAssetManager.cpp
+++ b/SHADE_Engine/src/Assets/SHAssetManager.cpp
@@ -14,6 +14,7 @@
 #include "SHAssetMetaHandler.h"
 #include "Filesystem/SHFileSystem.h"
 
+#include "Libraries/SHAssimpLibrary.h"
 #include "Libraries/SHMeshLoader.h"
 #include "Libraries/SHTextureLoader.h"
 
@@ -25,11 +26,10 @@ namespace SHADE
 	FMOD::System* SHAssetManager::audioSystem;
 	std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList;
 
-	std::vector<SHAsset> SHAssetManager::assetCollection;
-	std::unordered_map<AssetID, SHAsset> SHAssetManager::assetRegistry;
+	std::vector<SHAssetLoader*> SHAssetManager::loaders(TYPE_COUNT);
 
-	std::unordered_map<AssetID, SHMeshAsset> SHAssetManager::meshCollection;
-	std::unordered_map<AssetID, SHTextureAsset> SHAssetManager::textureCollection;
+	std::vector<SHAsset> SHAssetManager::assetCollection;
+	std::unordered_map<AssetID, SHAssetData * const> SHAssetManager::assetData;
 
 	/****************************************************************************
 	 * \brief   Static function to generate asset ID.
@@ -56,18 +56,15 @@ namespace SHADE
 	****************************************************************************/
 	void SHAssetManager::Unload() noexcept
 	{
-		for (auto const& asset : assetCollection)
-		{
-			SHAssetMetaHandler::WriteMetaData(asset);
-		}
+
 	}
 
-    void SHAssetManager::Unload(AssetID assetId) noexcept
-    {
-		// TODO
-    }
+	void SHAssetManager::Unload(AssetID assetId) noexcept
+	{
+	// TODO
+	}
 
-    AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
+		AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
 	{
 		if (!IsRecognised(path.extension().string().c_str()))
 		{
@@ -85,7 +82,37 @@ namespace SHADE
 		//	return std::filesystem::path();
 		//}
 
-		return std::filesystem::path(ASSET_ROOT + folder + path.filename().string());
+		return std::filesystem::path(std::string(ASSET_ROOT) + folder + path.filename().string());
+	}
+
+	AssetPath SHAssetManager::GenerateNewPath(AssetName name, AssetType type)
+	{
+		std::string folder;
+
+		switch(type)
+		{
+		case AssetType::SCENE:
+			folder = "scenes/";
+			break;
+
+		case AssetType::PREFAB:
+			folder = "prefabs/";
+			break;
+
+		case AssetType::MATERIAL:
+			folder = "materials/";
+			break;
+
+		default:
+			folder = "/";
+		}
+
+		return std::filesystem::path{
+			std::string(ASSET_ROOT) + 
+			folder + 
+			name + 
+			std::string(EXTENSIONS[static_cast<size_t>(type)])
+		};
 	}
 
 	/****************************************************************************
@@ -121,7 +148,7 @@ namespace SHADE
 		//	folder = "";
 		//	break;
 		//}
-		AssetPath path{ ASSET_ROOT + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
+		AssetPath path{ std::string{ASSET_ROOT} + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
 
 		SHAssetMetaHandler::WriteMetaData(meta);
 
@@ -130,6 +157,19 @@ namespace SHADE
 		return id;
 	}
 
+	AssetID SHAssetManager::CreateAsset(AssetName name, AssetType type) noexcept
+	{
+			AssetID id = GenerateAssetID(type);
+
+			assetCollection.emplace_back(
+				name,
+				id,
+				type,
+				GenerateNewPath(name, type),
+				0
+			); 
+			return id;
+		}
 	/****************************************************************************
 	 * \brief Import new asset from outside editor window.
 	 *
@@ -138,7 +178,10 @@ namespace SHADE
 	****************************************************************************/
 	AssetID SHAssetManager::ImportNewAsset(char const* p) noexcept
 	{
-		 std::filesystem::path const path{ p };
+		std::filesystem::path const path{ p };
+
+		auto const type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string());
+		auto const id = GenerateAssetID(type);
 
 		std::filesystem::path const newPath{ GenerateLocalPath(path) };
 		if (newPath.empty())
@@ -149,11 +192,7 @@ namespace SHADE
 
 		std::filesystem::copy(path, newPath);
 
-		AssetID id{ RetrieveAsset(newPath.string().c_str()) };
-		if (id != 0)
-		{
-			LoadData(id);
-		}
+		assetCollection.push_back(CreateAssetFromPath(newPath));
 
 		return id;
 	}
@@ -164,158 +203,14 @@ namespace SHADE
 	****************************************************************************/
 	void SHAssetManager::RefreshAllAssets() noexcept
 	{
-		std::vector<AssetPath> metaFiles;
-		std::vector<AssetPath> AssetFiles;
 
-		//SHFileSystem::LoadAllFiles(metaFiles, AssetFiles);
-		//std::vector<AssetPath> AssetFilesVerified;
-		std::vector<AssetPath> AssetFilesNew;
-
-		for (auto const& asset : AssetFiles)
-		{
-			bool found = false;
-		  for (auto it {metaFiles.begin()}; it != metaFiles.end(); ++it)
-		  {
-				std::string fileExtCheck{ asset.filename().string() };
-				fileExtCheck += META_EXTENSION;
-				if (it->filename().string() == fileExtCheck)
-				{
-					metaFiles.erase(it);
-					found = true;
-					break;
-				}
-		  }
-
-			if (!found && IsRecognised(asset.extension().string().c_str()))
-			{
-				AssetFilesNew.push_back(asset);
-			}
-		}
-
-		std::vector<SHAsset> newLoad;
-		newLoad.reserve(AssetFilesNew.size());
-
-		//TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa)
-		for (auto const& file : AssetFilesNew)
-		{
-			newLoad.push_back(RegisterAssetNew(file));
-		}
-
-    //UpdateAllSpriteSets();
-
-	}
-
-	void SHAssetManager::LoadDataTemp(std::string p) noexcept
-	{
-		AssetPath path{ p };
-
-		if (path.extension().string() == FBX_EXTENSION
-			|| path.extension().string() == GLTF_EXTENSION
-			|| path.extension().string() == MESH_EXTENSION)
-		{
-			LoadGLTF(
-				{
-					.name {path.filename().string()},
-					.id {0},
-					.type {AssetType::MESH},
-					.path {path},
-					.location {0}
-				}
-			);
-		}
-		else if (path.extension().string() == DDS_EXTENSION
-			|| path.extension().string() == TEXTURE_EXTENSION)
-		{
-			LoadDDS(
-				{
-					.name {path.filename().string()},
-					.id {0},
-					.type {AssetType::DDS},
-					.path {path},
-					.location {0}
-				}
-			);
-		}
-	}
-
-	std::vector<SHMeshAsset> SHAssetManager::GetAllMeshes() noexcept
-	{
-		std::vector<SHMeshAsset> result;
-		for (auto const& mesh : meshCollection)
-		{
-			result.push_back(mesh.second);
-		}
-
-		return result;
-	}
-
-	std::vector<SHTextureAsset> SHAssetManager::GetAllTextures() noexcept
-	{
-		std::vector<SHTextureAsset> result;
-		for (auto const& dds : textureCollection)
-		{
-			result.push_back(dds.second);
-		}
-
-		return result;
-	}
-
-	SHMeshAsset const* SHAssetManager::GetMesh(AssetID id) noexcept
-	{
-		if (meshCollection.find(id) == meshCollection.end())
-		{
-			return nullptr;
-		}
-
-		return &meshCollection[id];
-	}
-
-	SHTextureAsset const* SHAssetManager::GetTexture(AssetID id) noexcept
-	{
-		if (textureCollection.find(id) == textureCollection.end())
-		{
-			return nullptr;
-		}
-
-		return &textureCollection[id];
-	}
-
-	/****************************************************************************
-	 * \param   Path for meta data file
-	 * \param   Path for asset file
-
-	 * \brief   Links meta data to asset in registries. Meta data should
-	 *					already exist
-	****************************************************************************/
-	void SHAssetManager::RegisterAsset(AssetPath const& metaPath, AssetPath const& path) noexcept
-	{
-		SHAsset const meta = SHAssetMetaHandler::RetrieveMetaData(metaPath);
-
-		assetCollection.push_back(meta);
-	}
-
-	/****************************************************************************
-	 * \param   Path for asset file
-
-	 * \brief   Creates new meta data for new asset.
-	****************************************************************************/
-	SHAsset SHAssetManager::RegisterAssetNew(AssetPath const& asset) noexcept
-	{
-		SHAsset meta;
-		meta.type = SHAssetMetaHandler::GetTypeFromExtension(asset.extension().string());
-		meta.id = GenerateAssetID(meta.type);
-
-		assetCollection.push_back(meta);
-
-		SHAssetMetaHandler::WriteMetaData(meta);
-		return assetCollection.back();
 	}
 
 	bool SHAssetManager::IsRecognised(char const* ext) noexcept
 	{
 		for (auto const& e : EXTENSIONS)
 		{
-			if (strcmp(ext, e.c_str()) == 0)
+			if (strcmp(ext, e.data()) == 0)
 			{
 				return true;
 			}
@@ -324,54 +219,31 @@ namespace SHADE
 		return false;
 	}
 
-	void SHAssetManager::LoadGLTF(SHAsset asset) noexcept
+	SHAsset SHAssetManager::CreateAssetFromPath(AssetPath path) noexcept
 	{
-		std::vector<SHMeshAsset> meshes;
+		SHAsset result;
 
-		SHMeshLoader::LoadMesh(meshes, asset.path);
+		result.name = path.stem().string();
+		result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string());
+		result.id = GenerateAssetID(result.type);
+		result.path = path;
 
-		for (auto const& mesh : meshes)
-		{
-			auto id{ GenerateAssetID(AssetType::MESH) };
-			meshCollection.emplace(id, mesh);
-
-			AssetPath path;
-			if (!mesh.compiled)
-			{
-				path = SHMeshCompiler::CompileMeshBinary(mesh, asset.path);
-			}
-			
-			assetCollection.emplace_back(
-				mesh.header.meshName,
-				id,
-				AssetType::MESH,
-				path,
-				0
-			);
-		}
+		return result;
 	}
 
-	void SHAssetManager::LoadDDS(SHAsset asset) noexcept
+	void SHAssetManager::InitLoaders() noexcept
 	{
-		SHTextureAsset image;
-
-		SHTextureLoader::LoadImageAsset(asset.path, image);
-
-		if (!image.compiled)
-		{
-			auto id{ GenerateAssetID(AssetType::TEXTURE) };
-			textureCollection.emplace(id, image);
-
-			auto path{ SHTextureCompiler::CompileTextureBinary(image, asset.path) };
-
-			assetCollection.emplace_back(
-				image.name,
-				id,
-				AssetType::TEXTURE,
-				path,
-				0
-			);
-		}
+		loaders[static_cast<size_t>(AssetType::AUDIO)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::SHADER)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::MATERIAL)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::IMAGE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader());
+		loaders[static_cast<size_t>(AssetType::TEXTURE)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::MESH)] = dynamic_cast<SHAssetLoader*>(new SHMeshLoader());
+		loaders[static_cast<size_t>(AssetType::SCRIPT)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::SCENE)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::PREFAB)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::AUDIO_WAV)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::DDS)] = nullptr;
 	}
 
 	/****************************************************************************
@@ -379,8 +251,9 @@ namespace SHADE
 	****************************************************************************/
 	void SHAssetManager::Load() noexcept
 	{
-		RetrieveAssets();
-		LoadAllData();
+		InitLoaders();
+		BuildAssetCollection();
+		//LoadAllData();
 	}
 
 	/****************************************************************************
@@ -388,143 +261,40 @@ namespace SHADE
 	****************************************************************************/
 	void SHAssetManager::LoadAllData() noexcept
 	{
-		//TODO Remove when on demand loading is done
 		for (auto const& asset : assetCollection)
 		{
-			switch (asset.type)
-			{
-			case AssetType::MESH:
-				meshCollection.emplace(asset.id, SHMeshAsset());
-				SHMeshLoader::LoadSHMesh(meshCollection[asset.id], asset.path);
-				break;
-
-			case AssetType::TEXTURE:
-				textureCollection.emplace(asset.id, SHTextureAsset());
-				SHTextureLoader::LoadSHTexture(asset.path, textureCollection[asset.id]);
-				break;
-
-			default:
-				void;
-			}
+			SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
+			assetData.emplace(asset.id, data);
 		}
 	}
 
-	void SHAssetManager::LoadData(AssetID id) noexcept
+	SHAssetData* SHAssetManager::LoadData(SHAsset const& asset) noexcept
 	{
-		(void)id;
-	}
+		SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
 
-	/****************************************************************************
-	 * \brief   Retrieve all asset files and meta files from filesystem
-	****************************************************************************/
-	void SHAssetManager::RetrieveAssets() noexcept
-	{
-		std::vector<AssetPath> metaFiles;
-		std::vector<AssetPath> AssetFiles;
-
-		for (auto const dir : std::filesystem::recursive_directory_iterator(ASSET_ROOT))
+		if (data == nullptr)
 		{
-			if (dir.path().extension().string() == META_EXTENSION)
-			{
-				auto meta{ SHAssetMetaHandler::RetrieveMetaData(dir.path()) };
-
-				assetCollection.push_back(meta);
-				assetRegistry.emplace(meta.id, meta);
-			}
-		}
-
-		//TODO: Write new function for file manager to loop through all files
-		//SHFileSystem::StartupFillDirectories(ASSET_ROOT);
-		//FolderPointer rootFolder = SHFileSystem::GetRoot();
-
-		//for (auto const& meta : metaFiles)
-		//{
-		//	for (std::vector<AssetPath>::const_iterator it{ AssetFiles.cbegin() };
-		//		it != AssetFiles.cend();
-		//		++it)
-		//	{
-		//		// Asset exists for meta file
-		//		std::string fileExtCheck{ it->filename().string() };
-		//		fileExtCheck += META_EXTENSION;
-		//		if (meta.filename().string() == fileExtCheck)
-		//		{
-		//			RegisterAsset(meta, *it);
-		//			AssetFiles.erase(it);
-		//			break;
-		//		}
-		//	}
-		//}
-
-		//TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa)
-		//for (auto const& file : AssetFiles)
-		//{
-		//	if (IsRecognised(file.extension().string().c_str()))
-		//	{
-		//		SHAssetMetaHandler::WriteMetaData(RegisterAssetNew(file));
-		//	}
-		//	else
-		//	{
-		//		std::cout << "Unsupported File Format: " << file.filename() << "\n";
-		//	}
-		//}
-	}
-
-	AssetID SHAssetManager::RetrieveAsset(char const* path) noexcept
-	{
-		std::filesystem::path p{ path };
-		if (IsRecognised(p.extension().string().c_str()))
-		{
-			SHAsset const& meta{ RegisterAssetNew(p) };
-			SHAssetMetaHandler::WriteMetaData(meta);
-			return meta.id;
+			SHLOG_ERROR("Unable to load asset into memory: {}\n", asset.path.string());
 		}
 		else
 		{
-			std::cout << "Unsupported File Format: " << p.filename() << "\n";
+			assetData.emplace(asset.id, data);
 		}
 
-		// Assert that file imported is not recognised
-		return 0;
+		return data;
 	}
 
-	/****************************************************************************
-	 * \param   Full path of file
-
-	 * \brief   Extracts file name from path. Formats file name into readable
-	 *					with spaces and capitalises first letter of every word
-	****************************************************************************/
-	AssetName SHAssetManager::GetNameFromPath(AssetPath filepath) noexcept
+	void SHAssetManager::BuildAssetCollection() noexcept
 	{
-		std::string name{ filepath.filename().string() };
-		name = name.substr(0, name.find_last_of('.'));
-
-		//if (name[0] <= 122 && name[0] >= 97)
-		//{
-		//	name[0] -= 32;
-		//}
-
-		//for (size_t i{ 1 }; i < name.length(); ++i)
-		//{
-		//	// Replace all underscores with spaces
-		//	if (name[i] == '_')
-		//	{
-		//		name[i] = ' ';
-		//		continue;
-		//	}
-
-		//	if (name[i + 1] <= 'Z' && name[i + 1] >= 'A'
-		//		&& name[i] <= 'z' && name[i] >= 'a')
-		//	{
-		//		name.insert(i + 1, 1, ' ');
-		//		continue;
-		//	}
-
-		//	if (name[i - 1] == ' ' && name[i] <= 'z' && name[i] >= 'a')
-		//	{
-		//		name[i] -= 32;
-		//	}
-		//}
-
-		return name;
+		for (auto const& dir : std::filesystem::recursive_directory_iterator{ASSET_ROOT})
+		{
+			if (dir.is_regular_file())
+			{
+				if (dir.path().extension().string() == META_EXTENSION.data())
+				{
+					assetCollection.push_back(SHAssetMetaHandler::RetrieveMetaData(dir.path()));
+				}
+			}
+		}
 	}
 }
diff --git a/SHADE_Engine/src/Assets/SHAssetManager.h b/SHADE_Engine/src/Assets/SHAssetManager.h
index 2469165a..9ee7ab92 100644
--- a/SHADE_Engine/src/Assets/SHAssetManager.h
+++ b/SHADE_Engine/src/Assets/SHAssetManager.h
@@ -11,9 +11,10 @@
 #pragma once
 #include "tinyddsloader.h"
 #include "SHAsset.h"
+#include "Asset Types/SHAssetData.h"
+#include "Libraries/SHAssetLoader.h"
+#include <memory>
 
-#include "Asset Types/SHMeshAsset.h"	
-#include "Asset Types/SHTextureAsset.h"	
 #include "SH_API.h"
 
 namespace SHADE
@@ -28,6 +29,8 @@ namespace SHADE
 
 		static AssetPath GenerateLocalPath(AssetPath path) noexcept;
 
+		static AssetPath GenerateNewPath(AssetName name, AssetType type);
+
 		/****************************************************************************
 		 * \brief   Deallocate all memory used by resource data
 		****************************************************************************/
@@ -55,6 +58,7 @@ namespace SHADE
 		 * \return resource id generated for new asset
 		****************************************************************************/
 		static AssetID CreateNewAsset(AssetType, AssetName) noexcept;
+		static AssetID CreateAsset(AssetName name, AssetType type) noexcept;
 
 		/****************************************************************************
 		 * \brief Import new resource from outside editor window.
@@ -71,66 +75,33 @@ namespace SHADE
 		static void RefreshAllAssets() noexcept;
 		// -------------------------------------------------------------------------/
 
-		//TODO: TEMPORARY FOR TESTING GLTF & DDS
-		static void LoadDataTemp(std::string path) noexcept;
-		static std::vector<SHMeshAsset> GetAllMeshes() noexcept;
-		static std::vector<SHTextureAsset> GetAllTextures() noexcept;
-
-		static SHMeshAsset const* GetMesh(AssetID id) noexcept;
-		static SHTextureAsset const* GetTexture(AssetID id) noexcept;
+		template<typename T>
+		static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> GetData(AssetID id) noexcept;
 	private:
 		/****************************************************************************
 		 * \brief   Load resource data into memory
 		****************************************************************************/
 		static void LoadAllData() noexcept;
 
-		static void LoadData(AssetID id) noexcept;
+		static SHAssetData* LoadData(SHAsset const& asset) noexcept;
 
-		/****************************************************************************
-		 * \brief   Retrieve all resource files and meta files from filesystem
-		****************************************************************************/
-		static void RetrieveAssets() noexcept;
-
-		static AssetID RetrieveAsset(char const* path) noexcept;
-
-		/****************************************************************************
-		 * \param   Full path of file
-		
-		 * \brief   Extracts file name from path. Formats file name into readable
-		 *					with spaces and capitalises first letter of every word
-		****************************************************************************/
-		static AssetName GetNameFromPath(AssetPath) noexcept;
-
-		/****************************************************************************
-		 * \param   Path for meta data file
-		 * \param   Path for resource file
-		
-		 * \brief   Links meta data to resource in registries. Meta data should 
-		 *					already exist
-		****************************************************************************/
-		static void RegisterAsset(AssetPath const&, AssetPath const&) noexcept;
-
-		/****************************************************************************
-		 * \param   Path for resource file
-		
-		 * \brief   Creates new meta data for new resource.
-		****************************************************************************/
-		static SHAsset RegisterAssetNew(AssetPath const&) noexcept;
+		inline static void BuildAssetCollection() noexcept;
 
 		static bool IsRecognised(char const*) noexcept;
+		
+		static SHAsset CreateAssetFromPath(AssetPath	path) noexcept;
 
-		// Specialised load calls
-		static void LoadGLTF(SHAsset asset) noexcept;
-		static void LoadDDS(SHAsset asset) noexcept;
+		static void InitLoaders() noexcept;
 
 		static FMOD::System* audioSystem;
 		static std::unordered_map<AssetID,SHSound>* audioSoundList;
 
+		static std::vector<SHAssetLoader*> loaders;
+
 		// For all resources
 		static std::vector<SHAsset> assetCollection;
-		static std::unordered_map<AssetID, SHAsset> assetRegistry;
-
-		static std::unordered_map<AssetID, SHMeshAsset> meshCollection;
-		static std::unordered_map<AssetID, SHTextureAsset> textureCollection;
+		static std::unordered_map<AssetID, SHAssetData * const> assetData;
 	};
 }
+
+#include "SHAssetManager.hpp"
diff --git a/SHADE_Engine/src/Assets/SHAssetManager.hpp b/SHADE_Engine/src/Assets/SHAssetManager.hpp
new file mode 100644
index 00000000..6c420778
--- /dev/null
+++ b/SHADE_Engine/src/Assets/SHAssetManager.hpp
@@ -0,0 +1,26 @@
+
+#include "SHAssetManager.h"
+
+namespace SHADE
+{
+	template<typename T>
+	std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> SHAssetManager::GetData(AssetID id) noexcept
+	{
+		if (!assetData.contains(id))
+		{
+			for (auto const& asset : assetCollection)
+			{
+				if (asset.id == id)
+				{
+					assetData.emplace(id, LoadData(asset));
+					return dynamic_cast<T const* const>(assetData[id]);
+				}
+			}
+
+			SHLOG_ERROR("Asset ID provided does not exist: {}", id);
+			return nullptr;
+		}
+
+		return dynamic_cast<T const* const>(assetData[id]);
+	}
+}
diff --git a/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp b/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp
index 442c3d96..1bfec00d 100644
--- a/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp
+++ b/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp
@@ -37,7 +37,7 @@ namespace SHADE
 	{
 		for (int i{0}; i < EXTENSIONS->size(); ++i)
 		{
-			if (ext == EXTENSIONS[i])
+			if (strcmp(ext.c_str(), EXTENSIONS[i].data()) == 0)
 			{
 				return static_cast<AssetType>(i);
 			}
@@ -53,7 +53,7 @@ namespace SHADE
 	****************************************************************************/
 	AssetExtension SHAssetMetaHandler::GetExtensionFromType(AssetType type) noexcept
 	{
-		return EXTENSIONS[static_cast<size_t>(type)];
+		return AssetExtension(EXTENSIONS[static_cast<size_t>(type)]);
 	}
 
 	/****************************************************************************
@@ -124,16 +124,6 @@ namespace SHADE
 		metaFile << "ID: " << meta.id << "\n";
 		metaFile << "Type: " << static_cast<AssetTypeMeta>(meta.type) << std::endl;
 
-		////TODO Add in information that is specific to types like mesh
-		//switch(meta.type)
-		//{
-		//case AssetType::MESH:
-		//	break;
-
-		//default:
-		//	break;
-		//}
-
 		metaFile.close();
 	}
 
diff --git a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp
new file mode 100644
index 00000000..caad9b10
--- /dev/null
+++ b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp
@@ -0,0 +1,84 @@
+#include "SHpch.h"
+#include "SHAssetBrowser.h"
+
+#include "Editor/IconsMaterialDesign.h"
+#include "Editor/SHImGuiHelpers.hpp"
+#include <imgui.h>
+
+#include "Assets/SHAssetManager.h"
+#include "Editor/DragDrop/SHDragDrop.hpp"
+
+namespace SHADE
+{
+  SHAssetBrowser::SHAssetBrowser()
+    :SHEditorWindow("\xee\x8b\x87 Asset Browser", ImGuiWindowFlags_MenuBar)
+  {
+  }
+
+  void SHAssetBrowser::Init()
+  {
+    SHEditorWindow::Init();
+  }
+
+  void SHAssetBrowser::Update()
+  {
+    SHEditorWindow::Update();
+    if(Begin())
+    {
+      DrawMenuBar();
+      auto const& assets = SHAssetManager::GetAllAssets();
+      if(ImGui::BeginTable("AssetBrowserTable", 3))
+      {
+        ImGui::TableNextColumn();
+        ImGui::TableHeader("Asset ID");
+        ImGui::TableNextColumn();
+        ImGui::TableHeader("Name");
+        ImGui::TableNextColumn();
+        ImGui::TableHeader("Type");
+        for(SHAsset const& asset : assets)
+        {
+          DrawAsset(asset);
+        }
+        ImGui::EndTable();
+      }
+    }
+    ImGui::End();
+  }
+
+  void SHAssetBrowser::DrawMenuBar()
+  {
+    if(ImGui::BeginMenuBar())
+    {
+
+      ImGui::EndMenuBar();
+    }
+  }
+
+  void SHAssetBrowser::DrawAsset(SHAsset const& asset)
+  {
+    ImGui::PushID(asset.id);
+    ImGui::BeginGroup();
+
+    ImGui::TableNextColumn();
+    ImGui::Selectable(std::format("{}", asset.id).data(), false, ImGuiSelectableFlags_SpanAllColumns);
+    if(SHDragDrop::BeginSource())
+    {
+      auto id = asset.id;
+      ImGui::Text("Moving Asset: %zu", id);
+      SHDragDrop::SetPayload<AssetID>(DRAG_RESOURCE, &id);
+      SHDragDrop::EndSource();
+    }
+
+    ImGui::TableNextColumn();
+    ImGui::Text("%s", asset.name.c_str());
+
+    ImGui::TableNextColumn();
+    ImGui::Text("%s", "Type");
+
+    ImGui::EndGroup();
+    ImGui::PopID();
+
+    
+
+  }
+}
diff --git a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.h b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.h
new file mode 100644
index 00000000..0e3053bc
--- /dev/null
+++ b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "Assets/SHAsset.h"
+#include "Editor/EditorWindow/SHEditorWindow.h"
+
+namespace SHADE
+{
+  class SHAssetBrowser final : public SHEditorWindow
+  {
+  public:
+    SHAssetBrowser();
+
+    void Init();
+    void Update();
+
+    void Refresh();
+  private:
+    void DrawMenuBar();
+    void DrawAsset(SHAsset const& asset);
+
+    float idColumnWidth, nameColumnWidth, typeColumnWidth;
+    
+  };
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp
index 27e46d98..f2f8d927 100644
--- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp
+++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp
@@ -93,8 +93,7 @@ namespace SHADE
   {
     if (ImGui::BeginMenuBar())
     {
-      
-      ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x - 35.0f);
+      ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.75f);
       if(ImGui::SmallButton(ICON_MD_DESELECT))
       {
         auto editor = SHSystemManager::GetSystem<SHEditor>();
diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp
index 08f5695b..7fa39d74 100644
--- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp
+++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp
@@ -39,6 +39,10 @@ namespace SHADE
       {
         SHComponentManager::RemoveComponent<T>(component->GetEID());
       }
+      if (ImGui::Selectable(std::format("{} Reset {}", ICON_MD_RESTART_ALT, componentName.data()).data()))
+      {
+        *component = T();
+      }
       ImGui::EndPopup();
     }
   }
@@ -48,7 +52,7 @@ namespace SHADE
     if (!component)
       return;
     const auto componentType = rttr::type::get(*component);
-    SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; });
+    SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
     ImGui::SameLine();
     if (ImGui::CollapsingHeader(componentType.get_name().data()))
     {
@@ -89,7 +93,7 @@ namespace SHADE
             auto metaMax = property.get_metadata(META::max);
             if (metaMin && metaMax)
             {
-              SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), metaMin.template get_value<int>(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); });
+              SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), metaMax.template get_value<int>(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); });
             }
             else
             {
@@ -115,7 +119,7 @@ namespace SHADE
             auto metaMax = property.get_metadata(META::max);
             if (metaMin.is_valid() && metaMax.is_valid())
             {
-              SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), metaMin.template get_value<uint16_t>(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, "%zu");
+              SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), metaMax.template get_value<uint16_t>(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, "%zu");
             }
             else
             {
@@ -128,7 +132,7 @@ namespace SHADE
             auto metaMax = property.get_metadata(META::max);
             if (metaMin.is_valid() && metaMax.is_valid())
             {
-              SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), metaMin.template get_value<uint32_t>(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, "%zu");
+              SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), metaMax.template get_value<uint32_t>(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, "%zu");
             }
             else
             {
@@ -141,7 +145,7 @@ namespace SHADE
             auto metaMax = property.get_metadata(META::max);
             if (metaMin.is_valid() && metaMax.is_valid())
             {
-              SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), metaMin.template get_value<uint64_t>(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, "%zu");
+              SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), metaMax.template get_value<uint64_t>(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, "%zu");
             }
             else
             {
@@ -152,13 +156,18 @@ namespace SHADE
           {
             auto metaMin = property.get_metadata(META::min);
             auto metaMax = property.get_metadata(META::max);
+            float min{}, max{};
+            if(metaMin.is_valid())
+              min = std::max(metaMin.template get_value<float>(), -FLT_MAX * 0.5f);
+            if(metaMax.is_valid())
+              max = std::min(metaMax.template get_value<float>(), FLT_MAX * 0.5f);
             if (metaMin.is_valid() && metaMax.is_valid())
             {
-              SHEditorWidgets::SliderFloat(property.get_name().data(), metaMin.template get_value<float>(), metaMin.template get_value<float>(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
+              SHEditorWidgets::SliderFloat(property.get_name().data(), min, max, [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
             }
             else
             {
-              SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
+              SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }, "Test");
             }
           }
           else if (type == rttr::type::get<double>())
@@ -167,7 +176,7 @@ namespace SHADE
             auto metaMax = property.get_metadata(META::max);
             if (metaMin.is_valid() && metaMax.is_valid())
             {
-              SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), metaMin.template get_value<double>(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); });
+              SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), metaMax.template get_value<double>(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); });
             }
             else
             {
diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp
index b59ce9cc..ada5a35a 100644
--- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp
+++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp
@@ -84,8 +84,8 @@ namespace SHADE
         }
         ImGui::Separator();
         // Render Scripts
-		    SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
-		    scriptEngine->RenderScriptsInInspector(eid);
+        SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
+        scriptEngine->RenderScriptsInInspector(eid);
         ImGui::Separator();
         if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data()))
         {
diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h
index f0267b06..5208c6d9 100644
--- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h
+++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h
@@ -3,4 +3,5 @@
 #include "HierarchyPanel/SHHierarchyPanel.h"  //Hierarchy Panel
 #include "Inspector/SHEditorInspector.h"      //Inspector
 #include "Profiling/SHEditorProfiler.h"       //Profiler
-#include "ViewportWindow/SHEditorViewport.h"  //Editor Viewport
\ No newline at end of file
+#include "ViewportWindow/SHEditorViewport.h"  //Editor Viewport
+#include "AssetBrowser/SHAssetBrowser.h"      //Asset Browser
\ No newline at end of file
diff --git a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp
index b06c37c7..f5170999 100644
--- a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp
+++ b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp
@@ -24,12 +24,13 @@ namespace SHADE
   void SHEditorViewport::Init()
   {
     SHEditorWindow::Init();
-
+    transformGizmo.Init();
   }
 
   void SHEditorViewport::Update()
   {
     SHEditorWindow::Update();
+    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f,0.0f));
     if(Begin())
     {
       ImGuizmo::SetDrawlist();
@@ -55,7 +56,7 @@ namespace SHADE
     ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y);
     transformGizmo.Draw();
     ImGui::End();
-
+    ImGui::PopStyleVar();
   }
 
   void SHEditorViewport::Exit()
diff --git a/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp
index a53b8c10..3c984051 100644
--- a/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp
+++ b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp
@@ -13,6 +13,12 @@
 #include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h"
 namespace SHADE
 {
+  void SHTransformGizmo::Init()
+  {
+    auto& style = ImGuizmo::GetStyle();
+    style.RotationLineThickness = 2.5f;
+  }
+
   void SHTransformGizmo::Draw()
   {
     bool justChangedTfm = false;
@@ -26,9 +32,12 @@ namespace SHADE
 
     SHMatrix view = SHMatrix::Transpose(editorCamera->GetViewMatrix());
     SHMatrix proj = SHMatrix::Transpose(editorCamera->GetProjMatrix());
+
+    //Invert projection y-axis
     proj(1, 1) *= -1;
+
     static SHMatrix gridMat = SHMatrix::Translate(0, -0.5f, 0.f) * SHMatrix::Identity;
-    //ImGuizmo::DrawGrid(&view._11, &proj._11, &gridMat._11, 100.f);
+
     if (selectedEntityTransformComponent == nullptr)
     {
       SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
@@ -55,31 +64,37 @@ namespace SHADE
       return;
 
     SHMatrix mat = selectedEntityTransformComponent->GetTRS();
-    isManipulating = ImGuizmo::Manipulate(&view._11, &proj._11, static_cast<ImGuizmo::OPERATION>(operation), ImGuizmo::MODE::WORLD, &mat._11);
-    if (!justChangedTfm)
+    useSnap = ImGui::IsKeyDown(ImGuiKey_LeftCtrl);
+    if(useSnap)
     {
-      if (ImGui::IsItemClicked())
-        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx)
-          {
-            if (!tfm)
-              return;
-            SHVec3 translate{}, rotate{}, scale{};
-            mtx.Decompose(translate, rotate, scale);
-            tfm->SetWorldPosition(translate);
-            tfm->SetWorldRotation(rotate);
-            tfm->SetWorldScale(scale);
-          })));
-      else if (ImGui::IsItemHovered(ImGuiMouseButton_Left) && ImGui::IsMouseDown(ImGuiMouseButton_Left) && isManipulating)
-        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx)
-          {
-            if (!tfm)
-              return;
-            SHVec3 translate{}, rotate{}, scale{};
-            mtx.Decompose(translate, rotate, scale);
-            tfm->SetWorldPosition(translate);
-            tfm->SetWorldRotation(rotate);
-            tfm->SetWorldScale(scale);
-          })), true);
+      switch (operation)
+      {
+      case Operation::TRANSLATE: snap = &translationSnap.x; break;
+      case Operation::ROTATE: snap = &rotationSnap; break;
+      case Operation::SCALE: snap = &scaleSnap; break;
+      default: snap = &translationSnap.x;
+      }
     }
+    ImGuizmo::Manipulate(&view._11, &proj._11, static_cast<ImGuizmo::OPERATION>(operation), ImGuizmo::MODE::WORLD, &mat._11, nullptr, useSnap ? snap : nullptr);
+    static bool startRecording = false;
+    if (!justChangedTfm && ImGuizmo::IsUsing())
+    {
+      
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = (selectedEntityTransformComponent)](SHMatrix const& mtx)
+          {
+            if (!tfm)
+              return;
+            SHVec3 translate{}, rotate{}, scale{};
+            mtx.Decompose(translate, rotate, scale);
+            tfm->SetWorldPosition(translate);
+            tfm->SetWorldRotation(rotate);
+            tfm->SetWorldScale(scale);
+          })), startRecording);
+      if(!startRecording)
+        startRecording = true;
+    }
+    isManipulating = ImGuizmo::IsUsing() || startRecording;
+    if(startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      startRecording = false;
   }
 }
diff --git a/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.h b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.h
index 2565575f..fd847335 100644
--- a/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.h
+++ b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.h
@@ -37,11 +37,17 @@ namespace SHADE
       UNIVERSAL = TRANSLATE | ROTATE | SCALEU
     };
 
+    void Init();
     void Draw();
     bool isManipulating = false;
+    bool useSnap = false;
     Mode mode = Mode::WORLD;
     Operation operation = Operation::TRANSLATE;
   private:
+    float scaleSnap = 0.25f;
+    float rotationSnap = 1.0f;
+    SHVec3 translationSnap = SHVec3(0.25f, 0.25f, 0.25f);
+    float* snap = nullptr;
     SHTransformComponent* selectedEntityTransformComponent{nullptr};
     SHCameraComponent* editorCamera{nullptr};
   };
diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp
index aff1eaad..06fadfee 100644
--- a/SHADE_Engine/src/Editor/SHEditor.cpp
+++ b/SHADE_Engine/src/Editor/SHEditor.cpp
@@ -92,6 +92,7 @@ namespace SHADE
     SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
     SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
     SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>();
+    SHEditorWindowManager::CreateEditorWindow<SHAssetBrowser>();
     SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
 
     io = &ImGui::GetIO();
@@ -134,7 +135,7 @@ namespace SHADE
       }
     }
     
-    PollPicking();
+    //PollPicking();
 
     if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z))
     {
diff --git a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp
index 5788dc15..b54a6799 100644
--- a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp
+++ b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp
@@ -40,7 +40,6 @@ namespace SHADE
     {
       ImGui::BeginGroup();
 
-      auto cursorPos = ImGui::GetCursorScreenPos();
       auto itemSpacing = ImGui::GetStyle().ItemSpacing;
       ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
       ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
@@ -158,7 +157,7 @@ namespace SHADE
     }
 
     template <typename T, std::size_t N>
-    static bool DragN(const std::string& fieldLabel, std::vector<std::string>const& componentLabels,
+    static bool DragN(const std::string& label, std::vector<std::string>const& componentLabels,
       std::vector<T*> values, float speed = 0.1f, const char* displayFormat = "", T valueMin = T(), T valueMax = T(),
       ImGuiSliderFlags flags = 0, bool* isHovered = nullptr)
     {
@@ -169,13 +168,13 @@ namespace SHADE
       const ImGuiContext& g = *GImGui;
       bool valueChanged = false;
       ImGui::BeginGroup();
-      ImGui::PushID(fieldLabel.c_str());
+      ImGui::PushID(label.c_str());
       PushMultiItemsWidthsAndLabels(componentLabels, 0.0f);
       ImGui::BeginColumns("DragVecCol", 2, ImGuiOldColumnFlags_NoBorder | ImGuiOldColumnFlags_NoResize);
       ImGui::SetColumnWidth(-1, 80.0f);
-      ImGui::Text(fieldLabel.c_str());
+      ImGui::Text(label.c_str());
       if (isHovered)
-          *isHovered = ImGui::IsItemHovered();
+        *isHovered = ImGui::IsItemHovered();
       ImGui::NextColumn();
       for (std::size_t i = 0; i < N; ++i)
       {
@@ -203,75 +202,91 @@ namespace SHADE
       return valueChanged;
     }
 
-    static bool DragVec2(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec2(void)> get,
-      std::function<void(SHVec2)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
+    static bool DragVec2(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec2(void)> get,
+      std::function<void(SHVec2)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
       ImGuiSliderFlags flags = 0)
     {
       SHVec2 values = get();
-      bool changed = false;
-      if (DragN<float, 2>(fieldLabel, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags))
-      {
-        changed = true;
-      }
-
+      bool const changed = DragN<float, 2>(label, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags);
+      static bool startRecording = false;
       if (changed)
       {
-        if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), true);
-        else if (ImGui::IsItemDeactivatedAfterEdit())
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
+      }
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+        startRecording = false;
+      if(!tooltip.empty())
+      {
+        if(ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
       }
-
       return changed;
     }
 
-    static bool DragVec3(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec3(void)> get,
-      std::function<void(SHVec3)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
+    static bool DragVec3(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec3(void)> get,
+      std::function<void(SHVec3)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
       ImGuiSliderFlags flags = 0)
     {
       SHVec3 values = get();
-      bool changed = false;
-      if (DragN<float, 3>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags))
-      {
-        changed = true;
-      }
+      bool const changed = DragN<float, 3>(label, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags);
 
+
+      static bool startRecording = false;
       if (changed)
       {
-        if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), true);
-        else if (ImGui::IsItemDeactivatedAfterEdit())
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
+        SHVec3 old = get();
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(old, values, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
+      }
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      if(!tooltip.empty())
+      {
+        if(ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
       }
-
       return changed;
     }
 
-    static bool DragVec4(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec4(void)> get,
-      std::function<void(SHVec4)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
+    static bool DragVec4(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec4(void)> get,
+      std::function<void(SHVec4)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
       ImGuiSliderFlags flags = 0)
     {
       SHVec4 values = get();
-      bool changed = false;
-      if (DragN<float, 4>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags))
-      {
-        changed = true;
-      }
-
+      bool const changed = DragN<float, 4>(label, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags);
+      static bool startRecording = false;
       if (changed)
       {
-        if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), true);
-        else if (ImGui::IsItemDeactivatedAfterEdit())
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
+      }
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      if(!tooltip.empty())
+      {
+        if(ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
       }
-
       return changed;
     }
 
@@ -279,173 +294,325 @@ namespace SHADE
     //||                     Widget Extensions                      ||
     //#==============================================================#
 
-    static bool CheckBox(std::string const& label, std::function<bool(void)> get, std::function<void(bool const&)> set)
+    static void TextLabel(std::string_view const& text, bool sameLine = true)
+    {
+      const ImVec2 textSize = ImGui::CalcTextSize(text.data(), NULL, true);
+      if(textSize.x > 0.0f)
+      {
+        ImGui::Text(text.data());
+        ImGui::SameLine();
+      }
+    }
+
+    static bool CheckBox(std::string_view const& label, std::function<bool(void)> get, std::function<void(bool const&)> set, std::string_view const& tooltip = {})
     {
       bool value = get();
-      if (ImGui::Checkbox(label.c_str(), &value))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      if (ImGui::Checkbox("##", &value))
       {
         SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<bool>>(get(), value, set)), false);
         return true;
       }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if(!tooltip.empty())
+      {
+        if(ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
       return false;
     }
 
     template<typename T>
-    static bool RadioButton(std::vector<std::string> const& listLabels, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set)
+    static bool RadioButton(std::vector<std::string> const& label, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set ,std::string_view const& tooltip = {})
     {
       T type = get();
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
       for (size_t i = 0; i < listTypes.size(); i++)
       {
-        if (ImGui::RadioButton(listLabels[i].c_str(), type == listTypes[i]))
+        if (ImGui::RadioButton(label[i].c_str(), type == listTypes[i]))
         {
           SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), listTypes[i], set)), false);
         }
         ImGui::SameLine();
       }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
       return true;
     }
 
     static bool InputText(const std::string& label, const std::function<std::string(void)> get,
-      const std::function<void(std::string)> set, ImGuiInputTextFlags flag = 0,
-      ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0)
+      const std::function<void(std::string)> set, std::string_view const& tooltip = {},
+      ImGuiInputTextFlags flag = 0, ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0)
     {
       std::string text = get();
-      if (ImGui::InputText(label.c_str(), &text, flag, callback, userData))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      if (ImGui::InputText("##", &text, flag, callback, userData))
       {
         if (ImGui::IsItemDeactivatedAfterEdit())
           SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<std::string>>(get(), text, set)), false);
 
         return true;
       }
-      return false;
-    }
-
-    template <typename T>
-    static bool DragScalar(const std::string& fieldLabel, ImGuiDataType data_type, std::function<T(void)> get, std::function<void(T const&)>   set,
-      float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
-    {
-      T value = get();
-      std::cout << value << " \n";
-      //bool hasChange = ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags);
-
-      if (ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags))
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
       {
-        if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
-        else if (ImGui::IsItemDeactivatedAfterEdit())
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
-
-        return true;
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
       }
       return false;
     }
 
-    static bool DragFloat(const std::string& fieldLabel, std::function<float(void)> get, std::function<void(float const&)> set,
+    template <typename T>
+    static bool DragScalar(const std::string& label, ImGuiDataType data_type, std::function<T(void)> get, std::function<void(T const&)> set,
+      float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, ImGuiSliderFlags flags = 0)
+    {
+      T value = get();
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      const bool hasChange = ImGui::DragScalar("##", data_type, &value, speed, &p_min, &p_max, displayFormat, flags);
+      static bool startRecording = false;
+      if (hasChange)
+      {
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
+      }
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
+      return hasChange;
+    }
+
+    static bool DragFloat(const std::string_view& label, std::function<float(void)> get, std::function<void(float const&)> set, std::string_view const& tooltip = {},
       float speed = 0.1f, float p_min = float(), float p_max = float(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
     {
       float value = get();
-      //bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags);
-      if (ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      const bool hasChange = ImGui::DragFloat("##", &value, speed, p_min, p_max, displayFormat, flags);
+      static bool startRecording = false;
+      if (hasChange)
       {
-        if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
-        else if (ImGui::IsItemDeactivatedAfterEdit())
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
-
-        return true;
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
       }
-
-      return false;
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if(!tooltip.empty())
+      {
+        if(ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
+      return hasChange;
     }
 
-    static bool DragInt(const std::string& fieldLabel, std::function<int(void)> get, std::function<void(int const&)> set,
+    static bool DragInt(const std::string& label, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {},
       float speed = 1.0f, int p_min = int(), int p_max = int(), const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
     {
       int value = get();
-      //bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags);
-      if (ImGui::DragInt(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      const bool hasChange = ImGui::DragInt("##", &value, speed, p_min, p_max, displayFormat, flags);
+      static bool startRecording = false;
+      if (hasChange)
       {
-        if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), true);
-        else if (ImGui::IsItemDeactivatedAfterEdit())
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
-
-        return true;
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
       }
-
-      return false;
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
+      return hasChange;
     }
     template <typename T>
-    static bool SliderScalar(const std::string& fieldLabel, ImGuiDataType data_type, T min, T max, std::function<T(void)> get, std::function<void(T const&)> set,
+    static bool SliderScalar(const std::string& label, ImGuiDataType data_type, T min, T max, std::function<T(void)> get, std::function<void(T const&)> set, std::string_view const& tooltip = {},
       const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
     {
       T value = get();
-      if (ImGui::SliderScalar(fieldLabel.c_str(), data_type, &value, &min, &max, displayFormat, flags))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      bool const hasChange = ImGui::SliderScalar("##", data_type, &value, &min, &max, displayFormat, flags);
+      static bool startRecording = false;
+      if (hasChange)
       {
-        if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
 
-        return true;
       }
-
-      return false;
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
+      return hasChange;
     }
 
-    static bool SliderFloat(const std::string& fieldLabel, float min, float max, std::function<float(void)> get, std::function<void(float   const&)> set,
+    static bool SliderFloat(const std::string& label, float const& min, float const& max, std::function<float(void)> get, std::function<void(float const&)> set, std::string_view const& tooltip = {},
       const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
     {
       float value = get();
-      if (ImGui::SliderFloat(fieldLabel.c_str(), &value, min, max, displayFormat, flags))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      bool const hasChange = ImGui::SliderFloat("##", &value, min, max, displayFormat, flags);
+      static bool startRecording = false;
+      if (hasChange)
       {
-        if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
 
-
-        return true;
       }
-
-      return false;
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
+      return hasChange;
     }
 
-    static bool SliderInt(const std::string& fieldLabel, int min, int max, std::function<int(void)> get, std::function<void(int const&)>  set,
+    static bool SliderInt(const std::string& label, int min, int max, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {},
       const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
     {
       int value = get();
-      if (ImGui::SliderInt(fieldLabel.c_str(), &value, min, max, displayFormat, flags))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      bool const hasChange = ImGui::SliderInt("##", &value, min, max, displayFormat, flags);
+      static bool startRecording = false;
+      if (hasChange)
       {
-        if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), true);
 
-        return true;
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
       }
-
-      return false;
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
+      return hasChange;
     }
 
-    static bool ComboBox(const std::string& fieldLabel, std::vector<const char*> list, std::function<int(void)> get, std::function<void(int   const&)> set)
+    static bool ComboBox(const std::string& label, std::vector<const char*> list, std::function<int(void)> get, std::function<void(int   const&)> set, std::string_view const& tooltip = {})
     {
       bool edited = false;
       int selected = get();
-      ImGui::PushID(fieldLabel.c_str());
-      ImGui::Text(fieldLabel.c_str()); ImGui::SameLine();
+      ImGui::BeginGroup();
+      ImGui::PushID(label.c_str());
+      TextLabel(label);
+      ImGui::SameLine();
 
       if (edited = ImGui::Combo("##Combo", &selected, list.data(), static_cast<int>(list.size())))
       {
         SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), selected, set)), false);
       }
       ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
       return edited;
     }
   };
diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h
index 317b67c1..fc9f41e1 100644
--- a/SHADE_Engine/src/Events/SHEventDefines.h
+++ b/SHADE_Engine/src/Events/SHEventDefines.h
@@ -5,8 +5,9 @@ typedef uint32_t SHEventIdentifier;
 typedef uint32_t SHEventHandle;
 
 //Add your event identifiers here:
-constexpr SHEventIdentifier SH_EXAMPLE_EVENT{0};
-constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT{ 1 };
-constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT{ 2 };
-constexpr SHEventIdentifier	SH_COMPONENT_ADDED_EVENT{ 3 };
-constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT{ 4 };
+constexpr SHEventIdentifier SH_EXAMPLE_EVENT                  { 0 };
+constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT         { 1 };
+constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT          { 2 };
+constexpr SHEventIdentifier	SH_COMPONENT_ADDED_EVENT          { 3 };
+constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT        { 4 };
+constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 };
diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp
index 4300f2bd..7443b6e2 100644
--- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp
+++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp
@@ -49,7 +49,7 @@ namespace SHADE
   SHVkSampler::~SHVkSampler() noexcept
   {
     if (vkSampler)
-      device->GetVkLogicalDevice().destroySampler();
+      device->GetVkLogicalDevice().destroySampler(vkSampler);
   }
 
   /*-----------------------------------------------------------------------------------*/
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp
index 476351c9..09fde60f 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp
@@ -30,184 +30,199 @@ of DigiPen Institute of Technology is prohibited.
 
 namespace SHADE
 {
-    /*---------------------------------------------------------------------------------*/
-    /* SHBatch - Usage Functions                                                       */
-    /*---------------------------------------------------------------------------------*/
-    SHBatch::SHBatch(Handle<SHVkPipeline> pipeline)
+  /*---------------------------------------------------------------------------------*/
+  /* SHBatch - Usage Functions                                                       */
+  /*---------------------------------------------------------------------------------*/
+  SHBatch::SHBatch(Handle<SHVkPipeline> pipeline)
     : pipeline{ pipeline }
-    {
-        if (!pipeline)
-            throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!");
+  {
+    if (!pipeline)
+      throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!");
 
-        // Mark all as dirty
-        setAllDirtyFlags();
+    // Mark all as dirty
+    setAllDirtyFlags();
+  }
+
+  void SHBatch::Add(const SHRenderable* renderable)
+  {
+    // Check if we have a SubBatch with the same mesh yet
+    auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
+      {
+        return batch.Mesh == renderable->Mesh;
+      });
+
+    // Create one if not found
+    if (subBatch == subBatches.end())
+    {
+      subBatches.emplace_back(renderable->Mesh);
+      subBatch = subBatches.end() - 1;
     }
 
-    void SHBatch::Add(const SHRenderable* renderable)
-    {
-        // Check if we have a SubBatch with the same mesh yet
-        auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
-        {
-            return batch.Mesh == renderable->Mesh;
-        });
+    // Add renderable in
+    subBatch->Renderables.insert(renderable->GetEID());
 
-        // Create one if not found
-        if (subBatch == subBatches.end())
+    // Also add material instance in
+    referencedMatInstances.insert(renderable->GetMaterial());
+
+    // Mark all as dirty
+    setAllDirtyFlags();
+  }
+
+  void SHBatch::Remove(const SHRenderable* renderable)
+  {
+    // Check if we have a SubBatch with the same mesh yet
+    auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
+      {
+        return batch.Mesh == renderable->Mesh;
+      });
+
+    // Attempt to remove if it exists
+    if (subBatch == subBatches.end())
+      return;
+
+    subBatch->Renderables.erase(renderable->GetEID());
+
+    // Check if other renderables in subBatches contain the same material instance
+    bool matUnused = true;
+    for (const auto& sb : subBatches)
+      for (const auto& rendId : sb.Renderables)
+      {
+        auto rend = SHComponentManager::GetComponent<SHRenderable>(rendId);
+        if (rend)
         {
-            subBatches.emplace_back(renderable->Mesh);
-            subBatch = subBatches.end() - 1;
+          if (rend->GetMaterial() == renderable->GetMaterial())
+          {
+            matUnused = false;
+            break;
+          }
         }
+        else
+        {
+          SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
+        }
+      }
 
-        // Add renderable in
-        subBatch->Renderables.insert(renderable);
+    // Material is no longer in this library, so we remove it
+    if (matUnused)
+      referencedMatInstances.erase(renderable->WasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial());
 
-        // Also add material instance in
-        referencedMatInstances.insert(renderable->GetMaterial());
+    // Mark all as dirty
+    setAllDirtyFlags();
+  }
 
-        // Mark all as dirty
-        setAllDirtyFlags();
+  void SHBatch::Clear()
+  {
+    subBatches.clear();
+
+    // Clear CPU buffers
+    drawData.clear();
+    transformData.clear();
+    instancedIntegerData.clear();
+    matPropsData.reset();
+    matPropsDataSize = 0;
+
+
+    // Clear GPU buffers
+    for (int i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
+    {
+      drawDataBuffer[i].Free();
+      transformDataBuffer[i].Free();
+      instancedIntegerBuffer[i].Free();
+      matPropsBuffer[i].Free();
+    }
+  }
+
+  void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
+  {
+    if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
+    {
+      SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
+      return;
     }
 
-    void SHBatch::Remove(const SHRenderable* renderable)
+    // Check if there are even material properties to update
+    if (!matPropsData)
+      return;
+
+    // Check if any materials have changed
+    bool hasChanged = false;
+    for (const auto& material : referencedMatInstances)
     {
-        // Check if we have a SubBatch with the same mesh yet
-        auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
-        {
-            return batch.Mesh == renderable->Mesh;
-        });
-
-        // Attempt to remove if it exists
-        if (subBatch == subBatches.end())
-            return;
-
-        subBatch->Renderables.erase(renderable);
-
-        // Check if other renderables in subBatches contain the same material instance
-        bool matUnused = true;
-        for (const auto& sb : subBatches)
-        for (const auto& rend : sb.Renderables)
-        {
-            if (rend->GetMaterial() == renderable->GetMaterial())
-            {
-                matUnused = false;
-                break;
-            }
-        }
-
-        // Material is no longer in this library, so we remove it
-        if (matUnused)
-            referencedMatInstances.erase(renderable->GetMaterial());
-
-        // Mark all as dirty
-        for (bool& dirt : isDirty)
-            dirt = true;
+      if (material->HasChanged())
+      {
+        hasChanged = true;
+        break;
+      }
     }
 
-    void SHBatch::Clear()
+    // We need to update all the material buffers if the materials have changed
+    if (hasChanged)
     {
-        subBatches.clear();
-
-        // Clear CPU buffers
-        drawData.clear();
-        transformData.clear();
-        instancedIntegerData.clear();
-        matPropsData.reset();
-        matPropsDataSize = 0;
-
-
-        // Clear GPU buffers
-        for (int i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
-        {
-            drawDataBuffer[i].Free();
-            transformDataBuffer[i].Free();
-            instancedIntegerBuffer[i].Free();
-            matPropsBuffer[i].Free();
-        }
+      for (auto& dirt : matBufferDirty)
+        dirt = true;
     }
 
-	void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
-	{
-		if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
-		{
-			SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
-			return;
-		}
+    // Check if this frame's buffer is dirty
+    if (!matBufferDirty[frameIndex])
+      return;
 
-        // Check if there are even material properties to update
-        if (!matPropsData)
-            return;
-
-        // Check if any materials have changed
-        bool hasChanged = false;
-        for (const auto& material : referencedMatInstances)
+    // Build CPU Buffer
+    char* propsCurrPtr = matPropsData.get();
+    for (auto& subBatch : subBatches)
+      for (auto rendId : subBatch.Renderables)
+      {
+        const SHRenderable* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
+        if (renderable)
         {
-            if (material->HasChanged())
-            {
-                hasChanged = true;
-                break;
-            }
+          renderable->GetMaterial()->ExportProperties(propsCurrPtr);
         }
-
-        // We need to update all the material buffers if the materials have changed
-        if (hasChanged)
+        else
         {
-            for (auto& dirt : matBufferDirty)
-			    dirt = true;
+          SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
         }
+        propsCurrPtr += singleMatPropAlignedSize;
+      }
 
-        // Check if this frame's buffer is dirty
-        if (!matBufferDirty[frameIndex])
-            return;
+    // Transfer to GPU
+    rebuildMaterialBuffers(frameIndex, descPool);
 
-		// Build CPU Buffer
-		char* propsCurrPtr = matPropsData.get();
-		for (auto& subBatch : subBatches)
-		for (const SHRenderable* renderable : subBatch.Renderables)
-		{
-			renderable->GetMaterial()->ExportProperties(propsCurrPtr);
-			propsCurrPtr += singleMatPropAlignedSize;
-		}
-        
-        // Transfer to GPU
-        rebuildMaterialBuffers(frameIndex, descPool);
+    // This frame is updated
+    matBufferDirty[frameIndex] = false;
+  }
 
-        // This frame is updated
-        matBufferDirty[frameIndex] = false;
-	}
-
-	void SHBatch::UpdateTransformBuffer(uint32_t frameIndex)
+  void SHBatch::UpdateTransformBuffer(uint32_t frameIndex)
+  {
+    if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
     {
-        if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
-        {
-            SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
-            return;
-        }
-
-        // Reset Transform Data
-        transformData.clear();
-
-        // Populate on the CPU
-        for (auto& subBatch : subBatches)
-        for (const SHRenderable* renderable : subBatch.Renderables)
-        {
-            // Transform
-            auto transform = SHComponentManager::GetComponent<SHTransformComponent>(renderable->GetEID());
-            if (!transform)
-            {
-                SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
-                transformData.emplace_back();
-            }
-            else
-            {
-                transformData.emplace_back(transform->GetTRS());
-            }
-        }
-
-        // Transfer to GPU
-        if (transformDataBuffer[frameIndex])
-          transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
+      SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
+      return;
     }
 
+    // Reset Transform Data
+    transformData.clear();
+
+    // Populate on the CPU
+    for (auto& subBatch : subBatches)
+      for (auto rendId : subBatch.Renderables)
+      {
+        // Transform
+        auto transform = SHComponentManager::GetComponent<SHTransformComponent>(rendId);
+        if (transform)
+        {
+          transformData.emplace_back(transform->GetTRS());
+        }
+        else
+        {
+          SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
+          transformData.emplace_back();
+        }
+      }
+
+    // Transfer to GPU
+    if (transformDataBuffer[frameIndex])
+      transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
+  }
+
   void SHBatch::UpdateInstancedIntegerBuffer(uint32_t frameIndex)
   {
     if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
@@ -221,11 +236,12 @@ namespace SHADE
 
     // Populate on the CPU
     for (auto& subBatch : subBatches)
-      for (const SHRenderable* renderable : subBatch.Renderables)
+      for (auto rendId : subBatch.Renderables)
       {
+        auto* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
         instancedIntegerData.emplace_back(SHInstancedIntegerData
           {
-            renderable->GetEID(),
+            rendId,
             renderable->GetLightLayer()
           }
         );
@@ -238,213 +254,222 @@ namespace SHADE
   }
 
   void SHBatch::Build(Handle<SHVkLogicalDevice> _device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex)
+  {
+    if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
     {
-        if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
-        {
-            SHLOG_WARNING("[SHBatch] Attempted to update build batch buffers with an invalid frame index.");
-            return;
-        }
-
-        // Save logical device
-        device = _device;
-
-        // No need to build as there are no changes
-        if (!isDirty[frameIndex])
-            return;
-
-        // Count number of elements
-        size_t numTotalElements = 0;
-        for (const auto& subBatch : subBatches)
-        {
-            numTotalElements += subBatch.Renderables.size();
-        }
-
-        // Generate CPU buffers if there are changes
-        if (isCPUBuffersDirty)
-        {
-            // - Draw data
-            drawData.reserve(subBatches.size());
-            drawData.clear();
-            // - Transform data
-            transformData.reserve(numTotalElements);
-            transformData.clear();
-            // - EID data
-            instancedIntegerData.reserve(numTotalElements);
-            instancedIntegerData.clear();
-
-
-            // - Material Properties Data
-		    const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
-		    (
-			    SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
-			    SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
-			    vk::ShaderStageFlagBits::eFragment
-		    );
-            const bool EMPTY_MAT_PROPS = !SHADER_INFO;
-            Byte matPropTotalBytes = 0;
-            if (!EMPTY_MAT_PROPS)
-            {
-                singleMatPropSize = SHADER_INFO->GetBytesRequired();
-                singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
-                matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
-                if (matPropsDataSize < matPropTotalBytes)
-                {
-                    matPropsData.reset(new char[matPropTotalBytes]);
-                    matPropsDataSize = matPropTotalBytes;
-                }
-            }
-
-            // Build Sub Batches
-            uint32_t nextInstanceIndex = 0;
-            char* propsCurrPtr = matPropsData.get();
-            for (auto& subBatch : subBatches)
-            {
-                // Create command
-                drawData.emplace_back(vk::DrawIndexedIndirectCommand
-                {
-                    .indexCount = subBatch.Mesh->IndexCount,
-                    .instanceCount = static_cast<uint32_t>(subBatch.Renderables.size()),
-                    .firstIndex = subBatch.Mesh->FirstIndex,
-                    .vertexOffset = subBatch.Mesh->FirstVertex,
-                    .firstInstance = nextInstanceIndex++
-                });
-
-                // Fill in buffers (CPU)
-                for (const SHRenderable* renderable : subBatch.Renderables)
-                {
-                    // Transform
-                    EntityID eid = renderable->GetEID();
-                    auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
-                    if (!transform)
-                    {
-                        SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
-                        transformData.emplace_back();
-                    }
-                    else
-                    {
-                        transformData.emplace_back(transform->GetTRS());
-                    }
-
-                    instancedIntegerData.emplace_back(SHInstancedIntegerData
-                      {
-                        eid,
-                        renderable->GetLightLayer()
-                      }
-                    );
-
-                    // Material Properties
-                    if (!EMPTY_MAT_PROPS)
-                    {
-                        renderable->GetMaterial()->ExportProperties(propsCurrPtr);
-                        propsCurrPtr += singleMatPropAlignedSize;
-                    }
-                }
-            }
-
-            // Successfully update CPU buffers
-            isCPUBuffersDirty = false;
-        }
-
-        // Send all buffered data to the GPU buffers
-        using BuffUsage = vk::BufferUsageFlagBits;
-        // - Draw Data
-        const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
-        SHVkUtil::EnsureBufferAndCopyHostVisibleData
-        (
-            device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
-            BuffUsage::eIndirectBuffer
-        );
-        // - Transform Buffer
-        const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
-        SHVkUtil::EnsureBufferAndCopyHostVisibleData
-        (
-            device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
-            BuffUsage::eVertexBuffer
-        );
-        const uint32_t EID_DATA_BYTES = static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData));
-        SHVkUtil::EnsureBufferAndCopyHostVisibleData
-        (
-          device, instancedIntegerBuffer[frameIndex], instancedIntegerData.data(), EID_DATA_BYTES,
-          BuffUsage::eVertexBuffer
-        );
-        // - Material Properties Buffer
-        rebuildMaterialBuffers(frameIndex, descPool);
-
-        // Mark this frame as no longer dirty
-        isDirty[frameIndex] = false;
+      SHLOG_WARNING("[SHBatch] Attempted to update build batch buffers with an invalid frame index.");
+      return;
     }
 
-    /*---------------------------------------------------------------------------------*/
-    /* SHBatch - Usage Functions                                                       */
-    /*---------------------------------------------------------------------------------*/
-    void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
-    {
-      if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
-        {
-            SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index.");
-            return;
-        }
+    // Save logical device
+    device = _device;
 
-        // Bind all required objects before drawing
-        static std::array<uint32_t, 1> dynamicOffset { 0 };
-        cmdBuffer->BindPipeline(pipeline);
-        cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM,    transformDataBuffer[frameIndex], 0);
-        cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0);
-        if (matPropsDescSet[frameIndex])
+    // No need to build as there are no changes
+    if (!isDirty[frameIndex])
+      return;
+
+    // Count number of elements
+    size_t numTotalElements = 0;
+    for (const auto& subBatch : subBatches)
+    {
+      numTotalElements += subBatch.Renderables.size();
+    }
+
+    // Generate CPU buffers if there are changes
+    if (isCPUBuffersDirty)
+    {
+      // - Draw data
+      drawData.reserve(subBatches.size());
+      drawData.clear();
+      // - Transform data
+      transformData.reserve(numTotalElements);
+      transformData.clear();
+      // - EID data
+      instancedIntegerData.reserve(numTotalElements);
+      instancedIntegerData.clear();
+
+
+      // - Material Properties Data
+      const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
+      (
+        SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
+        SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
+        vk::ShaderStageFlagBits::eFragment
+      );
+      const bool EMPTY_MAT_PROPS = !SHADER_INFO;
+      Byte matPropTotalBytes = 0;
+      if (!EMPTY_MAT_PROPS)
+      {
+        singleMatPropSize = SHADER_INFO->GetBytesRequired();
+        singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
+        matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
+        if (matPropsDataSize < matPropTotalBytes)
         {
-          cmdBuffer->BindDescriptorSet
-          (
-            matPropsDescSet[frameIndex],
-            SH_PIPELINE_TYPE::GRAPHICS,
-            SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
-            dynamicOffset
+          matPropsData.reset(new char[matPropTotalBytes]);
+          matPropsDataSize = matPropTotalBytes;
+        }
+      }
+
+      // Build Sub Batches
+      uint32_t nextInstanceIndex = 0;
+      char* propsCurrPtr = matPropsData.get();
+      for (auto& subBatch : subBatches)
+      {
+        // Create command
+        const uint32_t CURR_INSTANCES = static_cast<uint32_t>(subBatch.Renderables.size());
+        drawData.emplace_back(vk::DrawIndexedIndirectCommand
+          {
+              .indexCount = subBatch.Mesh->IndexCount,
+              .instanceCount = CURR_INSTANCES,
+              .firstIndex = subBatch.Mesh->FirstIndex,
+              .vertexOffset = subBatch.Mesh->FirstVertex,
+              .firstInstance = nextInstanceIndex
+          });
+        nextInstanceIndex += CURR_INSTANCES;
+
+        // Fill in buffers (CPU)
+        for (auto rendId : subBatch.Renderables)
+        {
+          // Transform
+          auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(rendId);
+          if (!transform)
+          {
+            SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
+            transformData.emplace_back();
+          }
+          else
+          {
+            transformData.emplace_back(transform->GetTRS());
+          }
+
+          const SHRenderable* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
+          instancedIntegerData.emplace_back(SHInstancedIntegerData
+            {
+              rendId,
+              renderable->GetLightLayer()
+            }
           );
-        }
-        cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
-    }
 
-    /*---------------------------------------------------------------------------------*/
-    /* SHBatch - Helper Functions                                                      */
-    /*---------------------------------------------------------------------------------*/
-    void SHBatch::setAllDirtyFlags()
-    {
-        for (bool& dirt : isDirty)
-            dirt = true;
-        isCPUBuffersDirty = true;
-    }
-
-    void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
-    {
-        if (matPropsData)
-        {
-            SHVkUtil::EnsureBufferAndCopyHostVisibleData
-            (
-                device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
-                vk::BufferUsageFlagBits::eStorageBuffer
-            );
-
-            if (!matPropsDescSet[frameIndex])
+          // Material Properties
+          if (!EMPTY_MAT_PROPS)
+          {
+            if (renderable)
             {
-                matPropsDescSet[frameIndex] = descPool->Allocate
-                (
-                    { SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] },
-                    { 0 }
-                );
+              renderable->GetMaterial()->ExportProperties(propsCurrPtr);
             }
-            std::array<Handle<SHVkBuffer>, 1>  bufferList = { matPropsBuffer[frameIndex] };
-            matPropsDescSet[frameIndex]->ModifyWriteDescBuffer
-            (
-                SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
-                SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
-                bufferList,
-                0, static_cast<uint32_t>(matPropsDataSize)
-            );
-            matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer
-            (
-                SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
-                SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA
-            );
+            else
+            {
+              SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
+            }
+            propsCurrPtr += singleMatPropAlignedSize;
+          }
         }
+      }
+
+      // Successfully update CPU buffers
+      isCPUBuffersDirty = false;
     }
 
+    // Send all buffered data to the GPU buffers
+    using BuffUsage = vk::BufferUsageFlagBits;
+    // - Draw Data
+    const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
+    SHVkUtil::EnsureBufferAndCopyHostVisibleData
+    (
+      device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
+      BuffUsage::eIndirectBuffer
+    );
+    // - Transform Buffer
+    const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
+    SHVkUtil::EnsureBufferAndCopyHostVisibleData
+    (
+      device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
+      BuffUsage::eVertexBuffer
+    );
+    const uint32_t EID_DATA_BYTES = static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData));
+    SHVkUtil::EnsureBufferAndCopyHostVisibleData
+    (
+      device, instancedIntegerBuffer[frameIndex], instancedIntegerData.data(), EID_DATA_BYTES,
+      BuffUsage::eVertexBuffer
+    );
+    // - Material Properties Buffer
+    rebuildMaterialBuffers(frameIndex, descPool);
+
+    // Mark this frame as no longer dirty
+    isDirty[frameIndex] = false;
+  }
+
+  /*---------------------------------------------------------------------------------*/
+  /* SHBatch - Usage Functions                                                       */
+  /*---------------------------------------------------------------------------------*/
+  void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
+  {
+    if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
+    {
+      SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index.");
+      return;
+    }
+
+    // Bind all required objects before drawing
+    static std::array<uint32_t, 1> dynamicOffset{ 0 };
+    cmdBuffer->BindPipeline(pipeline);
+    cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
+    cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0);
+    if (matPropsDescSet[frameIndex])
+    {
+      cmdBuffer->BindDescriptorSet
+      (
+        matPropsDescSet[frameIndex],
+        SH_PIPELINE_TYPE::GRAPHICS,
+        SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
+        dynamicOffset
+      );
+    }
+    cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
+  }
+
+  /*---------------------------------------------------------------------------------*/
+  /* SHBatch - Helper Functions                                                      */
+  /*---------------------------------------------------------------------------------*/
+  void SHBatch::setAllDirtyFlags()
+  {
+    for (bool& dirt : isDirty)
+      dirt = true;
+    isCPUBuffersDirty = true;
+  }
+
+  void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
+  {
+    if (matPropsData)
+    {
+      SHVkUtil::EnsureBufferAndCopyHostVisibleData
+      (
+        device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
+        vk::BufferUsageFlagBits::eStorageBuffer
+      );
+
+      if (!matPropsDescSet[frameIndex])
+      {
+        matPropsDescSet[frameIndex] = descPool->Allocate
+        (
+          { SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] },
+          { 0 }
+        );
+      }
+      std::array<Handle<SHVkBuffer>, 1>  bufferList = { matPropsBuffer[frameIndex] };
+      matPropsDescSet[frameIndex]->ModifyWriteDescBuffer
+      (
+        SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
+        SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
+        bufferList,
+        0, static_cast<uint32_t>(matPropsDataSize)
+      );
+      matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer
+      (
+        SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
+        SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA
+      );
+    }
+  }
+
 }
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h
index a7124e05..de137b28 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h
@@ -56,7 +56,7 @@ namespace SHADE
         /* Data Members                                                                */
         /*-----------------------------------------------------------------------------*/
         Handle<SHMesh> Mesh;
-        std::unordered_set<const SHRenderable*> Renderables;
+        std::unordered_set<EntityID> Renderables;
     };
     /***********************************************************************************/
     /*!
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp
index 7b8b9e45..9b984a4b 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp
@@ -700,10 +700,10 @@ namespace SHADE
         continue;
     
       // Remove from old material's SuperBatch
-      Handle<SHMaterial> prevMaterial = renderable.GetPrevMaterial();
+      Handle<SHMaterialInstance> prevMaterial = renderable.GetPrevMaterial();
       if (prevMaterial)
       {
-        Handle<SHSuperBatch> oldSuperBatch = prevMaterial->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
+        Handle<SHSuperBatch> oldSuperBatch = prevMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
         oldSuperBatch->Remove(&renderable);
       }
     
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp
index 523722e4..7c4d0bb9 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp
@@ -33,15 +33,16 @@ namespace SHADE
 
   void SHRenderable::OnDestroy()
   {
+    // Remove from SuperBatch
+    Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
+	superBatch->Remove(this);
+
+    // Free resources
     if (material)
     {
       material.Free();
       material = {};
     }
-
-    // Remove from SuperBatch
-    Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
-	superBatch->Remove(this);
   }
   
   /*-----------------------------------------------------------------------------------*/
@@ -53,20 +54,23 @@ namespace SHADE
     if (!material && sharedMaterial == materialInstance)
       return;
 
+    // Flag that material was changed
+    materialChanged = true;
+
     // Free copies of materials if any
     if (material)
     {
+      oldMaterial = material;
       material.Free();
       material = {};
     }
-
-    // Flag that material was changed
-	materialChanged = true;
-    if (sharedMaterial)
-	  oldMaterial = sharedMaterial->GetBaseMaterial();
+    else if (sharedMaterial)
+    {
+      oldMaterial = sharedMaterial;
+    }
 
     // Update the material
-    sharedMaterial = materialInstance;	
+    sharedMaterial = materialInstance;
   }
 
   Handle<SHMaterialInstance> SHRenderable::GetMaterial() const
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h
index 95b53b9e..75e42d60 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h
@@ -55,7 +55,7 @@ namespace SHADE
       /* Getter Functions                                                              */
       /*-------------------------------------------------------------------------------*/
       bool WasMaterialChanged() const noexcept { return materialChanged; }
-      Handle<SHMaterial> GetPrevMaterial() const noexcept { return oldMaterial; }
+      Handle<SHMaterialInstance> GetPrevMaterial() const noexcept { return oldMaterial; }
       uint8_t GetLightLayer (void) const noexcept;
 
       /*-------------------------------------------------------------------------------*/
@@ -75,7 +75,7 @@ namespace SHADE
       Handle<SHMaterialInstance> sharedMaterial;
       Handle<SHMaterialInstance> material;
       bool materialChanged = true;
-      Handle<SHMaterial> oldMaterial; 
+      Handle<SHMaterialInstance> oldMaterial; 
       uint8_t lightLayer;
 	};
 }
diff --git a/SHADE_Engine/src/Math/SHMatrix.cpp b/SHADE_Engine/src/Math/SHMatrix.cpp
index 571fa4e0..ec3951e2 100644
--- a/SHADE_Engine/src/Math/SHMatrix.cpp
+++ b/SHADE_Engine/src/Math/SHMatrix.cpp
@@ -295,32 +295,33 @@ namespace SHADE
     ) != 0;
   }
 
+  SHMatrix::operator XMMATRIX() const noexcept
+  {
+    return XMLoadFloat4x4(this);
+  }
+
   SHMatrix operator*(float lhs, const SHMatrix& rhs) noexcept
   {
     return rhs * lhs;
   }
 
-
   /*-----------------------------------------------------------------------------------*/
   /* Function Member Definitions                                                       */
   /*-----------------------------------------------------------------------------------*/
 
   void SHMatrix::Transpose() noexcept
   {
-    const XMMATRIX M = XMLoadFloat4x4(this);
-    XMStoreFloat4x4(this, XMMatrixTranspose(M));
+    XMStoreFloat4x4(this, XMMatrixTranspose(*this));
   }
 
   void SHMatrix::Invert() noexcept
   {
-    const XMMATRIX M = XMLoadFloat4x4(this);
-    XMStoreFloat4x4(this, XMMatrixInverse(nullptr, M));
+    XMStoreFloat4x4(this, XMMatrixInverse(nullptr, *this));
   }
 
   float SHMatrix::Determinant() const noexcept
   {
-    const XMMATRIX M = XMLoadFloat4x4(this);
-    return XMVectorGetX(XMMatrixDeterminant(M));
+    return XMVectorGetX(XMMatrixDeterminant(*this));
   }
 
   std::string SHMatrix::ToString() const noexcept
@@ -337,9 +338,8 @@ namespace SHADE
   bool SHMatrix::Decompose(SHVec3& translation, SHVec3& rotation, SHVec3& scale) const noexcept
   {
     XMVECTOR s, r, t;
-    const XMMATRIX M = XMLoadFloat4x4(this);
 
-    if (!XMMatrixDecompose(&s, &r, &t, M))
+    if (!XMMatrixDecompose(&s, &r, &t, *this))
         return false;
 
     SHQuaternion orientation;
@@ -356,9 +356,8 @@ namespace SHADE
   bool SHMatrix::Decompose(SHVec3& translation, SHQuaternion& orientation, SHVec3& scale) const noexcept
   {
     XMVECTOR s, r, t;
-    const XMMATRIX M = XMLoadFloat4x4(this);
 
-    if (!XMMatrixDecompose(&s, &r, &t, M))
+    if (!XMMatrixDecompose(&s, &r, &t, *this))
         return false;
 
     XMStoreFloat3(&scale, s);
@@ -376,8 +375,7 @@ namespace SHADE
   {
     SHMatrix result;
 
-    const XMMATRIX M = XMLoadFloat4x4(&matrix);
-    XMStoreFloat4x4(&result, XMMatrixTranspose(M));
+    XMStoreFloat4x4(&result, XMMatrixTranspose(matrix));
     return result;
   }
 
@@ -385,8 +383,7 @@ namespace SHADE
   {
     SHMatrix result;
 
-    const XMMATRIX M = XMLoadFloat4x4(&matrix);
-    XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, M));
+    XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, matrix));
     return result;
   }
 
@@ -401,8 +398,8 @@ namespace SHADE
   SHMatrix SHMatrix::Translate(const SHVec3& pos) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z));
 
+    XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z));
     return result;
   }
 
@@ -410,25 +407,23 @@ namespace SHADE
   {
     SHMatrix result;
 
-    const XMVECTOR A = XMLoadFloat3(&axis);
-    XMStoreFloat4x4(&result, XMMatrixRotationAxis(A, angleInRad));
-
+    XMStoreFloat4x4(&result, XMMatrixRotationAxis(axis, angleInRad));
     return result;
   }
 
   SHMatrix SHMatrix::Rotate(float yaw, float pitch, float roll) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll));
 
+    XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll));
     return result;
   }
 
   SHMatrix SHMatrix::Rotate(const SHVec3& eulerAngles) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(eulerAngles.x, eulerAngles.y, eulerAngles.z));
 
+    XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYawFromVector(eulerAngles));
     return result;
   }
 
@@ -436,57 +431,55 @@ namespace SHADE
   {
     SHMatrix result;
 
-    const XMVECTOR Q = XMLoadFloat4(&q);
-    XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(Q));
-
+    XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(q));
     return result;
   }
 
   SHMatrix SHMatrix::RotateX(float angleInRad) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad));
 
+    XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad));
     return result;
   }
 
   SHMatrix SHMatrix::RotateY(float angleInRad) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad));
 
+    XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad));
     return result;
   }
 
   SHMatrix SHMatrix::RotateZ(float angleInRad) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad));
 
+    XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad));
     return result;
   }
 
   SHMatrix SHMatrix::Scale(float uniformScaleFactor) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor));
 
+    XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor));
     return result;
   }
 
   SHMatrix SHMatrix::Scale(float x, float y, float z) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z));
 
+    XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z));
     return result;
   }
 
   SHMatrix SHMatrix::Scale(const SHVec3& scale) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixScaling(scale.x, scale.y, scale.z));
 
+    XMStoreFloat4x4(&result, XMMatrixScalingFromVector(scale));
     return result;
   }
 
@@ -494,12 +487,7 @@ namespace SHADE
   {
     SHMatrix result;
 
-    const XMVECTOR EYE  = XMLoadFloat3(&eye);
-    const XMVECTOR TGT  = XMLoadFloat3(&target);
-    const XMVECTOR UP   = XMLoadFloat3(&up);
-
-    XMStoreFloat4x4(&result, XMMatrixLookAtRH(EYE, TGT, UP));
-
+    XMStoreFloat4x4(&result, XMMatrixLookAtRH(eye, target, up));
     return result;
   }
 
@@ -507,12 +495,7 @@ namespace SHADE
   {
     SHMatrix result;
 
-    const XMVECTOR EYE  = XMLoadFloat3(&eye);
-    const XMVECTOR TGT  = XMLoadFloat3(&target);
-    const XMVECTOR UP   = XMLoadFloat3(&up);
-
-    XMStoreFloat4x4(&result, XMMatrixLookAtLH(EYE, TGT, UP));
-
+    XMStoreFloat4x4(&result, XMMatrixLookAtLH(eye, target, up));
     return result;
   }
 
@@ -522,8 +505,8 @@ namespace SHADE
 
     const SHVec3   FWD_HAT  = SHVec3::Normalise(-forward);
 
-    const XMVECTOR Z_HAT    = XMVector3Normalize(XMLoadFloat3(&FWD_HAT));
-    const XMVECTOR X_HAT    = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT));
+    const XMVECTOR Z_HAT    = XMVector3Normalize(FWD_HAT);
+    const XMVECTOR X_HAT    = XMVector3Normalize(XMVector3Cross(up, Z_HAT));
     const XMVECTOR Y_HAT    = XMVector3Cross(Z_HAT, X_HAT);
 
     XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT);
@@ -543,8 +526,8 @@ namespace SHADE
 
     const SHVec3   FWD_HAT  = SHVec3::Normalise(forward);
 
-    const XMVECTOR Z_HAT    = XMVector3Normalize(XMLoadFloat3(&FWD_HAT));
-    const XMVECTOR X_HAT    = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT));
+    const XMVECTOR Z_HAT    = XMVector3Normalize(FWD_HAT);
+    const XMVECTOR X_HAT    = XMVector3Normalize(XMVector3Cross(up, Z_HAT));
     const XMVECTOR Y_HAT    = XMVector3Cross(Z_HAT, X_HAT);
 
     XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT);
@@ -563,7 +546,6 @@ namespace SHADE
     SHMatrix result;
 
     XMStoreFloat4x4(&result, XMMatrixPerspectiveFovRH(fov, aspectRatio, nearPlane, farPlane));
-
     return result;
   }
 
@@ -572,7 +554,6 @@ namespace SHADE
     SHMatrix result;
 
     XMStoreFloat4x4(&result, XMMatrixPerspectiveFovLH(fov, aspectRatio, nearPlane, farPlane));
-
     return result;
   }
 
@@ -581,7 +562,6 @@ namespace SHADE
     SHMatrix result;
 
     XMStoreFloat4x4(&result, XMMatrixPerspectiveRH(width, height, nearPlane, farPlane));
-
     return result;
   }
 
@@ -590,7 +570,6 @@ namespace SHADE
     SHMatrix result;
 
     XMStoreFloat4x4(&result, XMMatrixPerspectiveLH(width, height, nearPlane, farPlane));
-
     return result;
   }
 
@@ -599,7 +578,6 @@ namespace SHADE
     SHMatrix result;
 
     XMStoreFloat4x4(&result, XMMatrixOrthographicRH(width, height, nearPlane, farPlane));
-
     return result;
   }
 
@@ -608,7 +586,6 @@ namespace SHADE
     SHMatrix result;
 
     XMStoreFloat4x4(&result, XMMatrixOrthographicLH(width, height, nearPlane, farPlane));
-
     return result;
   }
 
diff --git a/SHADE_Engine/src/Math/SHMatrix.h b/SHADE_Engine/src/Math/SHMatrix.h
index 7a662478..4d8f1bfe 100644
--- a/SHADE_Engine/src/Math/SHMatrix.h
+++ b/SHADE_Engine/src/Math/SHMatrix.h
@@ -77,6 +77,8 @@ namespace SHADE
     SHMatrix&               operator=   (const SHMatrix& rhs) = default;
     SHMatrix&               operator=   (SHMatrix&& rhs)      = default;
 
+    operator DirectX::XMMATRIX          ()                    const noexcept;
+
     SHMatrix&               operator+=  (const SHMatrix& rhs)       noexcept;
     SHMatrix&               operator-=  (const SHMatrix& rhs)       noexcept;
     SHMatrix&               operator*=  (const SHMatrix& rhs)       noexcept;
diff --git a/SHADE_Engine/src/Math/SHQuaternion.cpp b/SHADE_Engine/src/Math/SHQuaternion.cpp
index 33c568a5..3564916a 100644
--- a/SHADE_Engine/src/Math/SHQuaternion.cpp
+++ b/SHADE_Engine/src/Math/SHQuaternion.cpp
@@ -36,44 +36,18 @@ namespace SHADE
   : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
   {}
 
+  SHQuaternion::SHQuaternion(const SHVec4& vec4) noexcept
+  : XMFLOAT4( vec4.x, vec4.y, vec4.z, vec4.w )
+  {}
+
   SHQuaternion::SHQuaternion(float _x, float _y, float _z, float _w) noexcept
   : XMFLOAT4( _x, _y, _z, _w )
   {}
 
-  SHQuaternion::SHQuaternion(float yaw, float pitch, float roll) noexcept
-  : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
-  {
-    XMStoreFloat4(this, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll));
-  }
-
-  SHQuaternion::SHQuaternion(const SHVec3& eulerAngles) noexcept
-  : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
-  {
-    const XMVECTOR V = XMLoadFloat3(&eulerAngles);
-    XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V));
-  }
-
-  SHQuaternion::SHQuaternion(const SHVec3& axis, float angleInRad) noexcept
-  : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
-  {
-    const XMVECTOR AXIS = XMLoadFloat3(&axis);
-    XMStoreFloat4(this, XMQuaternionRotationAxis(AXIS, angleInRad));
-  }
-
-  SHQuaternion::SHQuaternion(const SHMatrix& rotationMatrix) noexcept
-  : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
-  {
-    const XMMATRIX M = XMLoadFloat4x4(&rotationMatrix);
-    XMStoreFloat4(this, XMQuaternionRotationMatrix(M));
-  }
-
   SHQuaternion::SHQuaternion(const reactphysics3d::Vector3& rp3dEuler) noexcept
   : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
   {
-    const SHVec3& SHADE_VEC{ rp3dEuler };
-
-    const XMVECTOR V = XMLoadFloat3(&SHADE_VEC);
-    XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V));
+    XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(SHVec3 { rp3dEuler }));
   }
 
   SHQuaternion::SHQuaternion(const reactphysics3d::Quaternion& rp3dQuat) noexcept
@@ -113,10 +87,7 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMLoadFloat4(&rhs);
-
-    XMStoreFloat4(&result, XMVectorAdd(Q1, Q2));
+    XMStoreFloat4(&result, XMVectorAdd(*this, rhs));
     return result;
   }
 
@@ -124,10 +95,7 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMLoadFloat4(&rhs);
-
-    XMStoreFloat4(&result, XMVectorSubtract(Q1, Q2));
+    XMStoreFloat4(&result, XMVectorSubtract(*this, rhs));
     return result;
   }
 
@@ -135,9 +103,7 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q = XMLoadFloat4(this);
-
-    XMStoreFloat4(&result, XMVectorNegate(Q));
+    XMStoreFloat4(&result, XMVectorNegate(*this));
     return result;
   }
 
@@ -145,10 +111,7 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMLoadFloat4(&rhs);
-
-    XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2));
+    XMStoreFloat4(&result, XMQuaternionMultiply(*this, rhs));
     return result;
   }
 
@@ -156,9 +119,7 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q = XMLoadFloat4(this);
-
-    XMStoreFloat4(&result, XMVectorScale(Q, rhs));
+    XMStoreFloat4(&result, XMVectorScale(*this, rhs));
     return result;
   }
 
@@ -166,27 +127,18 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMQuaternionInverse(XMLoadFloat4(&rhs));
-
-    XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2));
+    XMStoreFloat4(&result, XMQuaternionMultiply(*this, XMQuaternionInverse(rhs)));
     return result;
   }
 
   bool SHQuaternion::operator==(const SHQuaternion& rhs) const noexcept
   {
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMLoadFloat4(&rhs);
-
-    return XMQuaternionEqual(Q1, Q2);
+    return XMQuaternionEqual(*this, rhs);
   }
 
   bool SHQuaternion::operator!=(const SHQuaternion& rhs) const noexcept
   {
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMLoadFloat4(&rhs);
-
-    return XMQuaternionNotEqual(Q1, Q2);
+    return XMQuaternionNotEqual(*this, rhs);
   }
 
   SHQuaternion::operator reactphysics3d::Quaternion() const noexcept
@@ -199,6 +151,11 @@ namespace SHADE
     return reactphysics3d::Vector3{ ToEuler() };
   }
 
+  SHQuaternion::operator XMVECTOR() const noexcept
+  {
+    return XMLoadFloat4(this);
+  }
+
   SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept
   {
     return rhs * lhs;
@@ -213,8 +170,7 @@ namespace SHADE
     XMVECTOR axis;
     float angle;
 
-    const XMVECTOR Q = XMLoadFloat4(this);
-    XMQuaternionToAxisAngle(&axis, &angle, Q);
+    XMQuaternionToAxisAngle(&axis, &angle, *this);
     return angle;
   }
 
@@ -223,8 +179,7 @@ namespace SHADE
     XMVECTOR axis;
     float angle;
 
-    const XMVECTOR Q = XMLoadFloat4(this);
-    XMQuaternionToAxisAngle(&axis, &angle, Q);
+    XMQuaternionToAxisAngle(&axis, &angle, *this);
 
 
     return SHVec4{XMVectorGetX(axis), XMVectorGetY(axis), XMVectorGetZ(axis), angle};
@@ -238,64 +193,49 @@ namespace SHADE
 
   void SHQuaternion::Invert() noexcept
   {
-    const XMVECTOR Q = XMLoadFloat4(this);
-    XMStoreFloat4(this, XMQuaternionInverse(Q));
+    XMStoreFloat4(this, XMQuaternionInverse(*this));
   }
 
   float SHQuaternion::Length() const noexcept
   {
-    const XMVECTOR Q = XMLoadFloat4(this);
-    return XMVectorGetX(XMQuaternionLength(Q));
+    return XMVectorGetX(XMQuaternionLength(*this));
   }
 
   float SHQuaternion::LengthSquared() const noexcept
   {
-    const XMVECTOR Q = XMLoadFloat4(this);
-    return XMVectorGetX(XMQuaternionLengthSq(Q));
+    return XMVectorGetX(XMQuaternionLengthSq(*this));
   }
 
   float SHQuaternion::Dot(const SHQuaternion& rhs) const noexcept
   {
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMLoadFloat4(&rhs);
-
-    return XMVectorGetX(XMQuaternionDot(Q1, Q2));
-  }
-
-  SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion&, float) const noexcept
-  {
-    SHQuaternion result;
-
-    // TODO (Diren)
-
-    return result;
+    return XMVectorGetX(XMQuaternionDot(*this, rhs));
   }
 
   SHVec3 SHQuaternion::ToEuler() const noexcept
   {
-    const float xx = x * x;
-    const float yy = y * y;
-    const float zz = z * z;
+    const float XX = x * x;
+    const float YY = y * y;
+    const float ZZ = z * z;
 
-    const float m31 = 2.f * x * z + 2.f * y * w;
-    const float m32 = 2.f * y * z - 2.f * x * w;
-    const float m33 = 1.f - 2.f * xx - 2.f * yy;
+    const float M_31 = 2.f * x * z + 2.f * y * w;
+    const float M_32 = 2.f * y * z - 2.f * x * w;
+    const float M_33 = 1.f - 2.f * XX - 2.f * YY;
 
-    const float cy = sqrtf(m33 * m33 + m31 * m31);
-    const float cx = atan2f(-m32, cy);
-    if (cy > 16.0f * SHMath::EPSILON)
+    const float CY = sqrtf(M_33 * M_33 + M_31 * M_31);
+    const float CX = atan2f(-M_32, CY);
+    if (CY > 16.0f * SHMath::EPSILON)
     {
-        const float m12 = 2.f * x * y + 2.f * z * w;
-        const float m22 = 1.f - 2.f * xx - 2.f * zz;
+      const float M_12 = 2.f * x * y + 2.f * z * w;
+      const float M_22 = 1.f - 2.f * XX - 2.f * ZZ;
 
-        return SHVec3(cx, atan2f(m31, m33), atan2f(m12, m22));
+      return SHVec3(CX, atan2f(M_31, M_33), atan2f(M_12, M_22));
     }
     else
     {
-        const float m11 = 1.f - 2.f * yy - 2.f * zz;
-        const float m21 = 2.f * x * y - 2.f * z * w;
+      const float m11 = 1.f - 2.f * YY - 2.f * ZZ;
+      const float m21 = 2.f * x * y - 2.f * z * w;
 
-        return SHVec3(cx, 0.f, atan2f(-m21, m11));
+      return SHVec3(CX, 0.f, atan2f(-m21, m11));
     }
   }
 
@@ -311,13 +251,43 @@ namespace SHADE
   /* Static Function Member Definitions                                                */
   /*-----------------------------------------------------------------------------------*/
 
+  SHQuaternion SHQuaternion::FromEuler(const SHVec3& eulerAngles) noexcept
+  {
+    SHQuaternion result;
+
+    XMStoreFloat4(&result, XMQuaternionRotationRollPitchYawFromVector(eulerAngles));
+    return result;
+  }
+
+  SHQuaternion SHQuaternion::FromPitchYawRoll(float pitch, float yaw, float roll) noexcept
+  {
+    SHQuaternion result;
+
+    XMStoreFloat4(&result, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll));
+    return result;
+  }
+
+  SHQuaternion SHQuaternion::FromAxisAngle(const SHVec3& axis, float angle) noexcept
+  {
+    SHQuaternion result;
+
+    XMStoreFloat4(&result, XMQuaternionRotationAxis(axis, angle));
+    return result;
+  }
+
+  SHQuaternion SHQuaternion::FromRotationMatrix(const SHMatrix& rotationMatrix) noexcept
+  {
+    SHQuaternion result;
+
+    XMStoreFloat4(&result, XMQuaternionRotationMatrix(rotationMatrix));
+    return result;
+  }
+
   SHQuaternion SHQuaternion::Normalise(const SHQuaternion& q) noexcept
   {
     SHQuaternion result;
 
-    const XMVECTOR Q = XMLoadFloat4(&q);
-    
-    XMStoreFloat4(&result, XMQuaternionNormalize(Q));
+    XMStoreFloat4(&result, XMQuaternionNormalize(q));
     return result;
   }
 
@@ -325,9 +295,7 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q = XMLoadFloat4(&q);
-    
-    XMStoreFloat4(&result, XMQuaternionConjugate(Q));
+    XMStoreFloat4(&result, XMQuaternionConjugate(q));
     return result;
   }
 
@@ -335,26 +303,37 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q = XMLoadFloat4(&q);
-    XMStoreFloat4(&result, XMQuaternionInverse(Q));
-
+    XMStoreFloat4(&result, XMQuaternionInverse(q));
     return result;
   }
 
 
-  float SHQuaternion::Angle(const SHQuaternion&, const SHQuaternion&) noexcept
+  float SHQuaternion::Angle(const SHQuaternion& q1, const SHQuaternion& q2) noexcept
   {
-    // TODO (Diren)
+    XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(q1), q2);
 
-    return 0.0f;
+    const float RS = XMVectorGetW(R);
+    R = XMVector3Length(R);
+    return 2.0f * atan2f(XMVectorGetX(R), RS);
   }
 
-  SHQuaternion SHQuaternion::Lerp(const SHQuaternion&, const SHQuaternion&, float) noexcept
+  SHQuaternion SHQuaternion::Lerp(const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept
   {
     SHQuaternion result;
 
-    // TODO (Diren)
+    XMVECTOR R = XMVectorZero();
+    if (XMVector4GreaterOrEqual(XMVector4Dot(q1, q2), R))
+    {
+      R = XMVectorLerp(q1, q2, t);
+    }
+    else
+    {
+      const XMVECTOR X0 = XMVectorMultiply(q1, XMVectorReplicate(1.f - t));
+      const XMVECTOR X1 = XMVectorMultiply(q2, XMVectorReplicate(t));
+      R = XMVectorSubtract(X0, X1);
+    }
 
+    XMStoreFloat4(&result, XMQuaternionNormalize(R));
     return result;
   }
 
@@ -362,19 +341,105 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q1 = XMLoadFloat4(&q1);
-    const XMVECTOR Q2 = XMLoadFloat4(&q2);
-
-    XMStoreFloat4(&result, XMQuaternionSlerp(Q1, Q2, t));
+    XMStoreFloat4(&result, XMQuaternionSlerp(q1, q2, t));
     return result;
   }
 
-  SHQuaternion SHQuaternion::Rotate(const SHVec3& , const SHVec3&) noexcept
+  SHQuaternion SHQuaternion::ClampedLerp(const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin, float tMax) noexcept
+  {
+    return Lerp(q1, q2, std::clamp(t, tMin, tMax));
+  }
+
+
+  SHQuaternion SHQuaternion::ClampedSlerp(const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin, float tMax) noexcept
+  {
+    return Slerp(q1, q2, std::clamp(t, tMin, tMax));
+  }
+
+  SHQuaternion SHQuaternion::FromToRotation(const SHVec3& from, const SHVec3& to) noexcept
+  {
+    // Melax, "The Shortest Arc Quaternion", Game Programming Gems
+
+    SHQuaternion result;
+
+    const XMVECTOR F = XMVector3Normalize(from);
+    const XMVECTOR T = XMVector3Normalize(to);
+
+    const float dot = XMVectorGetX(XMVector3Dot(F, T));
+    if (dot >= 1.f)
+    {
+        result = Identity;
+    }
+    else if (dot <= -1.f)
+    {
+        XMVECTOR axis = XMVector3Cross(F, SHVec3::Right);
+        if (XMVector3NearEqual(XMVector3LengthSq(axis), g_XMZero, g_XMEpsilon))
+        {
+            axis = XMVector3Cross(F, SHVec3::Up);
+        }
+
+        const XMVECTOR Q = XMQuaternionRotationAxis(axis, XM_PI);
+        XMStoreFloat4(&result, Q);
+    }
+    else
+    {
+        const XMVECTOR C = XMVector3Cross(F, T);
+        XMStoreFloat4(&result, C);
+
+        const float s = sqrtf((1.f + dot) * 2.f);
+        result.x /= s;
+        result.y /= s;
+        result.z /= s;
+        result.w = s * 0.5f;
+    }
+
+    return result;
+  }
+
+  SHQuaternion SHQuaternion::LookRotation(const SHVec3& forward, const SHVec3& up) noexcept
   {
     SHQuaternion result;
 
-    // TODO (Diren)
+    const SHQuaternion Q1 = FromToRotation(SHVec3::Forward, forward);
 
+    const XMVECTOR C = XMVector3Cross(forward, up);
+    if (XMVector3NearEqual(XMVector3LengthSq(C), g_XMZero, g_XMEpsilon))
+    {
+        // forward and up are co-linear
+        return Q1;
+    }
+
+    SHVec3 qU;
+    XMStoreFloat3(&qU, XMQuaternionMultiply(Q1, SHVec3::Up));
+
+    const SHQuaternion Q2 = FromToRotation(qU, up);
+
+    XMStoreFloat4(&result, XMQuaternionMultiply(Q2, Q1));
+
+    return result;
+  }
+
+  SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion& from, const SHQuaternion& to, float maxAngleInRad) noexcept
+  {
+    SHQuaternion result;
+
+    // We can use the conjugate here instead of inverse assuming q1 & q2 are normalized.
+    const XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(from), to);
+
+    const float RS = XMVectorGetW(R);
+    const XMVECTOR L = XMVector3Length(R);
+    const float angle = 2.f * atan2f(XMVectorGetX(L), RS);
+    if (angle > maxAngleInRad)
+    {
+        const XMVECTOR delta = XMQuaternionRotationAxis(R, maxAngleInRad);
+        const XMVECTOR Q = XMQuaternionMultiply(delta, from);
+        XMStoreFloat4(&result, Q);
+    }
+    else
+    {
+        // Don't overshoot.
+        result = to;
+    }
     return result;
   }
 
diff --git a/SHADE_Engine/src/Math/SHQuaternion.h b/SHADE_Engine/src/Math/SHQuaternion.h
index c94907b5..fa5b5d36 100644
--- a/SHADE_Engine/src/Math/SHQuaternion.h
+++ b/SHADE_Engine/src/Math/SHQuaternion.h
@@ -49,11 +49,8 @@ namespace SHADE
     SHQuaternion  (SHQuaternion&& rhs)      = default;
 
     SHQuaternion  ()                                            noexcept;
+    SHQuaternion  (const SHVec4& vec4)                          noexcept;
     SHQuaternion  (float x, float y, float z, float w)          noexcept;
-    SHQuaternion  (float yaw, float pitch, float roll)          noexcept;
-    SHQuaternion  (const SHVec3& eulerAngles)                   noexcept;
-    SHQuaternion  (const SHVec3& axis, float angleInRad)        noexcept;
-    SHQuaternion  (const SHMatrix& rotationMatrix)              noexcept;
 
     // Conversion from other math types
 
@@ -87,6 +84,7 @@ namespace SHADE
 
     operator reactphysics3d::Quaternion       ()                        const noexcept;
     operator reactphysics3d::Vector3          ()                        const noexcept;
+    operator DirectX::XMVECTOR                ()                        const noexcept;
 
     /*---------------------------------------------------------------------------------*/
     /* Getter Functions                                                                */
@@ -99,29 +97,37 @@ namespace SHADE
     /* Function Members                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    void                        Invert        ()                                                      noexcept;
+    void                        Invert        ()  noexcept;
 
-    [[nodiscard]] float         Length        ()                                                const noexcept;
-    [[nodiscard]] float         LengthSquared ()                                                const noexcept;
-    [[nodiscard]] float         Dot           (const SHQuaternion& rhs)                         const noexcept;
-    [[nodiscard]] SHQuaternion  RotateTowards (const SHQuaternion& target, float maxAngleInRad) const noexcept;
+    [[nodiscard]] float         Length        ()  const noexcept;
+    [[nodiscard]] float         LengthSquared ()  const noexcept;
+    [[nodiscard]] float         Dot           (const SHQuaternion& rhs) const noexcept;
 
-    [[nodiscard]] SHVec3        ToEuler       ()                                                const noexcept;
-    [[nodiscard]] std::string   ToString      ()                                                const noexcept;
+    [[nodiscard]] SHVec3        ToEuler       ()  const noexcept;
+    [[nodiscard]] std::string   ToString      ()  const noexcept;
 
     /*---------------------------------------------------------------------------------*/
     /* Static Function Members                                                         */
     /*---------------------------------------------------------------------------------*/
 
-    [[nodiscard]] static SHQuaternion Normalise (const SHQuaternion& q)                                   noexcept;
-    [[nodiscard]] static SHQuaternion Conjugate (const SHQuaternion& q)                                   noexcept;
-    [[nodiscard]] static SHQuaternion Inverse   (const SHQuaternion& q)                                   noexcept;
-    [[nodiscard]] static float        Angle     (const SHQuaternion& q1, const SHQuaternion& q2)          noexcept;
+    [[nodiscard]] static SHQuaternion FromEuler         (const SHVec3& eulerAngles)           noexcept;
+    [[nodiscard]] static SHQuaternion FromPitchYawRoll  (float pitch, float yaw, float roll)  noexcept;
+    [[nodiscard]] static SHQuaternion FromAxisAngle     (const SHVec3& axis, float angle)     noexcept;
+    [[nodiscard]] static SHQuaternion FromRotationMatrix(const SHMatrix& rotationMatrix)      noexcept;
 
-    [[nodiscard]] static SHQuaternion Lerp      (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
-    [[nodiscard]] static SHQuaternion Slerp     (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
+    [[nodiscard]] static SHQuaternion Normalise         (const SHQuaternion& q) noexcept;
+    [[nodiscard]] static SHQuaternion Conjugate         (const SHQuaternion& q) noexcept;
+    [[nodiscard]] static SHQuaternion Inverse           (const SHQuaternion& q) noexcept;
+    [[nodiscard]] static float        Angle             (const SHQuaternion& q1, const SHQuaternion& q2) noexcept;
 
-    [[nodiscard]] static SHQuaternion Rotate    (const SHVec3& from, const SHVec3& to)                    noexcept;
+    [[nodiscard]] static SHQuaternion Lerp              (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
+    [[nodiscard]] static SHQuaternion Slerp             (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
+    [[nodiscard]] static SHQuaternion ClampedLerp       (const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
+    [[nodiscard]] static SHQuaternion ClampedSlerp      (const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
+
+    [[nodiscard]] static SHQuaternion FromToRotation  (const SHVec3& from, const SHVec3& to)    noexcept;
+    [[nodiscard]] static SHQuaternion LookRotation    (const SHVec3& forward, const SHVec3& up) noexcept;
+    [[nodiscard]] static SHQuaternion RotateTowards   (const SHQuaternion& from, const SHQuaternion& to, float maxAngleInRad) noexcept;
   };
 
   SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept;
diff --git a/SHADE_Engine/src/Math/Transform/SHTransform.cpp b/SHADE_Engine/src/Math/Transform/SHTransform.cpp
index f51d73ec..ef7c5fda 100644
--- a/SHADE_Engine/src/Math/Transform/SHTransform.cpp
+++ b/SHADE_Engine/src/Math/Transform/SHTransform.cpp
@@ -26,15 +26,15 @@ namespace SHADE
   /*-----------------------------------------------------------------------------------*/
 
   SHTransform::SHTransform() noexcept
-  : position  { SHVec3::Zero }
-  , rotation  { SHVec3::Zero }
-  , scale     { SHVec3::One  }
+  : position    { SHVec3::Zero }
+  , orientation { SHQuaternion::Identity }
+  , scale       { SHVec3::One  }
   {}
 
   SHTransform::SHTransform(const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept
-  : position  { pos }
-  , rotation  { rot }
-  , scale     { scl }
+  : position    { pos }
+  , orientation { SHQuaternion::FromEuler(rot) }
+  , scale       { scl }
   {}
 
   /*-----------------------------------------------------------------------------------*/
@@ -43,12 +43,12 @@ namespace SHADE
 
   bool SHTransform::operator==(const SHTransform& rhs) const noexcept
   {
-    return !(position != rhs.position || rotation != rhs.rotation || scale != rhs.scale);
+    return !(position != rhs.position || orientation != rhs.orientation || scale != rhs.scale);
   }
 
   bool SHTransform::operator!=(const SHTransform& rhs) const noexcept
   {
-    return (position != rhs.position || rotation != rhs.rotation || scale != rhs.scale);
+    return (position != rhs.position || orientation != rhs.orientation || scale != rhs.scale);
   }
 
   /*-----------------------------------------------------------------------------------*/
@@ -59,7 +59,7 @@ namespace SHADE
   {
     
     const SHMatrix T = SHMatrix::Translate(position);
-    const SHMatrix R = SHMatrix::Rotate(rotation);
+    const SHMatrix R = SHMatrix::Rotate(orientation);
     const SHMatrix S = SHMatrix::Scale(scale);
 
     trs = S * R * T;
diff --git a/SHADE_Engine/src/Math/Transform/SHTransform.h b/SHADE_Engine/src/Math/Transform/SHTransform.h
index c1a0e565..2e7d236c 100644
--- a/SHADE_Engine/src/Math/Transform/SHTransform.h
+++ b/SHADE_Engine/src/Math/Transform/SHTransform.h
@@ -12,8 +12,8 @@
 
 // Project Headers
 #include "SH_API.h"
-#include "Math/Vector/SHVec2.h"
 #include "Math/Vector/SHVec3.h"
+#include "Math/SHQuaternion.h"
 #include "Math/SHMatrix.h"
 
 namespace SHADE
@@ -31,22 +31,23 @@ namespace SHADE
 
     static const SHTransform Identity;
 
-    SHVec3    position;
-    SHVec3    rotation;
-    SHVec3    scale;
+    SHVec3        position;
+    SHQuaternion  orientation;
+    SHVec3        scale;
 
-    SHMatrix  trs;
+    SHMatrix      trs;
 
     /*---------------------------------------------------------------------------------*/
     /* Constructors & Destructor                                                       */
     /*---------------------------------------------------------------------------------*/
     
-    SHTransform             (const SHTransform&)  = default;
-    SHTransform             (SHTransform&&)       = default;
-    ~SHTransform            ()                    = default;
+    SHTransform   (const SHTransform&)  = default;
+    SHTransform   (SHTransform&&)       = default;
+    ~SHTransform  ()                    = default;
 
-    SHTransform             ()                                                        noexcept;
-    SHTransform             (const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept;
+    SHTransform   ()                                                                noexcept;
+    SHTransform   (const SHVec3& pos, const SHVec3& rot, const SHVec3& scl)         noexcept;
+    SHTransform   (const SHVec3& pos, const SHQuaternion& quat, const SHVec3& scl)  noexcept;
 
     /*---------------------------------------------------------------------------------*/
     /* Operator Overloads                                                              */
@@ -63,7 +64,6 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
 
     const SHMatrix& ComputeTRS();
-
   };
 
 } // namespace SHADE
\ No newline at end of file
diff --git a/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp b/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp
index 949cfa67..e56cbc8d 100644
--- a/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp
+++ b/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp
@@ -12,6 +12,8 @@
 
 // Primary Header
 #include "SHTransformComponent.h"
+// Project Headers
+#include "Math/SHMathHelpers.h"
 
 namespace SHADE
 {
@@ -40,7 +42,12 @@ namespace SHADE
 
   const SHVec3& SHTransformComponent::GetLocalRotation() const noexcept
   {
-    return local.rotation;
+    return localRotation;
+  }
+
+  const SHQuaternion& SHTransformComponent::GetLocalOrientation() const noexcept
+  {
+    return local.orientation;
   }
 
   const SHVec3& SHTransformComponent::GetLocalScale() const noexcept
@@ -55,7 +62,12 @@ namespace SHADE
 
   const SHVec3& SHTransformComponent::GetWorldRotation() const noexcept
   {
-    return world.rotation;
+    return worldRotation;
+  }
+
+  const SHQuaternion& SHTransformComponent::GetWorldOrientation() const noexcept
+  {
+    return world.orientation;
   }
 
   const SHVec3& SHTransformComponent::GetWorldScale() const noexcept
@@ -91,16 +103,28 @@ namespace SHADE
   void SHTransformComponent::SetLocalRotation(const SHVec3& newLocalRotation) noexcept
   {
     dirty = true;
-    local.rotation = newLocalRotation;
+
+    localRotation = newLocalRotation;
+    updateQueue.push({ UpdateCommandType::LOCAL_ROTATION, newLocalRotation });
   }
 
   void SHTransformComponent::SetLocalRotation(float pitch, float yaw, float roll) noexcept
   {
     dirty = true;
 
-    local.rotation.x = pitch;
-    local.rotation.y = yaw;
-    local.rotation.z = roll;
+    localRotation.x = pitch;
+    localRotation.y = yaw;
+    localRotation.z = roll;
+
+    updateQueue.push({ UpdateCommandType::LOCAL_ROTATION, SHVec3{pitch, yaw, roll} });
+  }
+
+  void SHTransformComponent::SetLocalOrientation(const SHQuaternion& newLocalOrientation) noexcept
+  {
+    dirty = true;
+
+    local.orientation = newLocalOrientation;
+    updateQueue.push({ UpdateCommandType::LOCAL_ORIENTATION, newLocalOrientation });
   }
 
   void SHTransformComponent::SetLocalScale(const SHVec3& newLocalScale) noexcept
@@ -121,7 +145,7 @@ namespace SHADE
   {
     dirty = true;
 
-    world.rotation = newWorldRotation;
+    worldRotation = newWorldRotation;
     updateQueue.push({ UpdateCommandType::WORLD_ROTATION, newWorldRotation });
   }
 
@@ -129,13 +153,21 @@ namespace SHADE
   {
     dirty = true;
 
-    world.rotation.x = pitch;
-    world.rotation.y = yaw;
-    world.rotation.z = roll;
+    worldRotation.x = pitch;
+    worldRotation.y = yaw;
+    worldRotation.z = roll;
 
     updateQueue.push({ UpdateCommandType::WORLD_ROTATION, SHVec3{ pitch, yaw, roll} });
   }
 
+  void SHTransformComponent::SetWorldOrientation(const SHQuaternion& newWorldOrientation) noexcept
+  {
+    dirty = true;
+
+    world.orientation = newWorldOrientation;
+    updateQueue.push({ UpdateCommandType::WORLD_ORIENTATION, newWorldOrientation });
+  }
+
   void SHTransformComponent::SetWorldScale(const SHVec3& newWorldScale) noexcept
   {
     dirty = true;
@@ -153,6 +185,6 @@ RTTR_REGISTRATION
 
   registration::class_<SHTransformComponent>("Transform Component")
     .property("Translate" , &SHTransformComponent::GetLocalPosition , &SHTransformComponent::SetLocalPosition                                       )
-    .property("Rotate"    , &SHTransformComponent::GetLocalRotation , select_overload<void(SHVec3 const&)>(&SHTransformComponent::SetLocalRotation) )
+    .property("Rotate"    , &SHTransformComponent::GetLocalRotation , select_overload<void(const SHVec3&)>(&SHTransformComponent::SetLocalRotation) )
     .property("Scale"     , &SHTransformComponent::GetLocalScale    , &SHTransformComponent::SetLocalScale                                          );
 }
\ No newline at end of file
diff --git a/SHADE_Engine/src/Math/Transform/SHTransformComponent.h b/SHADE_Engine/src/Math/Transform/SHTransformComponent.h
index ad355694..2fe67bdd 100644
--- a/SHADE_Engine/src/Math/Transform/SHTransformComponent.h
+++ b/SHADE_Engine/src/Math/Transform/SHTransformComponent.h
@@ -56,42 +56,52 @@ namespace SHADE
     /* Getter Functions                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    [[nodiscard]] bool                HasChanged        ()  const noexcept;
+    [[nodiscard]] bool                HasChanged          ()  const noexcept;
 
-    [[nodiscard]] const SHVec3&       GetLocalPosition  ()  const noexcept;
-    [[nodiscard]] const SHVec3&       GetLocalRotation  ()  const noexcept;
-    [[nodiscard]] const SHVec3&       GetLocalScale     ()  const noexcept;
-    [[nodiscard]] const SHVec3&       GetWorldPosition  ()  const noexcept;
-    [[nodiscard]] const SHVec3&       GetWorldRotation  ()  const noexcept;
-    [[nodiscard]] const SHVec3&       GetWorldScale     ()  const noexcept;
+    [[nodiscard]] const SHVec3&       GetLocalPosition    ()  const noexcept;
+    [[nodiscard]] const SHVec3&       GetLocalRotation    ()  const noexcept;
+    [[nodiscard]] const SHQuaternion& GetLocalOrientation ()  const noexcept;
+    [[nodiscard]] const SHVec3&       GetLocalScale       ()  const noexcept;
+    [[nodiscard]] const SHVec3&       GetWorldPosition    ()  const noexcept;
+    [[nodiscard]] const SHVec3&       GetWorldRotation    ()  const noexcept;
+    [[nodiscard]] const SHQuaternion& GetWorldOrientation ()  const noexcept;
+    [[nodiscard]] const SHVec3&       GetWorldScale       ()  const noexcept;
 
-    [[nodiscard]] const SHMatrix&     GetLocalToWorld   ()  const noexcept;
-    [[nodiscard]] SHMatrix            GetWorldToLocal   ()  const noexcept;
+    [[nodiscard]] const SHMatrix&     GetLocalToWorld     ()  const noexcept;
+    [[nodiscard]] SHMatrix            GetWorldToLocal     ()  const noexcept;
 
-    [[nodiscard]] const SHMatrix&     GetTRS            ()  const noexcept;
+    [[nodiscard]] const SHMatrix&     GetTRS              ()  const noexcept;
 
     /*---------------------------------------------------------------------------------*/
     /* Setter Functions                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    void  SetLocalPosition  (const SHVec3& newLocalPosition)      noexcept;
-    void  SetLocalRotation  (const SHVec3& newLocalRotation)      noexcept;
-    void  SetLocalRotation  (float pitch, float yaw, float roll)  noexcept;
-    void  SetLocalScale     (const SHVec3& newLocalScale)         noexcept;
-    void  SetWorldPosition  (const SHVec3& newWorldPosition)      noexcept;
-    void  SetWorldRotation  (const SHVec3& newWorldRotation)      noexcept;
-    void  SetWorldRotation  (float pitch, float yaw, float roll)  noexcept;
-    void  SetWorldScale     (const SHVec3& newWorldScale)         noexcept;
+    void  SetLocalPosition    (const SHVec3& newLocalPosition)          noexcept;
+    void  SetLocalRotation    (const SHVec3& newLocalRotation)          noexcept;
+    void  SetLocalRotation    (float pitch, float yaw, float roll)      noexcept;
+    void  SetLocalOrientation (const SHQuaternion& newLocalOrientation) noexcept;
+    void  SetLocalScale       (const SHVec3& newLocalScale)             noexcept;
+    void  SetWorldPosition    (const SHVec3& newWorldPosition)          noexcept;
+    void  SetWorldRotation    (const SHVec3& newWorldRotation)          noexcept;
+    void  SetWorldRotation    (float pitch, float yaw, float roll)      noexcept;
+    void  SetWorldOrientation (const SHQuaternion& newWorldOrientation) noexcept;
+    void  SetWorldScale       (const SHVec3& newWorldScale)             noexcept;
 
   private:
     /*---------------------------------------------------------------------------------*/
     /* Type Definitions                                                                */
     /*---------------------------------------------------------------------------------*/
 
+    // Differentiate between rotation and orientation for setters
+    // Setting a quaternion directly is different from using euler angle rotations.
+
     enum class UpdateCommandType
     {
-      WORLD_POSITION
+      LOCAL_ROTATION
+    , LOCAL_ORIENTATION
+    , WORLD_POSITION
     , WORLD_ROTATION
+    , WORLD_ORIENTATION
     , WORLD_SCALE
     };
 
@@ -103,7 +113,7 @@ namespace SHADE
       /*-------------------------------------------------------------------------------*/
 
       UpdateCommandType type;
-      SHVec3            data;
+      SHVec4            data;
     };
 
     using UpdateQueue = std::queue<UpdateCommand>;
@@ -114,6 +124,12 @@ namespace SHADE
 
     bool        dirty;
 
+    // We store euler angle rotations separately to interface with transform quaternions.
+    // Reading quaternions are unreliable.
+
+    SHVec3      localRotation;    // Stored in Radians
+    SHVec3      worldRotation;    // Stored in Radians
+
     SHTransform local;    // Local TRS holds Local To World Transform
     SHTransform world;
 
diff --git a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp
index 6b05e323..5a540cd4 100644
--- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp
+++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp
@@ -17,7 +17,8 @@
 #include "Scene/SHSceneManager.h"
 #include "ECS_Base/Managers/SHComponentManager.h"
 #include "ECS_Base/Managers/SHEntityManager.h"
-#include "Tools/SHException.h"
+#include "ECS_Base/Managers/SHSystemManager.h"
+#include "Math/SHMathHelpers.h"
 
 namespace SHADE
 {
@@ -29,8 +30,12 @@ namespace SHADE
   /* Constructors & Destructor Definitions                                             */
   /*-----------------------------------------------------------------------------------*/
 
-  SHTransformSystem::TransformUpdateRoutine::TransformUpdateRoutine()
-  : SHSystemRoutine { "Transform Update", true }
+  SHTransformSystem::TransformPostLogicUpdate::TransformPostLogicUpdate()
+  : SHSystemRoutine { "Transform Post-Logic Update", true }
+  {}
+
+  SHTransformSystem::TransformPostPhysicsUpdate::TransformPostPhysicsUpdate()
+  : SHSystemRoutine { "Transform Post-Physics Update", false }
   {}
 
 
@@ -38,16 +43,27 @@ namespace SHADE
   /* Public Function Member Definitions                                                */
   /*-----------------------------------------------------------------------------------*/
 
-  void SHTransformSystem::TransformUpdateRoutine::Execute(double) noexcept
+  void SHTransformSystem::TransformPostLogicUpdate::Execute(double) noexcept
   {
     // Get the current scene graph to traverse and update
     const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
-    UpdateEntity(SCENE_GRAPH.GetRoot());
+
+    // TODO(Diren): Consider how to clear dirty in pause / stop mode and update physics, but do not clear in play mode.
+    UpdateEntity(SCENE_GRAPH.GetRoot(), false);
+  }
+
+  void SHTransformSystem::TransformPostPhysicsUpdate::Execute(double) noexcept
+  {
+    // Get the current scene graph to traverse and update
+    const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
+    UpdateEntity(SCENE_GRAPH.GetRoot(), true);
   }
 
   void SHTransformSystem::Init()
   {
-
+    std::shared_ptr thisReceiver { std::make_shared<SHEventReceiverSpec<SHTransformSystem>>(this, &SHTransformSystem::ChangeParent) };
+    ReceiverPtr receiver = std::dynamic_pointer_cast<SHEventReceiver>(thisReceiver);
+    SHEventManager::SubscribeTo(SH_SCENEGRAPH_CHANGE_PARENT_EVENT, receiver);
   }
 
   void SHTransformSystem::Exit()
@@ -59,7 +75,97 @@ namespace SHADE
   /* Private Function Member Definitions                                               */
   /*-----------------------------------------------------------------------------------*/
 
-  void SHTransformSystem::UpdateEntity(const SHSceneNode* node)
+  SHEventHandle SHTransformSystem::ChangeParent(SHEventPtr changeParentEvent)
+  {
+    const auto& eventData = reinterpret_cast<const SHEventSpec<SHSceneGraphChangeParentEvent>*>(changeParentEvent.get());
+
+    auto* node = eventData->data->node;
+    auto* tf = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
+
+    // Recompute local transform and store localToWorld Matrix
+    SHMatrix localToWorld = SHMatrix::Identity; 
+    SHMatrix worldToLocal = SHMatrix::Identity;
+
+    auto* newParent = eventData->data->newParent;
+    const auto* PARENT_TF = SHComponentManager::GetComponent_s<SHTransformComponent>(newParent->GetEntityID());
+    if (PARENT_TF != nullptr) // Not the root
+    {
+      localToWorld = PARENT_TF->GetTRS();
+      worldToLocal = SHMatrix::Inverse(localToWorld);
+    }
+
+    // Maintain World Transform and recompute Local Transform
+
+    // Compute Local Position
+    tf->local.position = SHVec3::Transform(tf->world.position, worldToLocal);
+
+          
+    tf->localRotation = tf->worldRotation;
+    tf->local.scale   = tf->world.scale;
+
+    if (PARENT_TF != nullptr)
+    {
+      // Compute Local Rotation
+      tf->localRotation -= PARENT_TF->GetLocalRotation();
+
+      // Compute Local Scale
+      tf->local.scale /= PARENT_TF->GetLocalScale();
+    }
+
+    tf->local.trs = localToWorld;
+
+    // Propagate maintaining world transform down the branch
+    UpdateChildrenLocalTransforms(node);
+    return eventData->handle;
+  }
+
+  void SHTransformSystem::UpdateChildrenLocalTransforms(SHSceneNode* node)
+  {
+    // Structure is similar to update entity, albeit without a queue to do being a forced update
+    for (const auto* child : node->GetChildren())
+    {
+      if (auto* childTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(child->GetEntityID()); childTransform)
+      {
+        const bool IS_NODE_ACTIVE = child->IsActive();
+        if (IS_NODE_ACTIVE && childTransform->isActive)
+        {
+          // Recompute local transform and store localToWorld Matrix
+          SHMatrix localToWorld = SHMatrix::Identity; 
+          SHMatrix worldToLocal = SHMatrix::Identity;
+
+          const auto* parent = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
+
+          if (parent != nullptr) // Not the root
+          {
+            localToWorld = parent->GetTRS();
+            worldToLocal = SHMatrix::Inverse(localToWorld);
+          }
+
+          // Maintain World Transform and recompute Local Transform
+
+          // Compute Local Position
+          childTransform->local.position = SHVec3::Transform(childTransform->world.position, worldToLocal);
+
+          
+          childTransform->localRotation = childTransform->worldRotation;
+          childTransform->local.scale   = childTransform->world.scale;
+
+          if (parent)
+          {
+            // Compute Local Rotation
+            childTransform->localRotation -= parent->GetLocalRotation();
+
+            // Compute Local Scale
+            childTransform->local.scale /= parent->GetLocalScale();
+          }
+
+          childTransform->local.trs = localToWorld;
+        }
+      }
+    }
+  }
+
+  void SHTransformSystem::UpdateEntity(const SHSceneNode* node, bool clearDirtyFlag)
   {
     const auto* NODE_TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
     const bool HAS_PARENT_CHANGED = NODE_TRANSFORM && NODE_TRANSFORM->dirty;
@@ -74,14 +180,17 @@ namespace SHADE
         if (IS_NODE_ACTIVE && childTransform->isActive)
         {
           if (childTransform->dirty || HAS_PARENT_CHANGED)
+          {
             UpdateTransform(*childTransform, NODE_TRANSFORM);
+            childTransform->dirty = true;
+          }
         }
       }
 
-      UpdateEntity(child);
+      UpdateEntity(child, clearDirtyFlag);
 
       // Clear dirty flag after all children are updated
-      if (childTransform)
+      if (childTransform && clearDirtyFlag)
         childTransform->dirty = false;
     }
   }
@@ -91,6 +200,8 @@ namespace SHADE
     SHMatrix localToWorld = SHMatrix::Identity;
     SHMatrix worldToLocal = SHMatrix::Identity;
 
+    bool convertRotation = true;
+
     if (parent)
     {
       localToWorld = parent->GetTRS();
@@ -103,22 +214,44 @@ namespace SHADE
 
       switch (UPDATE_COMMAND.type)
       {
+        case SHTransformComponent::UpdateCommandType::LOCAL_ROTATION:
+        {
+          convertRotation = true;
+          break;
+        }
+        case SHTransformComponent::UpdateCommandType::LOCAL_ORIENTATION:
+        {
+          convertRotation = false;
+          break;
+        }
         case SHTransformComponent::UpdateCommandType::WORLD_POSITION:
         {
-          tf.local.position = SHVec3::Transform(UPDATE_COMMAND.data, worldToLocal);
+          tf.local.position = SHVec3::Transform(UPDATE_COMMAND.data.ToVec3(), worldToLocal);
           break;
         }
         case SHTransformComponent::UpdateCommandType::WORLD_ROTATION:
         {
-          tf.local.rotation = tf.world.rotation;
+          tf.localRotation = UPDATE_COMMAND.data.ToVec3();
           if (parent)
-            tf.local.rotation -= parent->GetLocalRotation();
+            tf.localRotation -= parent->GetLocalRotation();
+
+          convertRotation = true;
+
+          break;
+        }
+        case SHTransformComponent::UpdateCommandType::WORLD_ORIENTATION:
+        {
+          tf.local.orientation = UPDATE_COMMAND.data;
+          if (parent)
+            tf.local.orientation /= parent->GetLocalOrientation();
+
+          convertRotation = false;
 
           break;
         }
         case SHTransformComponent::UpdateCommandType::WORLD_SCALE:
         {
-          tf.local.scale = tf.world.scale;
+          tf.local.scale = UPDATE_COMMAND.data.ToVec3();
           if (parent)
             tf.local.scale /= parent->GetLocalScale();
 
@@ -133,15 +266,38 @@ namespace SHADE
 
     tf.local.trs = localToWorld;
 
+    // Compute world transforms
     tf.world.position = SHVec3::Transform(tf.local.position, localToWorld);
-    tf.world.rotation = tf.local.rotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero);
     tf.world.scale    = tf.local.scale * (parent ? parent->GetLocalScale() : SHVec3::One);
 
-    tf.world.ComputeTRS();
+    
 
-    // Transpose TRS to column major
-    //tf.local.trs.Transpose();
-    //tf.world.trs.Transpose();
+    if (convertRotation)
+    {
+      tf.worldRotation  = tf.localRotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero);
+
+      // Set the orientation
+      // Wrap rotations between -360 and 360 and convert to radians
+      SHVec3 worldRotRad, localRotRad;
+      for (size_t i = 0; i < SHVec3::SIZE; ++i)
+      {
+        worldRotRad[i] = SHMath::Wrap(tf.worldRotation[i], -SHMath::TWO_PI, SHMath::TWO_PI);
+        localRotRad[i] = SHMath::Wrap(tf.localRotation[i], -SHMath::TWO_PI, SHMath::TWO_PI);
+      }
+
+      tf.world.orientation = SHQuaternion::FromEuler(worldRotRad);
+      tf.local.orientation = SHQuaternion::FromEuler(localRotRad);
+    }
+    else
+    {
+      tf.world.orientation = (parent ? parent->GetLocalOrientation() : SHQuaternion::Identity) * tf.local.orientation;
+
+      // Set the euler angle rotations
+      tf.worldRotation = tf.world.orientation.ToEuler();
+      tf.localRotation = tf.local.orientation.ToEuler();
+    }
+
+    tf.world.ComputeTRS();
   }
 
 } // namespace SHADE
\ No newline at end of file
diff --git a/SHADE_Engine/src/Math/Transform/SHTransformSystem.h b/SHADE_Engine/src/Math/Transform/SHTransformSystem.h
index 02c3b6c6..e63969ce 100644
--- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.h
+++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.h
@@ -45,25 +45,52 @@ namespace SHADE
     /* System Routines                                                                 */
     /*---------------------------------------------------------------------------------*/
 
-    class SH_API TransformUpdateRoutine final: public SHSystemRoutine
+    class SH_API TransformPostLogicUpdate final: public SHSystemRoutine
     {
     public:
       /*-------------------------------------------------------------------------------*/
       /* Constructors & Destructor                                                     */
       /*-------------------------------------------------------------------------------*/
 
-      TransformUpdateRoutine   ();
-      ~TransformUpdateRoutine  () = default;
+      TransformPostLogicUpdate   ();
+      ~TransformPostLogicUpdate  () = default;
 
-      TransformUpdateRoutine   (const TransformUpdateRoutine&)  = delete;
-      TransformUpdateRoutine   (TransformUpdateRoutine&&)       = delete;
+      TransformPostLogicUpdate   (const TransformPostLogicUpdate&)  = delete;
+      TransformPostLogicUpdate   (TransformPostLogicUpdate&&)       = delete;
 
       /*-------------------------------------------------------------------------------*/
       /* Operator Overloads                                                            */
       /*-------------------------------------------------------------------------------*/
 
-      TransformUpdateRoutine& operator= (const TransformUpdateRoutine&) = delete;
-      TransformUpdateRoutine& operator= (TransformUpdateRoutine&&)      = delete;
+      TransformPostLogicUpdate& operator= (const TransformPostLogicUpdate&) = delete;
+      TransformPostLogicUpdate& operator= (TransformPostLogicUpdate&&)      = delete;
+
+      /*-------------------------------------------------------------------------------*/
+      /* Function Members                                                              */
+      /*-------------------------------------------------------------------------------*/
+
+      void Execute(double dt) noexcept override;
+    };
+
+    class SH_API TransformPostPhysicsUpdate final: public SHSystemRoutine
+    {
+    public:
+      /*-------------------------------------------------------------------------------*/
+      /* Constructors & Destructor                                                     */
+      /*-------------------------------------------------------------------------------*/
+
+      TransformPostPhysicsUpdate   ();
+      ~TransformPostPhysicsUpdate  () = default;
+
+      TransformPostPhysicsUpdate   (const TransformPostPhysicsUpdate&)  = delete;
+      TransformPostPhysicsUpdate   (TransformPostPhysicsUpdate&&)       = delete;
+
+      /*-------------------------------------------------------------------------------*/
+      /* Operator Overloads                                                            */
+      /*-------------------------------------------------------------------------------*/
+
+      TransformPostPhysicsUpdate& operator= (const TransformPostPhysicsUpdate&) = delete;
+      TransformPostPhysicsUpdate& operator= (TransformPostPhysicsUpdate&&)      = delete;
 
       /*-------------------------------------------------------------------------------*/
       /* Function Members                                                              */
@@ -84,8 +111,11 @@ namespace SHADE
     /* Function Members                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    static void UpdateEntity   (const SHSceneNode* node);
-    static void UpdateTransform(SHTransformComponent& tf, const SHTransformComponent* parent = nullptr);
+    SHEventHandle ChangeParent                  (SHEventPtr changeParentEvent);
+    static void   UpdateChildrenLocalTransforms (SHSceneNode* node);
+
+    static void   UpdateEntity                  (const SHSceneNode* node, bool clearDirtyFlag);
+    static void   UpdateTransform               (SHTransformComponent& tf, const SHTransformComponent* parent = nullptr);
   };
 
 
diff --git a/SHADE_Engine/src/Math/Vector/SHVec4.cpp b/SHADE_Engine/src/Math/Vector/SHVec4.cpp
index bcf2ef97..9857818a 100644
--- a/SHADE_Engine/src/Math/Vector/SHVec4.cpp
+++ b/SHADE_Engine/src/Math/Vector/SHVec4.cpp
@@ -38,6 +38,10 @@ namespace SHADE
   : XMFLOAT4( 0.0f, 0.0f, 0.0f, 0.0f )
   {}
 
+  SHVec4::SHVec4(const SHVec3& vec3) noexcept
+  : XMFLOAT4( vec3.x, vec3.y, vec3.z, 1.0f )
+  {}
+
   SHVec4::SHVec4(const XMFLOAT4& xmfloat4) noexcept
   : XMFLOAT4( xmfloat4.x, xmfloat4.y, xmfloat4.z, xmfloat4.w )
   {}
@@ -271,6 +275,11 @@ namespace SHADE
     return result;
   }
 
+  SHVec3 SHVec4::ToVec3() const noexcept
+  {
+    return SHVec3{ x, y, z };
+  }
+
   /*-----------------------------------------------------------------------------------*/
   /* Static Function Member Definitions                                                */
   /*-----------------------------------------------------------------------------------*/
diff --git a/SHADE_Engine/src/Math/Vector/SHVec4.h b/SHADE_Engine/src/Math/Vector/SHVec4.h
index 911a714e..ce341bed 100644
--- a/SHADE_Engine/src/Math/Vector/SHVec4.h
+++ b/SHADE_Engine/src/Math/Vector/SHVec4.h
@@ -16,6 +16,7 @@
 
 // Project Headers
 #include "SH_API.h"
+#include "SHVec3.h"
 
 namespace SHADE
 {
@@ -53,6 +54,7 @@ namespace SHADE
     ~SHVec4 ()                  = default;
 
     SHVec4  ()                                    noexcept;
+    SHVec4  (const SHVec3& vec3)                  noexcept;
     SHVec4  (const XMFLOAT4& xmfloat4)            noexcept;
     SHVec4  (float x, float y, float z, float w)  noexcept;
 
@@ -102,16 +104,18 @@ namespace SHADE
     [[nodiscard]] float         Dot3D           (const SHVec4& rhs)                   const noexcept;
     [[nodiscard]] SHVec4        Cross3D         (const SHVec4& rhs)                   const noexcept;
     [[nodiscard]] SHVec4        Cross           (const SHVec4& v1, const SHVec4& v2)  const noexcept;
+
+    [[nodiscard]] SHVec3        ToVec3          ()                                    const noexcept;
   
     /*---------------------------------------------------------------------------------*/
     /* Static Function Members                                                         */
     /*---------------------------------------------------------------------------------*/
 
-    [[nodiscard]] static SHVec4 Normalise         (const SHVec4& v)                                                              noexcept;
-    [[nodiscard]] static SHVec4 Normalise3D       (const SHVec4& v)                                                              noexcept;
-    [[nodiscard]] static SHVec4 Abs               (const SHVec4& v)                                                              noexcept;
-    [[nodiscard]] static SHVec4 Min               (const std::initializer_list<SHVec4>& vs)                                      noexcept;
-    [[nodiscard]] static SHVec4 Max               (const std::initializer_list<SHVec4>& vs)                                      noexcept;
+    [[nodiscard]] static SHVec4 Normalise         (const SHVec4& v)                                                                 noexcept;
+    [[nodiscard]] static SHVec4 Normalise3D       (const SHVec4& v)                                                                 noexcept;
+    [[nodiscard]] static SHVec4 Abs               (const SHVec4& v)                                                                 noexcept;
+    [[nodiscard]] static SHVec4 Min               (const std::initializer_list<SHVec4>& vs)                                         noexcept;
+    [[nodiscard]] static SHVec4 Max               (const std::initializer_list<SHVec4>& vs)                                         noexcept;
     [[nodiscard]] static SHVec4 Clamp             (const SHVec4& v, const SHVec4& vMin, const SHVec4& vMax)                         noexcept;
     [[nodiscard]] static SHVec4 Lerp              (const SHVec4& a, const SHVec4& b, float t)                                       noexcept;
     [[nodiscard]] static SHVec4 ClampedLerp       (const SHVec4& a, const SHVec4& b, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
diff --git a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp
index 36f7c57e..f9b476ef 100644
--- a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp
+++ b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp
@@ -140,12 +140,12 @@ namespace SHADE
     isRigidBody  = true;
 
     rb->position    = tf->GetWorldPosition();
-    rb->orientation = tf->GetWorldRotation();
+    rb->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation());
 
     if (hasColliders)
     {
       c->position    = tf->GetWorldPosition();
-      c->orientation = tf->GetWorldRotation();
+      c->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation());
       // Get array of colliders and add them back into the rigidbody
       for (auto& collider : c->colliders | std::views::keys)
         AddCollider(&collider);
@@ -160,7 +160,7 @@ namespace SHADE
     hasColliders = true;
 
     c->position    = tf->GetWorldPosition();
-    c->orientation = tf->GetWorldRotation();
+    c->orientation = SHQuaternion::FromEuler(tf->GetWorldRotation());
 
     for (auto& collider : c->colliders | std::views::keys)
       AddCollider(&collider);
diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp
index 7dc6c44e..a1994ad2 100644
--- a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp
+++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp
@@ -16,6 +16,7 @@
 // Project Headers
 #include "ECS_Base/Managers/SHComponentManager.h"
 #include "ECS_Base/Managers/SHEntityManager.h"
+#include "Math/SHMathHelpers.h"
 #include "Scene/SHSceneManager.h"
 #include "Math/Transform/SHTransformComponent.h"
 
@@ -315,7 +316,7 @@ namespace SHADE
       if (TF->HasChanged())
       {
         physicsObject.SetPosition(TF->GetWorldPosition());
-        physicsObject.SetRotation(TF->GetWorldRotation());
+        physicsObject.SetOrientation(TF->GetWorldOrientation());
       }
     }
   }
@@ -492,8 +493,7 @@ namespace SHADE
       // Convert RP3D Transform to SHADE
       auto* tfComponent = SHComponentManager::GetComponent<SHTransformComponent>(entityID);
       tfComponent->SetWorldPosition(rp3dPos);
-      tfComponent->SetWorldRotation(SHQuaternion{ rp3dRot }.ToEuler());
-
+      tfComponent->SetWorldOrientation(SHQuaternion{ rp3dRot });
 
       // Cache transforms
       physicsObject.prevTransform = CURRENT_TF;
diff --git a/SHADE_Engine/src/Resource/SHResourceManager.hpp b/SHADE_Engine/src/Resource/SHResourceManager.hpp
index 54ced715..cff4e84b 100644
--- a/SHADE_Engine/src/Resource/SHResourceManager.hpp
+++ b/SHADE_Engine/src/Resource/SHResourceManager.hpp
@@ -15,6 +15,7 @@ of DigiPen Institute of Technology is prohibited.
 #include "SHResourceManager.h"
 // Project Includes
 #include "Assets/SHAssetManager.h"
+#include "Assets/Asset Types/SHAssetIncludes.h"
 #include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
 #include "ECS_Base/Managers/SHSystemManager.h"
 #include "Tools/SHLog.h"
@@ -48,7 +49,7 @@ namespace SHADE
         throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed.");
 
       // Load
-      const SHMeshAsset* assetData = SHAssetManager::GetMesh(assetId);
+      const SHMeshAsset* assetData = SHAssetManager::GetData<SHMeshAsset>(assetId);
       if (assetData == nullptr)
       {
         SHLog::Warning("[SHResourceManager] Attempted to load an asset with an invalid Asset ID.");
@@ -80,7 +81,7 @@ namespace SHADE
         throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed.");
 
       // Load
-      const SHTextureAsset* assetData = SHAssetManager::GetTexture(assetId);
+      const SHTextureAsset* assetData = SHAssetManager::GetData<SHTextureAsset>(assetId);
       if (assetData == nullptr)
       {
         SHLog::Warning("[SHResourceManager] Attempted to load an asset with an invalid Asset ID.");
@@ -133,7 +134,7 @@ namespace SHADE
   /* Query Functions                                                                   */
   /*-----------------------------------------------------------------------------------*/
   template<typename T>
-  static std::optional<AssetID> SHResourceManager::GetAssetID(Handle<T> handle)
+  std::optional<AssetID> SHResourceManager::GetAssetID(Handle<T> handle)
   {
     const Handle GENERIC_HANDLE = Handle(handle);
     auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap<T>();
diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.cpp b/SHADE_Engine/src/Scene/SHSceneGraph.cpp
index bbbdb7e4..950fd6a0 100644
--- a/SHADE_Engine/src/Scene/SHSceneGraph.cpp
+++ b/SHADE_Engine/src/Scene/SHSceneGraph.cpp
@@ -15,6 +15,7 @@
 
 // Project Headers
 #include "ECS_Base/Managers/SHEntityManager.h"
+#include "Events/SHEventManager.hpp"
 #include "Tools/SHLogger.h"
 #include "Tools/SHException.h"
 
@@ -317,6 +318,11 @@ namespace SHADE
     if (parentNode == nullptr)
     {
       SHLOG_WARNING("Removing Entity {}'s parent", entityID)
+
+      if (parent)
+        parent->RemoveChild(this);
+
+      return;
     }
 
     // Handle self assignment
@@ -359,10 +365,19 @@ namespace SHADE
     }
     ////////////////////////////////////////
 
+    const SHSceneGraphChangeParentEvent EVENT_DATA
+    {
+      .node       = NODE_ITER->second
+    , .oldParent  = NODE_ITER->second->GetParent()
+    , .newParent  = parent ? parent : root
+    };
+
     if (parent == nullptr)
       parent = root;
 
     NODE_ITER->second->SetParent(parent);
+
+    SHEventManager::BroadcastEvent<SHSceneGraphChangeParentEvent>(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT);
   }
 
   void SHSceneGraph::SetParent(EntityID entityID, EntityID parent) const noexcept
@@ -396,8 +411,17 @@ namespace SHADE
     }
     ////////////////////////////////////////
 
+    const SHSceneGraphChangeParentEvent EVENT_DATA
+    {
+      .node       = NODE_ITER->second
+    , .oldParent  = NODE_ITER->second->GetParent()
+    , .newParent  = PARENT_ITER->second
+    };
+
     SHSceneNode* currentNode = NODE_ITER->second;
     currentNode->SetParent(PARENT_ITER->second);
+
+    SHEventManager::BroadcastEvent<SHSceneGraphChangeParentEvent>(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT);
   }
 
   /*-----------------------------------------------------------------------------------*/
@@ -558,7 +582,7 @@ namespace SHADE
       ReleaseNode(node);
   }
 
-  void SHSceneGraph::Traverse (const UnaryPredicate& predicate) const
+  void SHSceneGraph::Traverse (const UnaryFunction& predicate) const
   {
     TraverseAndInvokePredicate(root, predicate);
   }
@@ -597,7 +621,7 @@ namespace SHADE
     delete node;
   }
 
-  void SHSceneGraph::TraverseAndInvokePredicate(const SHSceneNode* node, const UnaryPredicate& predicate)
+  void SHSceneGraph::TraverseAndInvokePredicate(const SHSceneNode* node, const UnaryFunction& predicate)
   {
     for (auto* child : node->children)
     { 
diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.h b/SHADE_Engine/src/Scene/SHSceneGraph.h
index 3f3ebf92..a4cf45eb 100644
--- a/SHADE_Engine/src/Scene/SHSceneGraph.h
+++ b/SHADE_Engine/src/Scene/SHSceneGraph.h
@@ -97,9 +97,8 @@ namespace SHADE
     /* Type Definitions                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    using EntityNodeMap       = std::unordered_map<EntityID, SHSceneNode*>;
-
-    using UnaryPredicate      = std::function<void(SHSceneNode*)>;
+    using EntityNodeMap = std::unordered_map<EntityID, SHSceneNode*>;
+    using UnaryFunction = std::function<void(SHSceneNode*)>;
     
 
     /*---------------------------------------------------------------------------------*/
@@ -143,8 +142,7 @@ namespace SHADE
     bool          RemoveNode  (SHSceneNode* nodeToRemove)                         noexcept;
     void          Reset       ()                                                  noexcept;
 
-    void          Traverse    (const UnaryPredicate& predicate)                   const;
-    
+    void          Traverse    (const UnaryFunction& predicate)                    const;
 
   private:
     /*---------------------------------------------------------------------------------*/
@@ -160,8 +158,14 @@ namespace SHADE
 
     SHSceneNode*  AllocateNode                (EntityID entityID);
     void          ReleaseNode                 (SHSceneNode* node) noexcept;
-    static void   TraverseAndInvokePredicate  (const SHSceneNode* node, const UnaryPredicate& predicate);
+    static void   TraverseAndInvokePredicate  (const SHSceneNode* node, const UnaryFunction& predicate);
   };
 
+  struct SHSceneGraphChangeParentEvent
+  {
+    SHSceneNode* node;
+    SHSceneNode* oldParent;
+    SHSceneNode* newParent;
+  };
 
 } // namespace SHADE
\ No newline at end of file
diff --git a/SHADE_Managed/src/Components/Transform.cxx b/SHADE_Managed/src/Components/Transform.cxx
index 0f0716dc..98f0da4f 100644
--- a/SHADE_Managed/src/Components/Transform.cxx
+++ b/SHADE_Managed/src/Components/Transform.cxx
@@ -29,13 +29,21 @@ namespace SHADE
     {
         GetNativeComponent()->SetLocalPosition(Convert::ToNative(val));
     }
-    Vector3 Transform::LocalRotation::get()
+    Quaternion Transform::LocalRotation::get()
     {
-        return Convert::ToCLI(GetNativeComponent()->GetLocalRotation());
+        return Convert::ToCLI(GetNativeComponent()->GetLocalOrientation());
     }
-    void Transform::LocalRotation::set(Vector3 val)
+    void Transform::LocalRotation::set(Quaternion val)
     {
-        GetNativeComponent()->SetLocalRotation(Convert::ToNative(val));
+        GetNativeComponent()->SetLocalOrientation(Convert::ToNative(val));
+    }
+    Vector3 Transform::LocalEulerAngles::get()
+    {
+      return Convert::ToCLI(GetNativeComponent()->GetLocalRotation());
+    }
+    void Transform::LocalEulerAngles::set(Vector3 val)
+    {
+      GetNativeComponent()->SetLocalRotation(Convert::ToNative(val));
     }
     Vector3 Transform::LocalScale::get()
     {
@@ -54,13 +62,21 @@ namespace SHADE
     {
         GetNativeComponent()->SetWorldPosition(Convert::ToNative(val));
     }
-    Vector3 Transform::GlobalRotation::get()
+    Quaternion Transform::GlobalRotation::get()
     {
-        return Convert::ToCLI(GetNativeComponent()->GetWorldRotation());
+        return Convert::ToCLI(GetNativeComponent()->GetLocalOrientation());
     }
-    void Transform::GlobalRotation::set(Vector3 val)
+    void Transform::GlobalRotation::set(Quaternion val)
     {
-        GetNativeComponent()->SetWorldRotation(Convert::ToNative(val));
+        GetNativeComponent()->SetWorldOrientation(Convert::ToNative(val));
+    }
+    Vector3 Transform::GlobalEulerAngles::get()
+    {
+      return Convert::ToCLI(GetNativeComponent()->GetWorldRotation());
+    }
+    void Transform::GlobalEulerAngles::set(Vector3 val)
+    {
+      GetNativeComponent()->SetWorldRotation(Convert::ToNative(val));
     }
     Vector3 Transform::GlobalScale::get()
     {
diff --git a/SHADE_Managed/src/Components/Transform.hxx b/SHADE_Managed/src/Components/Transform.hxx
index 9efd2927..bbe9fd19 100644
--- a/SHADE_Managed/src/Components/Transform.hxx
+++ b/SHADE_Managed/src/Components/Transform.hxx
@@ -17,14 +17,14 @@ of DigiPen Institute of Technology is prohibited.
 // Project Includes
 #include "Components/Component.hxx"
 #include "Math/Vector3.hxx"
-#include "Utility/Convert.hxx"
+#include "Math/Quaternion.hxx"
 // External Dependencies
 #include "Math/Transform/SHTransformComponent.h"
 
 namespace SHADE
 {
     /// <summary>
-    /// CLR version of the the SHADE Engine's TransformComponent.
+    /// CLR version of the SHADE Engine's TransformComponent.
     /// </summary>
     public ref class Transform : public Component<SHTransformComponent>
     {
@@ -52,9 +52,17 @@ namespace SHADE
             void set(Vector3 val);
         }
         /// <summary>
-        /// Local Z-axis rotation angle stored by this Transform in Radians.
+        /// Local rotation quaternion stored by this Transform.
         /// </summary>
-        property Vector3 LocalRotation
+        property Quaternion LocalRotation
+        {
+            Quaternion get();
+            void set(Quaternion val);
+        }
+        /// <summary>
+        /// Local euler angle rotations stored by this Transform.
+        /// </summary>
+        property Vector3 LocalEulerAngles
         {
             Vector3 get();
             void set(Vector3 val);
@@ -76,16 +84,23 @@ namespace SHADE
             void set(Vector3 val);
         }
         /// <summary>
-        /// Global Z-axis rotation angle stored by this Transform in Radians.
+        /// Global rotation quaternion stored by this Transform.
         /// </summary>
-        property Vector3 GlobalRotation
+        property Quaternion GlobalRotation
+        {
+            Quaternion get();
+            void set(Quaternion val);
+        }
+        /// <summary>
+        /// Global euler angle rotations stored by this Transform.
+        /// </summary>
+        property Vector3 GlobalEulerAngles
         {
             Vector3 get();
             void set(Vector3 val);
         }
         /// <summary>
         /// Global scale stored by this Transform.
-        /// Note that this operation is expensive.
         /// </summary>
         property Vector3 GlobalScale
         {
diff --git a/SHADE_Managed/src/Math/Math.cxx b/SHADE_Managed/src/Math/Math.cxx
index 5ec850a1..fa72e2b6 100644
--- a/SHADE_Managed/src/Math/Math.cxx
+++ b/SHADE_Managed/src/Math/Math.cxx
@@ -21,7 +21,7 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
     /* Utility Functions                                                               */
     /*---------------------------------------------------------------------------------*/
-    double Math::Wrap(double value, double min, double max)
+    float Math::Wrap(float value, float min, float max)
     {
         while (value < min)
         {
@@ -33,24 +33,24 @@ namespace SHADE
         }
         return value;
     }
-    double Math::DegreesToRadians(double degrees)
+    float Math::DegreesToRadians(float degrees)
     {
         return degrees * Deg2Rad;
     }
-    double Math::RadiansToDegrees(double radians)
+    float Math::RadiansToDegrees(float radians)
     {
         return radians * Rad2Deg;
     }
-    double Math::Lerp(double a, double b, double t)
+    float Math::Lerp(float a, float b, float t)
     {
-        return LerpUnclamped(a, b, System::Math::Clamp(t, 0.0, 1.0));
+        return LerpUnclamped(a, b, System::Math::Clamp(t, 0.0f, 1.0f));
     }
-    double Math::LerpUnclamped(double a, double b, double t)
+    float Math::LerpUnclamped(float a, float b, float t)
     {
         return a + t * (b - a);
     }
 
-    double Math::InverseLerp(double a, double b, double value)
+    float Math::InverseLerp(float a, float b, float value)
     {
         return (value - a) / (b - a);
     }
diff --git a/SHADE_Managed/src/Math/Math.hxx b/SHADE_Managed/src/Math/Math.hxx
index 3ddc5149..1578d97c 100644
--- a/SHADE_Managed/src/Math/Math.hxx
+++ b/SHADE_Managed/src/Math/Math.hxx
@@ -27,11 +27,11 @@ namespace SHADE
         /// <summary>
         /// Degrees-to-radians conversion constant
         /// </summary>
-        static constexpr double Deg2Rad = System::Math::PI / 180.0;
+        static constexpr float Deg2Rad = System::Math::PI / 180.0f;
         /// <summary>
         /// Radians-to-degrees conversion constant
         /// </summary>
-        static constexpr double Rad2Deg = 180.0 / System::Math::PI;
+        static constexpr float Rad2Deg = 180.0f / System::Math::PI;
         /// <summary>
         /// Small value used for single precision floating point comparisons.
         /// </summary>
@@ -47,28 +47,28 @@ namespace SHADE
         /// <param name="min">Minimum value to wrap at.</param>
         /// <param name="max">Maximum value to wrap at.</param>
         /// <returns>Wrapped value.</returns>
-        static double Wrap(double value, double min, double max);
+        static float Wrap(float value, float min, float max);
         /// <summary>
         /// Converts an angle from degree representation to radian representation.
         /// </summary>
         /// <param name="degrees">Degree-based angle to convert.</param>
         /// <returns>The specified angle in radians.</returns>
-        static double DegreesToRadians(double degrees);
+        static float DegreesToRadians(float degrees);
         /// <summary>
         /// Converts an angle from radian representation to degree representation.
         /// </summary>
         /// <param name="radians">Radian-based angle to convert.</param>
         /// <returns>The specified angle in degrees.</returns>
-        static double RadiansToDegrees(double radians);
+        static float RadiansToDegrees(float radians);
         /// <summary>
         /// Linearly interpolates between a and b by t. 
         /// The parameter t is clamped to the range [0, 1].
         /// </summary>
         /// <param name="a">The start value.</param>
         /// <param name="b">The end value.</param>
-        /// <param name="t">The interpolation value between the two double.</param>
-        /// <returns>The interpolated double result between the two double values.</returns>
-        static double Lerp(double a, double b, double t);
+        /// <param name="t">The interpolation value between the two float.</param>
+        /// <returns>The interpolated float result between the two float values.</returns>
+        static float Lerp(float a, float b, float t);
         /// <summary>
         /// Linearly interpolates between a and b by t. 
         /// The parameter t is not clamped and a value based on a and b is supported. 
@@ -77,9 +77,9 @@ namespace SHADE
         /// </summary>
         /// <param name="a">The start value.</param>
         /// <param name="b">The end value.</param>
-        /// <param name="t">The interpolation value between the two double.</param>
-        /// <returns>The interpolated double result between the two double values.</returns>
-        static double LerpUnclamped(double a, double b, double t);
+        /// <param name="t">The interpolation value between the two float.</param>
+        /// <returns>The interpolated float result between the two float values.</returns>
+        static float LerpUnclamped(float a, float b, float t);
         /// <summary>
         /// Calculates the linear parameter t that produces the interpolant value within the range [a, b].
         /// </summary>
@@ -87,6 +87,6 @@ namespace SHADE
         /// <param name="b">End value.</param>
         /// <param name="value">Value between start and end.</param>
         /// <returns>Percentage of value between start and end.</returns>
-        static double InverseLerp(double a, double b, double value);
+        static float InverseLerp(float a, float b, float value);
     };
 }
diff --git a/SHADE_Managed/src/Math/Quaternion.cxx b/SHADE_Managed/src/Math/Quaternion.cxx
new file mode 100644
index 00000000..863241ac
--- /dev/null
+++ b/SHADE_Managed/src/Math/Quaternion.cxx
@@ -0,0 +1,170 @@
+/************************************************************************************//*!
+\file           Quaternion.cxx
+\author         Diren D Bharwani, diren.dbharwani, 390002520
+\par            email: diren.dbharwani\@digipen.edu
+\date           Oct 23, 2022
+\brief          Contains the definitions of functions in the Quaternion struct.
+ 
+                Note: This file is written in C++17/CLI.
+
+Copyright (C) 2021 DigiPen Institute of Technology.
+Reproduction or disclosure of this file or its contents without the prior written consent 
+of DigiPen Institute of Technology is prohibited.
+*//*************************************************************************************/
+
+// Precompiled Headers
+#include "SHpch.h"
+// Primary Header
+#include "Quaternion.hxx"
+// External Dependencies
+#include "Math/SHQuaternion.h"
+#include "Math/Vector/SHVec4.h"
+// Project Headers
+#include "Utility/Convert.hxx"
+#include "Math.hxx"
+
+namespace SHADE
+{
+  /*---------------------------------------------------------------------------------*/
+  /* Constructors                                                                    */
+  /*---------------------------------------------------------------------------------*/
+
+  Quaternion::Quaternion(float _x, float _y, float _z, float _w)
+  : x { _x }
+  , y { _y }
+  , z { _z }
+  , w { _w }
+  {}
+
+  /*---------------------------------------------------------------------------------*/
+  /* Usage Functions                                                                 */
+  /*---------------------------------------------------------------------------------*/
+
+  void Quaternion::SetFromToRotation(Vector3 fromDirection, Vector3 toDirection)
+  {
+    const SHQuaternion R = SHQuaternion::FromToRotation(Convert::ToNative(fromDirection), Convert::ToNative(toDirection));
+    *this = Convert::ToCLI(R);
+  }
+
+  void Quaternion::SetLookRotation(Vector3 view, Vector3 up)
+  {
+    const SHQuaternion R = SHQuaternion::LookRotation(Convert::ToNative(view), Convert::ToNative(up));
+    *this = Convert::ToCLI(R);
+  }
+
+  void Quaternion::ToAngleAxis(float^% angle, Vector3^% axis)
+  {
+    const SHVec4 NATIVE_AXIS_ANGLE = Convert::ToNative(*this).GetAxisAngle();
+    axis = Convert::ToCLI(NATIVE_AXIS_ANGLE.ToVec3());
+    angle = NATIVE_AXIS_ANGLE.w;
+  }
+
+  System::String^ Quaternion::ToString()
+  {
+    return ValueType::ToString();
+  }
+
+  /*---------------------------------------------------------------------------------*/
+  /* IEquatable                                                                      */
+  /*---------------------------------------------------------------------------------*/
+
+  bool Quaternion::Equals(Quaternion other)
+  {
+    const float DOT = Dot(*this, other);
+    return fabs(1.0f - DOT) <= Math::Epsilon;
+  }
+
+  /*---------------------------------------------------------------------------------*/
+  /* Object Overrides                                                                */
+  /*---------------------------------------------------------------------------------*/
+
+  bool Quaternion::Equals(Object^ o)
+  {
+    return ValueType::Equals(o);
+  }
+
+  int Quaternion::GetHashCode()
+  {
+    return ValueType::GetHashCode();
+  }
+
+  /*---------------------------------------------------------------------------------*/
+    /* Static Functions                                                                */
+    /*---------------------------------------------------------------------------------*/
+
+  float Quaternion::Angle(Quaternion a, Quaternion b)
+  {
+    return SHQuaternion::Angle(Convert::ToNative(a), Convert::ToNative(b));
+  }
+
+  Quaternion Quaternion::AngleAxis(float angle, Vector3 axis)
+  {
+    return Convert::ToCLI(SHQuaternion::FromAxisAngle(Convert::ToNative(axis), angle));
+  }
+
+  float Quaternion::Dot(Quaternion a, Quaternion b)
+  {
+    return (a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w);
+  }
+
+  Quaternion Quaternion::Euler(float _x, float _y, float _z)
+  {
+    return Convert::ToCLI(SHQuaternion::FromPitchYawRoll(_x, _y, _z));
+  }
+
+  Quaternion Quaternion::FromToRotation(Vector3 fromDirection, Vector3 toDirection)
+  {
+    return Convert::ToCLI(SHQuaternion::FromToRotation(Convert::ToNative(fromDirection), Convert::ToNative(toDirection)));
+  }
+
+  Quaternion Quaternion::Inverse(Quaternion rotation)
+  {
+    return Convert::ToCLI(SHQuaternion::Inverse(Convert::ToNative(rotation)));
+  }
+
+  Quaternion Quaternion::Lerp(Quaternion a, Quaternion b, float t)
+  {
+    return Convert::ToCLI(SHQuaternion::ClampedLerp(Convert::ToNative(a), Convert::ToNative(b), t));
+  }
+
+  Quaternion Quaternion::LerpUnclamped(Quaternion a, Quaternion b, float t)
+  {
+    return Convert::ToCLI(SHQuaternion::Lerp(Convert::ToNative(a), Convert::ToNative(b), t));
+  }
+
+  Quaternion Quaternion::LookRotation(Vector3 forward, Vector3 upwards)
+  {
+    return Convert::ToCLI(SHQuaternion::LookRotation(Convert::ToNative(forward), Convert::ToNative(upwards)));
+  }
+
+  Quaternion Quaternion::Normalize(Quaternion q)
+  {
+    return Convert::ToCLI(SHQuaternion::Normalise(Convert::ToNative(q)));
+  }
+
+  Quaternion Quaternion::RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta)
+  {
+    return Convert::ToCLI(SHQuaternion::RotateTowards(Convert::ToNative(from), Convert::ToNative(to), Math::DegreesToRadians(maxDegreesDelta)));
+  }
+
+  Quaternion Quaternion::Slerp(Quaternion a, Quaternion b, float t)
+  {
+    return Convert::ToCLI(SHQuaternion::ClampedSlerp(Convert::ToNative(a), Convert::ToNative(b), t));
+  }
+
+  Quaternion Quaternion::SlerpUnclamped(Quaternion a, Quaternion b, float t)
+  {
+    return Convert::ToCLI(SHQuaternion::Slerp(Convert::ToNative(a), Convert::ToNative(b), t));
+  }
+
+
+  Quaternion Quaternion::operator*(Quaternion lhs, Quaternion rhs)
+  {
+    return Convert::ToCLI(Convert::ToNative(lhs) * Convert::ToNative(rhs));
+  }
+
+  bool Quaternion::operator==(Quaternion lhs, Quaternion rhs)
+  {
+    return lhs.Equals(rhs);
+  }
+}
\ No newline at end of file
diff --git a/SHADE_Managed/src/Math/Quaternion.hxx b/SHADE_Managed/src/Math/Quaternion.hxx
new file mode 100644
index 00000000..783038c9
--- /dev/null
+++ b/SHADE_Managed/src/Math/Quaternion.hxx
@@ -0,0 +1,237 @@
+/************************************************************************************//*!
+\file           Quaternion.hxx
+\author         Diren D Bharwani, diren.dbharwani, 390002520
+\par            email: diren.dbharwani\@digipen.edu
+\date           Oct 23, 2022
+\brief          Contains the definitions of Quaternion struct.
+ 
+                Note: This file is written in C++17/CLI.
+
+Copyright (C) 2021 DigiPen Institute of Technology.
+Reproduction or disclosure of this file or its contents without the prior written consent 
+of DigiPen Institute of Technology is prohibited.
+*//*************************************************************************************/
+
+#pragma once
+
+// Standard Libraries
+#include <limits>
+// Project Includes
+#include "Vector3.hxx"
+
+namespace SHADE
+{
+  ///<summary>
+  /// CLR version of SHADE's Quaternion class that represents an orientation.
+  /// Designed to closely match Unity's Quaternion struct.
+  /// </summary>
+  [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
+  public value struct Quaternion : public System::IEquatable<Quaternion>
+  {
+  public:
+    /*-----------------------------------------------------------------------------*/
+    /* Constants                                                                   */
+    /*-----------------------------------------------------------------------------*/
+#pragma region Constants
+
+    ///<summary>
+    /// Shorthand for writing Quaternion(0, 0, 0, 1).
+    ///</summary>
+    static initonly Quaternion Identity = Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
+
+#pragma endregion
+
+    /*-----------------------------------------------------------------------------*/
+    /* Public Members                                                              */
+    /*-----------------------------------------------------------------------------*/
+
+    ///<summary>
+    /// X-component of the Quaternion.
+    /// Don't modify this directly unless you know quaternions inside out.
+    ///</summary>
+    float x;
+    ///<summary>
+    /// Y-component of the Quaternion.
+    /// Don't modify this directly unless you know quaternions inside out.
+    ///</summary>
+    float y;
+    ///<summary>
+    /// Z-component of the Quaternion.
+    /// Don't modify this directly unless you know quaternions inside out.
+    ///</summary>
+    float z;
+    ///<summary>
+    /// W-component of the Quaternion. Do not directly modify quaternions.
+    ///</summary>
+    float w;
+
+    /*-----------------------------------------------------------------------------*/
+    /* Constructors                                                                */
+    /*-----------------------------------------------------------------------------*/
+
+    /// <summary>
+    /// Constructor to construct a Quaternion with the specified components.
+    /// </summary>
+    /// <param name="_x">X-coordinate to set.</param>
+    /// <param name="_y">Y-coordinate to set.</param>
+    /// <param name="_z">Z-coordinate to set.</param>
+    /// <param name="_z">W-coordinate to set.</param>
+    Quaternion(float _x, float _y, float _z, float _w);
+
+    /*-----------------------------------------------------------------------------*/
+    /* Usage Functions                                                             */
+    /*-----------------------------------------------------------------------------*/
+
+    /// <summary>
+    /// Creates a rotation which rotates from fromDirection to toDirection. <br/>
+    /// Use this to create a rotation which starts at the first Vector (fromDirection) and rotates to the second Vector (toDirection).
+    /// These Vectors must be set up in a script.
+    /// </summary>
+    void SetFromToRotation(Vector3 fromDirection, Vector3 toDirection);
+
+    /// <summary>
+    /// Creates a rotation with the specified forward and upwards directions. <br/>
+    /// The result is applied to this quaternion.
+    /// If used to orient a Transform, the Z axis will be aligned with forward and the Y axis with upwards, assuming these vectors are orthogonal.
+    /// Logs an error if the forward direction is zero.
+    /// </summary>
+    /// <param name="view">The direction to look in.</param>
+    /// <param name="up">The vector that defines in which direction up is.</param>
+    void SetLookRotation(Vector3 view, Vector3 up);
+
+    /// <summary>
+    /// Converts a rotation to angle-axis representation (angles in degrees).
+    /// </summary>
+    void ToAngleAxis(float^% angle, Vector3^% axis);
+    
+    System::String^ ToString() override;
+
+    /*-----------------------------------------------------------------------------*/
+    /* IEquatable                                                                  */
+    /*-----------------------------------------------------------------------------*/
+
+    /// <summary>
+    /// Compares equality with an object of the same type.
+    /// </summary>
+    /// <param name="other">The object to compare with.</param>
+    /// <returns>True if both objects are the same.</returns>
+    virtual bool Equals(Quaternion other);
+
+    /*-----------------------------------------------------------------------------*/
+    /* Object                                                                      */
+    /*-----------------------------------------------------------------------------*/
+
+    /// <summary>
+    /// Compares equality with another unboxed object.
+    /// </summary>
+    /// <param name="o">The unboxed object to compare with.</param>
+    /// <returns>True if both objects are the same.</returns>
+    bool Equals(Object^ o) override;
+
+    /// <summary>
+    /// Gets a unique hash for this object.
+    /// </summary>
+    /// <returns>Unique hash for this object.</returns>
+    int  GetHashCode() override;
+
+    /*-----------------------------------------------------------------------------*/
+    /* Static Functions                                                            */
+    /*-----------------------------------------------------------------------------*/
+
+    /// <summary>
+    /// Returns the angle in degrees between two rotations a and b.<br/>
+    /// </summary>
+    /// <returns>The angle in degrees between the two vectors. </returns>
+    static float Angle(Quaternion a, Quaternion b);
+
+    /// <summary>
+    /// Creates a rotation which rotates angle degrees around axis.
+    /// </summary>
+    static Quaternion AngleAxis(float angle, Vector3 axis);
+
+    /// <summary>
+    /// The dot product between two rotations.
+    /// </summary>
+    static float Dot(Quaternion a, Quaternion b);
+
+    /// <summary>
+    /// Returns a rotation that rotates y degrees around the y axis, x degrees around the x axis, and z degrees around the z axis; applied in that order.
+    /// </summary>
+    static Quaternion Euler(float _x, float _y, float _z);
+
+    /// <summary>
+    /// Creates a rotation which rotates from fromDirection to toDirection.
+    /// </summary>
+    static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection);
+
+    /// <summary>
+    /// Returns the Inverse of rotation.
+    /// </summary>
+    static Quaternion Inverse(Quaternion rotation);
+
+    /// <summary>
+    /// Interpolates between a and b by t and normalizes the result afterwards. The parameter t is clamped to the range [0, 1].
+    /// </summary>
+    /// <param name="a">Start value, returned when t = 0.</param>
+    /// <param name="b">End value, returned when t = 1.</param>
+    /// <param name="t">Interpolation ratio.</param>
+    /// <returns> A quaternion interpolated between quaternions a and b.</returns>
+    static Quaternion Lerp(Quaternion a, Quaternion b, float t);
+
+    /// <summary>
+    /// Interpolates between a and b by t and normalizes the result afterwards. The parameter t is not clamped.
+    /// </summary>
+    static Quaternion LerpUnclamped(Quaternion a, Quaternion b, float t);
+
+    /// <summary>
+    /// Creates a rotation with the specified forward and upwards directions. <br/>
+    /// Z axis will be aligned with forward, X axis aligned with cross product between forward and upwards, and Y axis aligned with cross product between Z and X.
+    /// </summary>
+    static Quaternion LookRotation(Vector3 forward, Vector3 upwards);
+
+    /// <summary>
+    /// Converts this quaternion to one with the same orientation but with a magnitude of 1.
+    /// </summary>
+    static Quaternion Normalize(Quaternion q);
+
+    /// <summary>
+    /// Rotates a rotation from towards to. <br/>
+    /// The from quaternion is rotated towards to by an angular step of maxDegreesDelta (but note that the rotation will not overshoot).
+    /// Negative values of maxDegreesDelta will move away from to until the rotation is exactly the opposite direction.
+    /// </summary>
+    static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta);
+
+    /// <summary>
+    /// Spherically interpolates between quaternions a and b by ratio t. The parameter t is clamped to the range [0, 1].
+    /// </summary>
+    /// <param name="a">Start value, returned when t = 0.</param>
+    /// <param name="b">End value, returned when t = 1.</param>
+    /// <param name="t">Interpolation ratio.</param>
+    /// <returns> A quaternion spherically interpolated between quaternions a and b.</returns>
+    static Quaternion Slerp(Quaternion a, Quaternion b, float t);
+
+    /// <summary>
+    /// Spherically interpolates between a and b by t. The parameter t is not clamped.
+    /// </summary>
+    static Quaternion SlerpUnclamped(Quaternion a, Quaternion b, float t); 
+
+    /*-----------------------------------------------------------------------------*/
+    /* Overloaded Operators                                                        */
+    /*-----------------------------------------------------------------------------*/
+
+    /// <summary>
+    /// Combines rotations lhs and rhs.
+    /// </summary>
+    /// <param name="lhs">Left-hand side quaternion.</param>
+    /// <param name="rhs">Right-hand side quaternion.</param>
+    static Quaternion operator*(Quaternion lhs, Quaternion rhs);
+
+    /// <summary>
+    /// Are two quaternions equal to each other?
+    /// </summary>
+    /// <param name="lhs">Left-hand side quaternion.</param>
+    /// <param name="rhs">Right-hand side quaternion.</param>
+    static bool operator==(Quaternion lhs, Quaternion rhs);
+  };
+
+} // namespace SHADE
diff --git a/SHADE_Managed/src/Math/Vector2.cxx b/SHADE_Managed/src/Math/Vector2.cxx
index d40e2323..b110d4f8 100644
--- a/SHADE_Managed/src/Math/Vector2.cxx
+++ b/SHADE_Managed/src/Math/Vector2.cxx
@@ -26,10 +26,10 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
     /* Constructors                                                                    */
     /*---------------------------------------------------------------------------------*/
-    Vector2::Vector2(double _x) 
-    : Vector2 { _x, 0.0 }
+    Vector2::Vector2(float _x) 
+    : Vector2 { _x, 0.0f }
     {}
-    Vector2::Vector2(double _x, double _y)
+    Vector2::Vector2(float _x, float _y)
     : x { _x }
     , y { _y }
     {}
@@ -47,22 +47,22 @@ namespace SHADE
         return *this / GetMagnitude();
     }
 
-    double Vector2::GetMagnitude()
+    float Vector2::GetMagnitude()
     {
         return sqrt(x * x + y * y);
     }
 
-    double Vector2::GetSqrMagnitude()
+    float Vector2::GetSqrMagnitude()
     {
         return x * x + y * y;
     }
 
-    double Vector2::AngleFromRightRadians()
+    float Vector2::AngleFromRightRadians()
     {
         return atan2(y, x);
     }
 
-    double Vector2::AngleFromRightDegrees()
+    float Vector2::AngleFromRightDegrees()
     {
         return Math::RadiansToDegrees(AngleFromRightRadians());
     }
@@ -72,7 +72,7 @@ namespace SHADE
         return IsNearPoint(point, Math::Epsilon);
     }
 
-    bool Vector2::IsNearPoint(Vector2 point, double tolerance)
+    bool Vector2::IsNearPoint(Vector2 point, float tolerance)
     {
         return (*this - point).GetSqrMagnitude() < (tolerance * tolerance);
     }
@@ -113,13 +113,13 @@ namespace SHADE
     {
         return IsNear(lhs, rhs, Math::Epsilon);
     }
-    bool Vector2::IsNear(Vector2 lhs, Vector2 rhs, double tolerance)
+    bool Vector2::IsNear(Vector2 lhs, Vector2 rhs, float tolerance)
     {
         return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance
                &&
                (std::abs(lhs.y) - std::abs(rhs.y)) < tolerance;
     }
-    double Vector2::Dot(Vector2 lhs, Vector2 rhs)
+    float Vector2::Dot(Vector2 lhs, Vector2 rhs)
     {
         return lhs.x * rhs.x + lhs.y * rhs.y;
     }
@@ -153,12 +153,12 @@ namespace SHADE
     }
     Vector2 Vector2::Reflect(Vector2 vec, Vector2 normal)
     {
-        return vec - (Project(vec, normal.GetNormalised()) * 2.0);
+        return vec - (Project(vec, normal.GetNormalised()) * 2.0f);
     }
-    Vector2 Vector2::RotateRadians(Vector2 vec, double radians)
+    Vector2 Vector2::RotateRadians(Vector2 vec, float radians)
     {
-        const double SINE   = sin(radians);
-        const double COSINE = cos(radians);
+        const float SINE   = sin(radians);
+        const float COSINE = cos(radians);
 
         return Vector2
         (
@@ -166,35 +166,35 @@ namespace SHADE
             vec.x * SINE   + vec.y * COSINE
         );
     }
-    Vector2 Vector2::RotateDegrees(Vector2 vec, double degrees)
+    Vector2 Vector2::RotateDegrees(Vector2 vec, float degrees)
     {
         return RotateRadians(vec, Math::DegreesToRadians(degrees));
     }
     Vector2 Vector2::Min(Vector2 lhs, Vector2 rhs)
     {
-        double lx = lhs.x, rx = rhs.x;
-        double ly = lhs.y, ry = rhs.y;
+        float lx = lhs.x, rx = rhs.x;
+        float ly = lhs.y, ry = rhs.y;
 
         return Vector2(std::min(lx, rx),
                        std::min(ly, ry));   
     }
     Vector2 Vector2::Max(Vector2 lhs, Vector2 rhs)
     {
-        double lx = lhs.x, rx = rhs.x;
-        double ly = lhs.y, ry = rhs.y;
+        float lx = lhs.x, rx = rhs.x;
+        float ly = lhs.y, ry = rhs.y;
 
         return Vector2(std::max(lx, rx),
                        std::max(ly, ry));  
     }
-    Vector2 Vector2::Lerp(Vector2 a, Vector2 b, double t)
+    Vector2 Vector2::Lerp(Vector2 a, Vector2 b, float t)
     {
-        return LerpUnclamped(a, b, std::clamp(t, 0.0, 1.0));
+        return LerpUnclamped(a, b, std::clamp(t, 0.0f, 1.0f));
     }
-    Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, double t)
+    Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, float t)
     {
         return a + ((b - a) * t);
     }
-    Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta)
+    Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target, float maxDistanceDelta)
     {
         // Ignore if it is exactly on the same point
         if (current == target)
@@ -206,7 +206,7 @@ namespace SHADE
 
         // Check if check if is behind or ahead of target
         Vector2 DIFF = target - newPos;
-        if (Dot(DELTA, DIFF) < 0.0)
+        if (Dot(DELTA, DIFF) < 0.0f)
         {
             newPos = target;
         }
@@ -236,7 +236,7 @@ namespace SHADE
             lhs.y * rhs.y
         );
     }
-    Vector2 Vector2::operator*(Vector2 lhs, double rhs)
+    Vector2 Vector2::operator*(Vector2 lhs, float rhs)
     {
         return Vector2
         (
@@ -244,7 +244,7 @@ namespace SHADE
             lhs.y * rhs
         );
     }
-    Vector2 Vector2::operator/(Vector2 lhs, double rhs)
+    Vector2 Vector2::operator/(Vector2 lhs, float rhs)
     {
         return Vector2
         (
diff --git a/SHADE_Managed/src/Math/Vector2.hxx b/SHADE_Managed/src/Math/Vector2.hxx
index 9253a703..94b1989f 100644
--- a/SHADE_Managed/src/Math/Vector2.hxx
+++ b/SHADE_Managed/src/Math/Vector2.hxx
@@ -19,8 +19,8 @@ of DigiPen Institute of Technology is prohibited.
 namespace SHADE
 {
     ///<summary>
-    /// CLR version of the the SHADE Engine's Vector2 class that represents a 
-    /// 2-Dimensional Vector. Designed to closely match Unity's Vector2 struct.
+    /// CLR version of SHADE Engine's Vector2 class that represents a 2-Dimensional Vector.
+    /// Designed to closely match Unity's Vector2 struct.
     /// </summary>
     [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
     public value struct Vector2 : public System::IEquatable<Vector2>
@@ -33,37 +33,37 @@ namespace SHADE
         ///<summary>
         /// Shorthand for writing Vector2(0, -1).
         ///</summary>
-        static initonly Vector2 Down = Vector2(0.0, -1.0);
+        static initonly Vector2 Down = Vector2(0.0f, -1.0f);
         ///<summary>
         /// Shorthand for writing Vector2(-1, 0).
         ///</summary>
-        static initonly Vector2 Left = Vector2(-1.0, 0.0);
+        static initonly Vector2 Left = Vector2(-1.0f, 0.0f);
         ///<summary>
-        /// Shorthand for writing Vector2(double.NegativeInfinity, 
-        /// double.NegativeInfinity).
+        /// Shorthand for writing Vector2(float.NegativeInfinity, 
+        /// float.NegativeInfinity).
         ///</summary>
-        static initonly Vector2 NegativeInfinity = Vector2(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest());
+        static initonly Vector2 NegativeInfinity = Vector2(std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest());
         ///<summary>
         /// Shorthand for writing Vector2(1, 1).
         ///</summary>
-        static initonly Vector2 One = Vector2(1.0, 1.0);
+        static initonly Vector2 One = Vector2(1.0f, 1.0f);
         ///<summary>
-        /// Shorthand for writing Vector2(double.PositiveInfinity, 
-        /// double.PositiveInfinity).
+        /// Shorthand for writing Vector2(float.PositiveInfinity, 
+        /// float.PositiveInfinity).
         ///</summary>
-        static initonly Vector2 PositiveInfinity = Vector2(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
+        static initonly Vector2 PositiveInfinity = Vector2(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
         ///<summary>
         /// Shorthand for writing Vector2(1, 0).
         ///</summary>
-        static initonly Vector2 Right = Vector2(1.0, 0.0);
+        static initonly Vector2 Right = Vector2(1.0f, 0.0f);
         ///<summary>
         /// Shorthand for writing Vector2(0, 1).
         ///</summary>
-        static initonly Vector2 Up = Vector2(0.0, 1.0);
+        static initonly Vector2 Up = Vector2(0.0f, 1.0f);
         ///<summary>
         /// Shorthand for writing Vector2(0, 0).
         ///</summary>        
-        static initonly Vector2 Zero = Vector2(0.0, 0.0);
+        static initonly Vector2 Zero = Vector2(0.0f, 0.0f);
         #pragma endregion
 
         /*-----------------------------------------------------------------------------*/
@@ -72,27 +72,27 @@ namespace SHADE
         ///<summary>
         /// X-component of the Vector2.
         ///</summary>
-        double x;
+        float x;
         ///<summary>
         /// Y-component of the Vector2.
         ///</summary>
-        double y;
+        float y;
 
         /*-----------------------------------------------------------------------------*/
         /* Constructors                                                                */
         /*-----------------------------------------------------------------------------*/
         /// <summary>
         /// Constructor to construct a Vector2 with the specified components with the 
-        /// Y-component set to 0.0.
+        /// Y-component set to 0.0f.
         /// </summary>
         /// <param name="_x">X-coordinate to set.</param>
-        Vector2(double _x);
+        Vector2(float _x);
         /// <summary>
         /// Constructor to construct a Vector2 with the specified components..
         /// </summary>
         /// <param name="_x">X-coordinate to set.</param>
         /// <param name="_y">Y-coordinate to set.</param>
-        Vector2(double _x, double _y);
+        Vector2(float _x, float _y);
 
         /*-----------------------------------------------------------------------------*/
         /* Usage Functions                                                             */
@@ -117,24 +117,24 @@ namespace SHADE
         /// need the precise magnitude, consider using GetSqrMagnitude() instead.
         /// </summary>
         /// <returns>Returns the length of this Vector2.</returns>
-        double GetMagnitude();
+        float GetMagnitude();
         /// <summary>
         /// Calculates and returns the squared magnitude of this Vector2.
         /// </summary>
         /// <returns>Returns the squared length of this Vector2.</returns>
-        double GetSqrMagnitude();
+        float GetSqrMagnitude();
         /// <summary>
         /// Calculates and returns the angle of this vector from the right vector. This 
         /// function returns values between -Math.PI and Math.PI.
         /// </summary>
         /// <returns>Returns the angle of this vector from the right vector in radians.</returns>
-        double AngleFromRightRadians();
+        float AngleFromRightRadians();
         /// <summary>
         /// Calculates and returns the angle of this vector from the right vector. This 
-        /// function returns values between -180.0 and 180.0.
+        /// function returns values between -180.0f and 180.0f.
         /// </summary>
         /// <returns>Returns the angle of this vector from the right vector in degrees.</returns>
-        double AngleFromRightDegrees();
+        float AngleFromRightDegrees();
         /// <summary>
         /// Checks if a specified point is near this Vector2 that represents a point with
         /// a tolerance value of PLS_EPSILON.
@@ -156,7 +156,7 @@ namespace SHADE
         /// True if this Vector2 representing a point and the specified point are within
         /// the range of the specified tolerance. False otherwise.
         /// </returns>
-        bool IsNearPoint(Vector2 point, double tolerance);
+        bool IsNearPoint(Vector2 point, float tolerance);
 
         /*-----------------------------------------------------------------------------*/
         /* IEquatable                                                                  */
@@ -206,7 +206,7 @@ namespace SHADE
         /// <returns>
         /// True if the two Vector2s are within the tolerance value specified
         /// </returns>
-        static bool IsNear(Vector2 lhs, Vector2 rhs, double tolerance);
+        static bool IsNear(Vector2 lhs, Vector2 rhs, float tolerance);
         /// <summary>
         /// Computes and returns the dot product of 2 specified Vector2s.
         /// </summary>
@@ -215,7 +215,7 @@ namespace SHADE
         /// <returns>
         /// Scalar value representing the dot product of the two Vector2s.
         /// </returns>
-        static double Dot(Vector2 lhs, Vector2 rhs);
+        static float Dot(Vector2 lhs, Vector2 rhs);
         /// <summary>
         /// Computes the inward perpendicular Vector2 to the specified Vector2.
         /// Equivalent to calling Perpendicular(lhs, true). This means, the
@@ -260,7 +260,7 @@ namespace SHADE
         /// Angle to rotate the vector by in an anti-clockwise direction in radians.
         /// </param>
         /// <returns>The Vector2 that represents the rotated vector.</returns>
-        static Vector2 RotateRadians(Vector2 vec, double radians);
+        static Vector2 RotateRadians(Vector2 vec, float radians);
         /// <summary>
         /// Rotates a Vector2 on the Z-axis by a specified angle in an anti-clockwise 
         /// direction.
@@ -270,7 +270,7 @@ namespace SHADE
         /// Angle to rotate the vector by in an anti-clockwise direction in degrees.
         /// </param>
         /// <returns>The Vector2 that represents the rotated vector.</returns>
-        static Vector2 RotateDegrees(Vector2 vec, double degrees);
+        static Vector2 RotateDegrees(Vector2 vec, float degrees);
         /// <summary>
         /// Computes and returns a Vector2 that is made from the smallest components of 
         /// the two specified Vector2s.
@@ -298,25 +298,25 @@ namespace SHADE
         /// This is most commonly used to find a point some fraction of the way along a 
         /// line between two endpoints.
         /// </summary>
-        /// <param name="a">The start Vector2, returned when t = 0.0.</param>
-        /// <param name="b">The end Vector2, returned when t = 1.0.</param>
+        /// <param name="a">The start Vector2, returned when t = 0.0f.</param>
+        /// <param name="b">The end Vector2, returned when t = 1.0f.</param>
         /// <param name="t">
         /// Value used to interpolate between a and b which is clamped to
         /// the range[0, 1].
         /// </param>
         /// <returns>The interpolated Vector2.</returns>
-        static Vector2 Lerp(Vector2 a, Vector2 b, double t);        
+        static Vector2 Lerp(Vector2 a, Vector2 b, float t);        
         /// <summary>
         /// Linearly interpolates between two specified points. 
         /// This is most commonly used to find a point some fraction of the way along a 
         /// line between two endpoints.
         /// Unlike Lerp(), t is not clamped to a range at all.
         /// </summary>
-        /// <param name="a">The start Vector2, returned when t = 0.0.</param>
-        /// <param name="b">The end Vector2, returned when t = 1.0.</param>
+        /// <param name="a">The start Vector2, returned when t = 0.0f.</param>
+        /// <param name="b">The end Vector2, returned when t = 1.0f.</param>
         /// <param name="t">Value used to interpolate between a and b.</param>
         /// <returns>The interpolated Vector2.</returns>
-        static Vector2 LerpUnclamped(Vector2 a, Vector2 b, double t);
+        static Vector2 LerpUnclamped(Vector2 a, Vector2 b, float t);
         /// <summary>
         /// Moves a point current towards target.
         /// Similar to Lerp(), however, the function will ensure that the distance never
@@ -327,7 +327,7 @@ namespace SHADE
         /// <param name="target">The target position to move to.</param>
         /// <param name="maxDistanceDelta">Maximum distance moved per call.</param>
         /// <returns>Vector representing the moved point.</returns>
-        static Vector2 MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta);
+        static Vector2 MoveTowards(Vector2 current, Vector2 target, float maxDistanceDelta);
 
         /*-----------------------------------------------------------------------------*/
         /* Overloaded Operators                                                        */
@@ -361,7 +361,7 @@ namespace SHADE
         /// <param name="lhs">Vector2 to multiply with.</param>
         /// <param name="rhs">Scalar to multiply with.</param>
         /// <returns>The result of the scalar multiplication.</returns>
-        static Vector2 operator*(Vector2 lhs, double rhs);
+        static Vector2 operator*(Vector2 lhs, float rhs);
         /// <summary>
         /// Calculates the division of a Vector2 with a scalar value and returns 
         /// the result.
@@ -369,7 +369,7 @@ namespace SHADE
         /// <param name="lhs">Scalar to divide with.</param>
         /// <param name="rhs">Vector2 to divide with.</param>
         /// <returns>The result of the scalar division.</returns>
-        static Vector2 operator/(Vector2 lhs, double rhs);
+        static Vector2 operator/(Vector2 lhs, float rhs);
         /// <summary>
         /// Checks if two Vector2s are approximately equal. This is equivalent to 
         /// calling Vector2.IsNear() with default tolerance values.
diff --git a/SHADE_Managed/src/Math/Vector3.cxx b/SHADE_Managed/src/Math/Vector3.cxx
index 26ff5a72..adbb4d3a 100644
--- a/SHADE_Managed/src/Math/Vector3.cxx
+++ b/SHADE_Managed/src/Math/Vector3.cxx
@@ -11,6 +11,7 @@ Copyright (C) 2021 DigiPen Institute of Technology.
 Reproduction or disclosure of this file or its contents without the prior written consent 
 of DigiPen Institute of Technology is prohibited.
 *//*************************************************************************************/
+
 // Precompiled Headers
 #include "SHpch.h"
 // Primary Header
@@ -26,13 +27,13 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
     /* Constructors                                                                    */
     /*---------------------------------------------------------------------------------*/
-    Vector3::Vector3(double _x) 
-    : Vector3 {_x, 0.0, 0.0}
+    Vector3::Vector3(float _x) 
+    : Vector3 {_x, 0.0f, 0.0f}
     {}
-    Vector3::Vector3(double _x, double _y)
-    : Vector3 {_x, _y, 0.0}
+    Vector3::Vector3(float _x, float _y)
+    : Vector3 {_x, _y, 0.0f}
     {}
-    Vector3::Vector3(double _x, double _y, double _z)
+    Vector3::Vector3(float _x, float _y, float _z)
     : x { _x }
     , y { _y }
     , z { _z }
@@ -54,22 +55,22 @@ namespace SHADE
         return *this / GetSqrMagnitude();
     }
 
-    double Vector3::GetMagnitude()
+    float Vector3::GetMagnitude()
     {
         return sqrt(x * x + y * y + z * z);
     }
 
-    double Vector3::GetSqrMagnitude()
+    float Vector3::GetSqrMagnitude()
     {
         return x * x + y * y + z * z;
     }
 
-    double Vector3::Angle2DFromRightRadians()
+    float Vector3::Angle2DFromRightRadians()
     {
         return atan2(y, x);
     }
 
-    double Vector3::Angle2DFromRightDegrees()
+    float Vector3::Angle2DFromRightDegrees()
     {
         return Math::RadiansToDegrees(Angle2DFromRightRadians());
     }
@@ -79,7 +80,7 @@ namespace SHADE
         return IsNearPoint(point, Math::Epsilon);
     }
 
-    bool Vector3::IsNearPoint(Vector3 point, double tolerance)
+    bool Vector3::IsNearPoint(Vector3 point, float tolerance)
     {
         return (*this - point).GetSqrMagnitude() < (tolerance * tolerance);
     }
@@ -121,7 +122,7 @@ namespace SHADE
     {
         return IsNear(lhs, rhs, Math::Epsilon);
     }
-    bool Vector3::IsNear(Vector3 lhs, Vector3 rhs, double tolerance)
+    bool Vector3::IsNear(Vector3 lhs, Vector3 rhs, float tolerance)
     {
         return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance
                &&
@@ -129,7 +130,7 @@ namespace SHADE
                &&
                (std::abs(lhs.z) - std::abs(rhs.z)) < tolerance;
     }
-    double Vector3::Dot(Vector3 lhs, Vector3 rhs)
+    float Vector3::Dot(Vector3 lhs, Vector3 rhs)
     {
         return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
     }
@@ -145,12 +146,12 @@ namespace SHADE
     }
     Vector3 Vector3::Reflect(Vector3 vec, Vector3 normal)
     {
-        return vec - (Project(vec, normal.GetNormalised()) * 2.0);
+        return vec - (Project(vec, normal.GetNormalised()) * 2.0f);
     }
-    Vector3 Vector3::RotateRadians(Vector3 vec, double radians)
+    Vector3 Vector3::RotateRadians(Vector3 vec, float radians)
     {
-        const double SINE   = sin(radians);
-        const double COSINE = cos(radians);
+        const float SINE   = sin(radians);
+        const float COSINE = cos(radians);
 
         return Vector3
         (
@@ -159,15 +160,15 @@ namespace SHADE
             vec.z
         );
     }
-    Vector3 Vector3::RotateDegrees(Vector3 vec, double degrees)
+    Vector3 Vector3::RotateDegrees(Vector3 vec, float degrees)
     {
         return RotateRadians(vec, Math::DegreesToRadians(degrees));
     }
     Vector3 Vector3::Min(Vector3 lhs, Vector3 rhs)
     {
-        double lx = lhs.x, rx = rhs.x;
-        double ly = lhs.y, ry = rhs.y;
-        double lz = lhs.z, rz = rhs.z;
+        float lx = lhs.x, rx = rhs.x;
+        float ly = lhs.y, ry = rhs.y;
+        float lz = lhs.z, rz = rhs.z;
 
         return Vector3(std::min(lx, rx),
                        std::min(ly, ry),
@@ -175,23 +176,23 @@ namespace SHADE
     }
     Vector3 Vector3::Max(Vector3 lhs, Vector3 rhs)
     {
-        double lx = lhs.x, rx = rhs.x;
-        double ly = lhs.y, ry = rhs.y;
-        double lz = lhs.z, rz = rhs.z;
+        float lx = lhs.x, rx = rhs.x;
+        float ly = lhs.y, ry = rhs.y;
+        float lz = lhs.z, rz = rhs.z;
 
         return Vector3(std::max(lx, rx),
                        std::max(ly, ry),
                        std::max(lz, rz));  
     }
-    Vector3 Vector3::Lerp(Vector3 a, Vector3 b, double t)
+    Vector3 Vector3::Lerp(Vector3 a, Vector3 b, float t)
     {
-        return LerpUnclamped(a, b, std::clamp(t, 0.0, 1.0));
+        return LerpUnclamped(a, b, std::clamp(t, 0.0f, 1.0f));
     }
-    Vector3 Vector3::LerpUnclamped(Vector3 a, Vector3 b, double t)
+    Vector3 Vector3::LerpUnclamped(Vector3 a, Vector3 b, float t)
     {
         return a + ((b - a) * t);
     }
-    Vector3 Vector3::MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta)
+    Vector3 Vector3::MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta)
     {
         // Ignore if it is exactly on the same point
         if (current == target)
@@ -203,7 +204,7 @@ namespace SHADE
 
         // Check if check if is behind or ahead of target
         Vector3 DIFF = target - newPos;
-        if (Dot(DELTA, DIFF) < 0.0)
+        if (Dot(DELTA, DIFF) < 0.0f)
         {
             newPos = target;
         }
@@ -236,7 +237,7 @@ namespace SHADE
             lhs.z * rhs.z
         );
     }
-    Vector3 Vector3::operator*(Vector3 lhs, double rhs)
+    Vector3 Vector3::operator*(Vector3 lhs, float rhs)
     {
         return Vector3
         (
@@ -245,7 +246,7 @@ namespace SHADE
             lhs.z * rhs
         );
     }
-    Vector3 Vector3::operator/(Vector3 lhs, double rhs)
+    Vector3 Vector3::operator/(Vector3 lhs, float rhs)
     {
         return Vector3
         (
diff --git a/SHADE_Managed/src/Math/Vector3.hxx b/SHADE_Managed/src/Math/Vector3.hxx
index e6cdc7d4..70cff88f 100644
--- a/SHADE_Managed/src/Math/Vector3.hxx
+++ b/SHADE_Managed/src/Math/Vector3.hxx
@@ -11,6 +11,7 @@ Copyright (C) 2021 DigiPen Institute of Technology.
 Reproduction or disclosure of this file or its contents without the prior written consent 
 of DigiPen Institute of Technology is prohibited.
 *//*************************************************************************************/
+
 #pragma once
 
 // Standard Libraries
@@ -21,8 +22,8 @@ of DigiPen Institute of Technology is prohibited.
 namespace SHADE
 {
     ///<summary>
-    /// CLR version of the the PlushieEngine's Vector3 class that represents a 
-    /// 3-Dimensional Vector. Designed to closely match Unity's Vector3 struct.
+    /// CLR version of SHADE Engine's Vector3 class that represents a 3-Dimensional Vector.
+    /// Designed to closely match Unity's Vector3 struct.
     /// </summary>
     [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
     public value struct Vector3 : public System::IEquatable<Vector3>
@@ -35,49 +36,49 @@ namespace SHADE
         ///<summary>
         /// Shorthand for writing Vector3(0, 0, -1).
         ///</summary>
-        static initonly Vector3 Back = Vector3(0.0, 0.0, -1.0);
+        static initonly Vector3 Back = Vector3(0.0f, 0.0f, -1.0f);
         ///<summary>
         /// Shorthand for writing Vector3(0, -1, 0).
         ///</summary>
-        static initonly Vector3 Down = Vector3(0.0, -1.0, 0.0);
+        static initonly Vector3 Down = Vector3(0.0f, -1.0f, 0.0f);
         ///<summary>
         /// Shorthand for writing Vector3(0, 0, 1).
         ///</summary>
-        static initonly Vector3 Forward = Vector3(0.0, 0.0, 1.0);
+        static initonly Vector3 Forward = Vector3(0.0f, 0.0f, 1.0f);
         ///<summary>
         /// Shorthand for writing Vector3(-1, 0, 0).
         ///</summary>
-        static initonly Vector3 Left = Vector3(-1.0, 0.0, 0.0);
+        static initonly Vector3 Left = Vector3(-1.0f, 0.0f, 0.0f);
         ///<summary>
-        /// Shorthand for writing Vector3(double.NegativeInfinity, 
-        /// double.NegativeInfinity, double.NegativeInfinity).
+        /// Shorthand for writing Vector3(float.NegativeInfinity, 
+        /// float.NegativeInfinity, float.NegativeInfinity).
         ///</summary>
-        static initonly Vector3 NegativeInfinity = Vector3(std::numeric_limits<double>::lowest(),
-                                                               std::numeric_limits<double>::lowest(), 
-                                                               std::numeric_limits<double>::lowest());
+        static initonly Vector3 NegativeInfinity = Vector3(std::numeric_limits<float>::lowest(),
+                                                               std::numeric_limits<float>::lowest(), 
+                                                               std::numeric_limits<float>::lowest());
         ///<summary>
         /// Shorthand for writing Vector3(1, 1, 1).
         ///</summary>
-        static initonly Vector3 One = Vector3(1.0, 1.0, 1.0);
+        static initonly Vector3 One = Vector3(1.0f, 1.0f, 1.0f);
         ///<summary>
-        /// Shorthand for writing Vector3(double.PositiveInfinity, 
-        /// double.PositiveInfinity, double.PositiveInfinity).
+        /// Shorthand for writing Vector3(float.PositiveInfinity, 
+        /// float.PositiveInfinity, float.PositiveInfinity).
         ///</summary>
-        static initonly Vector3 PositiveInfinity = Vector3(std::numeric_limits<double>::max(),
-                                                               std::numeric_limits<double>::max(), 
-                                                               std::numeric_limits<double>::max());
+        static initonly Vector3 PositiveInfinity = Vector3(std::numeric_limits<float>::max(),
+                                                               std::numeric_limits<float>::max(), 
+                                                               std::numeric_limits<float>::max());
         ///<summary>
         /// Shorthand for writing Vector3(1, 0, 0).
         ///</summary>
-        static initonly Vector3 Right = Vector3(1.0, 0.0, 0.0);
+        static initonly Vector3 Right = Vector3(1.0f, 0.0f, 0.0f);
         ///<summary>
         /// Shorthand for writing Vector3(0, 1, 0).
         ///</summary>
-        static initonly Vector3 Up = Vector3(0.0, 1.0, 0.0);
+        static initonly Vector3 Up = Vector3(0.0f, 1.0f, 0.0f);
         ///<summary>
         /// Shorthand for writing Vector3(0, 0, 0).
         ///</summary>        
-        static initonly Vector3 Zero = Vector3(0.0, 0.0, 0.0);
+        static initonly Vector3 Zero = Vector3(0.0f, 0.0f, 0.0f);
         #pragma endregion
 
         /*-----------------------------------------------------------------------------*/
@@ -86,39 +87,39 @@ namespace SHADE
         ///<summary>
         /// X-component of the Vector3.
         ///</summary>
-        double x;
+        float x;
         ///<summary>
         /// Y-component of the Vector3.
         ///</summary>
-        double y;
+        float y;
         ///<summary>
         /// Z-component of the Vector3.
         ///</summary>
-        double z;
+        float z;
 
         /*-----------------------------------------------------------------------------*/
         /* Constructors                                                                */
         /*-----------------------------------------------------------------------------*/
         /// <summary>
         /// Constructor to construct a Vector3 with the specified components with the 
-        /// Y and Z-component set to 0.0.
+        /// Y and Z-component set to 0.0f.
         /// </summary>
         /// <param name="_x">X-coordinate to set.</param>
-        Vector3(double _x);
+        Vector3(float _x);
         /// <summary>
         /// Constructor to construct a Vector3 with the specified components with the 
-        /// Z-component set to 0.0.
+        /// Z-component set to 0.0f.
         /// </summary>
         /// <param name="_x">X-coordinate to set.</param>
         /// <param name="_y">Y-coordinate to set.</param>
-        Vector3(double _x, double _y);
+        Vector3(float _x, float _y);
         /// <summary>
         /// Constructor to construct a Vector3 with the specified components.
         /// </summary>
         /// <param name="_x">X-coordinate to set.</param>
         /// <param name="_y">Y-coordinate to set.</param>
         /// <param name="_z">Z-coordinate to set.</param>
-        Vector3(double _x, double _y, double _z);
+        Vector3(float _x, float _y, float _z);
         /// <summary>
         /// Conversion constructor to construct a Vector3 using a Vector2.
         /// </summary>
@@ -148,24 +149,24 @@ namespace SHADE
         /// need the precise magnitude, consider using GetSqrMagnitude() instead.
         /// </summary>
         /// <returns>Returns the length of this Vector3.</returns>
-        double GetMagnitude();
+        float GetMagnitude();
         /// <summary>
         /// Calculates and returns the squared magnitude of this Vector3.
         /// </summary>
         /// <returns>Returns the squared length of this Vector3.</returns>
-        double GetSqrMagnitude();
+        float GetSqrMagnitude();
         /// <summary>
         /// Calculates and returns the angle of this vector from the right vector. This 
         /// function returns values between -Math.PI and Math.PI.
         /// </summary>
         /// <returns>Returns the angle of this vector from the right vector in radians.</returns>
-        double Angle2DFromRightRadians();
+        float Angle2DFromRightRadians();
         /// <summary>
         /// Calculates and returns the angle of this vector from the right vector. This 
-        /// function returns values between -180.0 and 180.0.
+        /// function returns values between -180.0f and 180.0f.
         /// </summary>
         /// <returns>Returns the angle of this vector from the right vector in degrees.</returns>
-        double Angle2DFromRightDegrees();
+        float Angle2DFromRightDegrees();
         /// <summary>
         /// Checks if a specified point is near this Vector3 that represents a point with
         /// a tolerance value of PLS_EPSILON.
@@ -187,7 +188,7 @@ namespace SHADE
         /// True if this Vector3 representing a point and the specified point are within
         /// the range of the specified tolerance. False otherwise.
         /// </returns>
-        bool IsNearPoint(Vector3 point, double tolerance);
+        bool IsNearPoint(Vector3 point, float tolerance);
 
         /*-----------------------------------------------------------------------------*/
         /* IEquatable                                                                  */
@@ -207,12 +208,12 @@ namespace SHADE
         /// </summary>
         /// <param name="o">The unboxed object to compare with.</param>
         /// <returns>True if both objects are the same.</returns>
-        bool Equals(Object^ o) override; 
+        bool Equals(Object^ o) override;
         /// <summary>
         /// Gets a unique hash for this object.
         /// </summary>
         /// <returns>Unique hash for this object.</returns>
-        int  GetHashCode() override;         
+        int  GetHashCode() override;
 
         /*-----------------------------------------------------------------------------*/
         /* Static Functions                                                            */
@@ -235,14 +236,14 @@ namespace SHADE
         /// <returns>
         /// True if the two Vector3s are within the tolerance value specified
         /// </returns>
-        static bool IsNear(Vector3 lhs, Vector3 rhs, double tolerance);
+        static bool IsNear(Vector3 lhs, Vector3 rhs, float tolerance);
         /// <summary>
         /// Computes and returns the dot product of 2 specified Vector3s.
         /// </summary>
         /// <param name="lhs">Vector3 to calculate dot product with.</param>
         /// <param name="rhs">Another Vector3 to calculate dot product with.</param>
         /// <returns>Scalar value representing the dot product of the two Vector3s.</returns>
-        static double Dot(Vector3 lhs, Vector3 rhs);
+        static float Dot(Vector3 lhs, Vector3 rhs);
         /// <summary>
         /// Computes and returns the cross product of 2 specified Vector3s.
         /// </summary>
@@ -273,7 +274,7 @@ namespace SHADE
         /// Angle to rotate the vector by in an anti-clockwise direction in radians.
         /// </param>
         /// <returns>The Vector3 that represents the rotated vector.</returns>
-        static Vector3 RotateRadians(Vector3 vec, double radians);
+        static Vector3 RotateRadians(Vector3 vec, float radians);
         /// <summary>
         /// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise 
         /// direction.
@@ -283,7 +284,7 @@ namespace SHADE
         /// Angle to rotate the vector by in an anti-clockwise direction in degrees.
         /// </param>
         /// <returns>The Vector3 that represents the rotated vector.</returns>
-        static Vector3 RotateDegrees(Vector3 vec, double degrees);
+        static Vector3 RotateDegrees(Vector3 vec, float degrees);
         /// <summary>
         /// Computes and returns a Vector3 that is made from the smallest components of 
         /// the two specified Vector3s.
@@ -311,25 +312,25 @@ namespace SHADE
         /// This is most commonly used to find a point some fraction of the way along a 
         /// line between two endpoints.
         /// </summary>
-        /// <param name="a">The start Vector3, returned when t = 0.0.</param>
-        /// <param name="b">The end Vector3, returned when t = 1.0.</param>
+        /// <param name="a">The start Vector3, returned when t = 0.0f.</param>
+        /// <param name="b">The end Vector3, returned when t = 1.0f.</param>
         /// <param name="t">
         /// Value used to interpolate between a and b which is clamped to
         /// the range[0, 1].
         /// </param>
         /// <returns>The interpolated Vector3.</returns>
-        static Vector3 Lerp(Vector3 a, Vector3 b, double t);        
+        static Vector3 Lerp(Vector3 a, Vector3 b, float t);        
         /// <summary>
         /// Linearly interpolates between two specified points. 
         /// This is most commonly used to find a point some fraction of the way along a 
         /// line between two endpoints.
         /// Unlike Lerp(), t is not clamped to a range at all.
         /// </summary>
-        /// <param name="a">The start Vector3, returned when t = 0.0.</param>
-        /// <param name="b">The end Vector3, returned when t = 1.0.</param>
+        /// <param name="a">The start Vector3, returned when t = 0.0f.</param>
+        /// <param name="b">The end Vector3, returned when t = 1.0f.</param>
         /// <param name="t">Value used to interpolate between a and b.</param>
         /// <returns>The interpolated Vector3.</returns>
-        static Vector3 LerpUnclamped(Vector3 a, Vector3 b, double t);
+        static Vector3 LerpUnclamped(Vector3 a, Vector3 b, float t);
         /// <summary>
         /// Moves a point current towards target.
         /// Similar to Lerp(), however, the function will ensure that the distance never
@@ -340,7 +341,7 @@ namespace SHADE
         /// <param name="target">The target position to move to.</param>
         /// <param name="maxDistanceDelta">Maximum distance moved per call.</param>
         /// <returns>Vector representing the moved point.</returns>
-        static Vector3 MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta);
+        static Vector3 MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta);
 
         /*-----------------------------------------------------------------------------*/
         /* Overloaded Operators                                                        */
@@ -374,7 +375,7 @@ namespace SHADE
         /// <param name="lhs">Vector3 to multiply with.</param>
         /// <param name="rhs">Scalar to multiply with.</param>
         /// <returns>The result of the scalar multiplication.</returns>
-        static Vector3 operator*(Vector3 lhs, double rhs);
+        static Vector3 operator*(Vector3 lhs, float rhs);
         /// <summary>
         /// Calculates the division of a Vector3 with a scalar value and returns 
         /// the result.
@@ -382,7 +383,7 @@ namespace SHADE
         /// <param name="lhs">Scalar to divide with.</param>
         /// <param name="rhs">Vector3 to divide with.</param>
         /// <returns>The result of the scalar division.</returns>
-        static Vector3 operator/(Vector3 lhs, double rhs);
+        static Vector3 operator/(Vector3 lhs, float rhs);
         /// <summary>
         /// Checks if two Vector3s are approximately equal. This is equivalent to 
         /// calling Vector3.IsNear() with default tolerance values.
diff --git a/SHADE_Managed/src/Utility/Convert.cxx b/SHADE_Managed/src/Utility/Convert.cxx
index 661eb3e4..4646194b 100644
--- a/SHADE_Managed/src/Utility/Convert.cxx
+++ b/SHADE_Managed/src/Utility/Convert.cxx
@@ -35,10 +35,7 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
     SHVec3 Convert::ToNative(Vector3 vec)
     {
-        const double X = vec.x;
-        const double Y = vec.y;
-        const double Z = vec.z;
-        return SHVec3(X, Y, Z);
+        return SHVec3(vec.x, vec.y, vec.z);
     }
     Vector3 Convert::ToCLI(const SHVec3& vec)
     {
@@ -46,9 +43,7 @@ namespace SHADE
     }
     SHVec2 Convert::ToNative(Vector2 vec)
     {
-        const double X = vec.x;
-        const double Y = vec.y;
-        return SHVec2(X, Y);
+        return SHVec2(vec.x, vec.y);
     }
 
     Vector2 Convert::ToCLI(const SHVec2& vec)
@@ -56,6 +51,16 @@ namespace SHADE
         return Vector2(vec.x, vec.y);
     }
 
+    SHQuaternion Convert::ToNative(Quaternion quat)
+    {
+      return SHQuaternion{ quat.x, quat.y, quat.z, quat.w };
+    }
+
+    Quaternion   Convert::ToCLI(const SHQuaternion& quat)
+    {
+      return Quaternion{ quat.x, quat.y, quat.z, quat.w };
+    }
+
     /*---------------------------------------------------------------------------------*/
     /* String Conversions                                                              */
     /*---------------------------------------------------------------------------------*/
diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx
index f04cbf4b..d694ca6a 100644
--- a/SHADE_Managed/src/Utility/Convert.hxx
+++ b/SHADE_Managed/src/Utility/Convert.hxx
@@ -18,10 +18,12 @@ of DigiPen Institute of Technology is prohibited.
 #include "ECS_Base/Entity/SHEntity.h"
 #include "Math/Vector/SHVec2.h"
 #include "Math/Vector/SHVec3.h"
+#include "Math/SHQuaternion.h"
 // Project Includes
 #include "Engine/Entity.hxx"
 #include "Math/Vector2.hxx"
 #include "Math/Vector3.hxx"
+#include "Math/Quaternion.hxx"
 
 namespace SHADE
 {
@@ -74,6 +76,18 @@ namespace SHADE
         /// <param name="vec">The native Vector2 to convert from.</param>
         /// <returns>Managed copy of a native Vector2.</returns>
         static Vector2 ToCLI(const SHVec2& vec);
+        /// <summary>
+        /// Converts from a managed Quaternion to a native Quaternion.
+        /// </summary>
+        /// <param name="quat">The managed Quaternion to convert from.</param>
+        /// <returns>Native copy of a managed Quaternion.</returns>
+        static SHQuaternion ToNative(Quaternion quat);
+        /// <summary>
+        /// Converts from a native Quaternion to a managed Quaternion.
+        /// </summary>
+        /// <param name="quat">The native Quaternion to convert from.</param>
+        /// <returns>Managed copy of a native Quaternion.</returns>
+        static Quaternion ToCLI(const SHQuaternion& quat);
 
         /*-----------------------------------------------------------------------------*/
         /* String Conversions                                                          */
