kitgit

tirbofish/dropbear · commit

c7d0b98b1acb1f01b2db1d31c7994e7d9d94f633

compiles, made a lot of efactoring...

Unverified

tk <4tkbytes@pm.me> · 2025-11-20 13:15

view full diff

diff --git a/Cargo.toml b/Cargo.toml
index 91d35fa..4811015 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,7 +6,17 @@ package.repository = "https://github.com/4tkbytes/dropbear"
 package.readme = "README.md"
 
 resolver = "3"
-members = [ "dropbear-engine", "dropbear-macro", "dropbear-shader", "dropbear-traits", "dropbear_future-queue", "eucalyptus-core", "eucalyptus-editor", "magna-carta", "redback-runtime"]
+members = [
+    "dropbear-engine",
+    "dropbear-macro",
+    "dropbear-shader",
+    "dropbear-traits",
+    "dropbear_future-queue",
+    "eucalyptus-core",
+    "eucalyptus-editor",
+    "magna-carta",
+    "redback-runtime"
+]
 
 [workspace.dependencies]
 anyhow = { version = "1.0", features = ["backtrace"] }
@@ -32,7 +42,6 @@ gilrs = "0.11"
 git2 = { version = "0.20", features = ["vendored-openssl"] }
 glam = { version = "0.30", features = ["serde"] }
 hecs = { version = "0.10", features = ["serde"] }
-lazy_static = "1.5"
 log = "0.4"
 log-once = "0.4"
 model_to_image = "0.1"
@@ -67,6 +76,7 @@ memory-stats = "1.2"
 typetag = "0.2"
 syn = { version = "2.0", features = ["full"] }
 quote = "1.0"
+egui_ltreeview = { version = "0.6", features = ["doc"] }
 
 [workspace.dependencies.image]
 version = "0.25"
diff --git a/dropbear-engine/src/entity.rs b/dropbear-engine/src/entity.rs
index eebd2a7..c652f3b 100644
--- a/dropbear-engine/src/entity.rs
+++ b/dropbear-engine/src/entity.rs
@@ -25,10 +25,21 @@ pub struct EntityTransform {
 }
 
 impl EntityTransform {
+    /// Creates a new [EntityTransform] from a local and world [Transform]
     pub fn new(local: Transform, world: Transform) -> Self {
         Self { local, world }
     }
 
+    /// Creates a new [EntityTransform] from a world [Transform] and a default local transform.
+    ///
+    /// This is best for situations where a local transform is not required.
+    pub fn new_from_world(world: Transform) -> Self {
+        Self {
+            world,
+            local: Transform::default()
+        }
+    }
+
     /// Gets a reference to the local transform
     pub fn local(&self) -> &Transform {
         &self.local
diff --git a/dropbear-engine/src/lighting.rs b/dropbear-engine/src/lighting.rs
index bda5959..3e3d4c7 100644
--- a/dropbear-engine/src/lighting.rs
+++ b/dropbear-engine/src/lighting.rs
@@ -2,7 +2,6 @@ use dropbear_traits::SerializableComponent;
 use glam::{DMat4, DQuat, DVec3};
 use std::fmt::{Display, Formatter};
 use std::sync::Arc;
-use serde::{Deserialize, Serialize};
 use wgpu::{
     BindGroup, BindGroupLayout, Buffer, BufferAddress, CompareFunction, DepthBiasState,
     RenderPipeline, StencilState, VertexBufferLayout, util::DeviceExt,
diff --git a/eucalyptus-core/src/component.rs b/eucalyptus-core/src/component.rs
index d896a6f..4ff5bf7 100644
--- a/eucalyptus-core/src/component.rs
+++ b/eucalyptus-core/src/component.rs
@@ -4,6 +4,14 @@
 /// ```
 /// use eucalyptus_core::with_component;
 ///
+/// use eucalyptus_core::scene::SceneEntity;
+///
+/// struct Transform {
+///     position: [f32; 3],
+/// }
+///
+/// let scene_entity = SceneEntity::default();
+///
 /// with_component!(scene_entity, Transform, /*mut*/ |transform| {
 ///     transform.position.x += 1.0;
 /// });
@@ -11,60 +19,43 @@
 macro_rules! with_component {
     // immutable
     ($entity:expr, $comp_type:ty, $closure:expr) => {
-        if let Some(comp) = $entity.get_component::<$comp_type>() {
+        $crate::traits::SerializableComponent::
+        if let Some(comp) = $entity.as_any().downcast_ref::<$comp_type>() {
             $closure(comp)
         }
     };
 
     // mutable
     ($entity:expr, $comp_type:ty, mut $closure:expr) => {
-        if let Some(comp) = $entity.get_component_mut::<$comp_type>() {
+        if let Some(comp) = $entity.as_any_mut().downcast_mut()::<$comp_type>() {
             $closure(comp)
         }
     };
 }
 
-/// Get a component or return early from the function
+/// Try to get a component, or execute else block
 ///
 /// # Usage
 /// ```
-/// use dropbear_engine::entity::MeshRenderer;
-/// use eucalyptus_core::get_component;
+/// use eucalyptus_core::if_component;
 ///
-/// fn process_entity(entity: &SceneEntity) {
-///     let renderer = get_component!(entity, MeshRenderer);
-///     println!("Processing mesh: {:?}", renderer.handle);
+/// use eucalyptus_core::scene::SceneEntity;
+///
+/// struct Transform {
+///     position: [f32; 3],
 /// }
-#[macro_export]
-macro_rules! get_component {
-    ($entity:expr, $comp_type:ty) => {
-        match $entity.get_component::<$comp_type>() {
-            Some(comp) => comp,
-            None => return,
-        }
-    };
-
-    ($entity:expr, $comp_type:ty, mut) => {
-        match $entity.get_component_mut::<$comp_type>() {
-            Some(comp) => comp,
-            None => return,
-        }
-    };
-}
-
-/// Try to get a component, or execute else block
 ///
-/// # Usage
-/// ```
-/// if_component!(scene_entity, Transform, |/*mut*/ transform| {
-///     transform.position = Vec3::new(1.0, 2.0, 3.0);
+/// let scene_entity = SceneEntity::default();
+///
+/// if_component!(scene_entity, Transform, /*mut*/ |transform| {
+///     let position = transform.position.get(0);
 /// } else {
 ///     println!("No transform found");
 /// });
 #[macro_export]
 macro_rules! if_component {
     ($entity:expr, $comp_type:ty, |$comp:ident| $then:block else $else:block) => {
-        if let Some($comp) = $entity.get_component::<$comp_type>() {
+        if let Some($comp) = $entity.as_any().downcast_ref::<$comp_type>() {
             $then
         } else {
             $else
@@ -72,13 +63,13 @@ macro_rules! if_component {
     };
 
     ($entity:expr, $comp_type:ty, |$comp:ident| $then:block) => {
-        if let Some($comp) = $entity.get_component::<$comp_type>() {
+        if let Some($comp) = $entity.as_any().downcast_ref::<$comp_type>() {
             $then
         }
     };
 
     ($entity:expr, $comp_type:ty, |mut $comp:ident| $then:block else $else:block) => {
-        if let Some(mut $comp) = $entity.get_component_mut::<$comp_type>() {
+        if let Some(mut $comp) =  $entity.as_any_mut().downcast_mut()::<$comp_type>() {
             $then
         } else {
             $else
@@ -86,7 +77,7 @@ macro_rules! if_component {
     };
 
     ($entity:expr, $comp_type:ty, |mut $comp:ident| $then:block) => {
-        if let Some(mut $comp) = $entity.get_component_mut::<$comp_type>() {
+        if let Some(mut $comp) = $entity.as_any_mut().downcast_mut()::<$comp_type>() {
             $then
         }
     };
diff --git a/eucalyptus-core/src/config.rs b/eucalyptus-core/src/config.rs
new file mode 100644
index 0000000..ae773a8
--- /dev/null
+++ b/eucalyptus-core/src/config.rs
@@ -0,0 +1,395 @@
+use std::path::{Path, PathBuf};
+use ron::ser::PrettyConfig;
+use std::fs;
+use serde::{Deserialize, Serialize};
+use egui_dock::DockState;
+use chrono::Utc;
+use crate::scene::SceneConfig;
+use crate::states::{EditorSettings, EditorTab, File, Folder, Node, ResourceType, RESOURCES, SCENES, SOURCE};
+
+/// The root config file, responsible for building and other metadata.
+///
+/// # Location
+/// This file is {project_name}.eucp and is located at {project_dir}/{project_name}.eucp
+#[derive(Debug, Deserialize, Serialize, Default, Clone)]
+pub struct ProjectConfig {
+    pub project_name: String,
+    pub project_path: PathBuf,
+    pub date_created: String,
+    pub date_last_accessed: String,
+    #[serde(default)]
+    pub dock_layout: Option<DockState<EditorTab>>,
+    #[serde(default)]
+    pub editor_settings: EditorSettings,
+    #[serde(default)]
+    pub last_opened_scene: Option<String>,
+}
+
+impl ProjectConfig {
+    /// Creates a new instance of the ProjectConfig. This function is typically used when creating
+    /// a new project, with it creating new defaults for everything.
+    pub fn new(project_name: String, project_path: impl AsRef<Path>) -> Self {
+        let date_created = format!("{}", Utc::now().format("%Y-%m-%d %H:%M:%S"));
+        let date_last_accessed = format!("{}", Utc::now().format("%Y-%m-%d %H:%M:%S"));
+
+        let mut result = Self {
+            project_name,
+            project_path: project_path.as_ref().to_path_buf(),
+            date_created,
+            date_last_accessed,
+            editor_settings: Default::default(),
+            dock_layout: None,
+            last_opened_scene: None,
+        };
+        let _ = result.load_config_to_memory();
+        result
+    }
+
+    /// This function writes the [`ProjectConfig`] struct (and other PathBufs) to a file of the choice
+    /// under the PathBuf path parameter.
+    ///
+    /// # Parameters
+    /// * path - The root **folder** of the project.
+    pub fn write_to(&mut self, path: impl AsRef<Path>) -> anyhow::Result<()> {
+        self.load_config_to_memory()?;
+        self.date_last_accessed = format!("{}", Utc::now().format("%Y-%m-%d %H:%M:%S"));
+        // self.assets = Assets::walk(path);
+        let ron_str = ron::ser::to_string_pretty(&self, PrettyConfig::default())
+            .map_err(|e| anyhow::anyhow!("RON serialization error: {}", e))?;
+        let config_path = path
+            .as_ref()
+            .join(format!("{}.eucp", self.project_name.clone().to_lowercase()));
+        self.project_path = path.as_ref().to_path_buf();
+
+        fs::write(&config_path, ron_str).map_err(|e| anyhow::anyhow!(e.to_string()))?;
+        Ok(())
+    }
+
+    /// This function reads from the RON and traverses down the different folders to add more information
+    /// to the ProjectConfig, such as Assets location and other stuff.
+    ///
+    /// # Parameters
+    /// * path - The root config **file** for the project
+    pub fn read_from(path: impl AsRef<Path>) -> anyhow::Result<Self> {
+        let ron_str = fs::read_to_string(path.as_ref())?;
+        let mut config: ProjectConfig = ron::de::from_str(ron_str.as_str())?;
+        config.project_path = path.as_ref().parent().unwrap().to_path_buf();
+        log::info!("Loaded project!");
+        log::debug!("Loaded config info");
+        log::debug!("Updating with new content");
+        config.load_config_to_memory()?;
+        config.write_to_all()?;
+        log::debug!("Successfully updated!");
+        Ok(config)
+    }
+
+    /// This function loads a `source.eucc`, `resources.eucc` or a `{scene}.eucs` config file into memory, allowing
+    /// you to reference and load the nodes located inside them.
+    pub fn load_config_to_memory(&mut self) -> anyhow::Result<()> {
+        let project_root = PathBuf::from(&self.project_path);
+
+        // resource config
+        match ResourceConfig::read_from(&project_root) {
+            Ok(resources) => {
+                let mut cfg = RESOURCES.write();
+                *cfg = resources;
+            }
+            Err(e) => {
+                if let Some(io_err) = e.downcast_ref::<std::io::Error>() {
+                    if io_err.kind() == std::io::ErrorKind::NotFound {
+                        log::warn!("resources.eucc not found, creating default.");
+                        let default = ResourceConfig {
+                            path: project_root.join("resources"),
+                            nodes: vec![],
+                        };
+                        default.write_to(&project_root)?;
+                        {
+                            let mut cfg = RESOURCES.write();
+                            *cfg = default;
+                        }
+                    } else {
+                        log::warn!("Failed to load resources.eucc: {}", e);
+                    }
+                } else {
+                    log::warn!("Failed to load resources.eucc: {}", e);
+                }
+            }
+        }
+
+        // src config
+        let mut source_config = SOURCE.write();
+        match SourceConfig::read_from(&project_root) {
+            Ok(source) => *source_config = source,
+            Err(e) => {
+                if let Some(io_err) = e.downcast_ref::<std::io::Error>() {
+                    if io_err.kind() == std::io::ErrorKind::NotFound {
+                        log::warn!("source.eucc not found, creating default.");
+                        let default = SourceConfig {
+                            path: project_root.join("src"),
+                            nodes: vec![],
+                        };
+                        default.write_to(&project_root)?;
+                        *source_config = default;
+                    } else {
+                        log::warn!("Failed to load source.eucc: {}", e);
+                    }
+                } else {
+                    log::warn!("Failed to load source.eucc: {}", e);
+                }
+            }
+        }
+
+        // scenes
+        let mut scene_configs = SCENES.write();
+        scene_configs.clear();
+
+        // iterate through each scene file in the folder
+        let scene_folder = &project_root.join("scenes");
+
+        if !scene_folder.exists() {
+            fs::create_dir_all(scene_folder)?;
+        }
+
+        for scene_entry in fs::read_dir(scene_folder)? {
+            let scene_entry = scene_entry?;
+            let path = scene_entry.path();
+
+            if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("eucs") {
+                match SceneConfig::read_from(&path) {
+                    Ok(scene) => {
+                        log::debug!("Loaded scene: {}", scene.scene_name);
+                        scene_configs.push(scene);
+                    }
+                    Err(e) => {
+                        if let Some(io_err) = e.downcast_ref::<std::io::Error>() {
+                            if io_err.kind() == std::io::ErrorKind::NotFound {
+                                log::warn!("Scene file {:?} not found", path);
+                            } else {
+                                panic!("Failed to load scene file {:?}: {}", path, e);
+                            }
+                        } else {
+                            panic!("Failed to load scene file {:?}: {}", path, e);
+                        }
+                    }
+                }
+            }
+        }
+
+        if scene_configs.is_empty() {
+            log::info!("No scenes found, creating default scene");
+            let default_scene =
+                SceneConfig::new("Default".to_string(), scene_folder.join("default.eucs"));
+            default_scene.write_to(&project_root)?;
+            self.last_opened_scene = Some(default_scene.scene_name.clone());
+            scene_configs.push(default_scene);
+        }
+
+        if let Some(ref last_scene_name) = self.last_opened_scene {
+            if let Some(pos) = scene_configs
+                .iter()
+                .position(|scene| &scene.scene_name == last_scene_name)
+            {
+                if pos != 0 {
+                    let scene = scene_configs.remove(pos);
+                    scene_configs.insert(0, scene);
+                }
+            } else if let Some(first) = scene_configs.first() {
+                self.last_opened_scene = Some(first.scene_name.clone());
+            }
+        } else if let Some(first) = scene_configs.first() {
+            self.last_opened_scene = Some(first.scene_name.clone());
+        }
+
+        Ok(())
+    }
+
+    /// # Parameters
+    /// * path - The root folder of the project
+    pub fn write_to_all(&mut self) -> anyhow::Result<()> {
+        let path = self.project_path.clone();
+
+        {
+            let resources_config = RESOURCES.read();
+            resources_config.write_to(&path)?;
+        }
+
+        {
+            let source_config = SOURCE.read();
+            source_config.write_to(&path)?;
+        }
+
+        {
+            let scene_configs = SCENES.read();
+            for scene in scene_configs.iter() {
+                scene.write_to(&path)?;
+            }
+        }
+
+        self.write_to(&path)?;
+        Ok(())
+    }
+}
+
+/// The resource config.
+#[derive(Default, Debug, Serialize, Deserialize)]
+pub struct ResourceConfig {
+    /// The path to the resource folder.
+    pub path: PathBuf,
+    /// The files and folders of the assets
+    pub nodes: Vec<Node>,
+}
+
+impl ResourceConfig {
+    /// # Parameters
+    /// - path: The root **folder** of the project
+    pub fn write_to(&self, path: impl AsRef<Path>) -> anyhow::Result<()> {
+        let resource_dir = path.as_ref().join("resources");
+        let updated_config = ResourceConfig {
+            path: resource_dir.clone(),
+            nodes: collect_nodes(&resource_dir, path.as_ref(), vec!["thumbnails"].as_slice()),
+        };
+        let ron_str = ron::ser::to_string_pretty(&updated_config, PrettyConfig::default())
+            .map_err(|e| anyhow::anyhow!("RON serialization error: {}", e))?;
+        let config_path = path.as_ref().join("resources").join("resources.eucc");
+        fs::create_dir_all(config_path.parent().unwrap())?;
+        fs::write(&config_path, ron_str).map_err(|e| anyhow::anyhow!(e.to_string()))?;
+        Ok(())
+    }
+
+    /// Updates the in-memory ResourceConfig by re-scanning the resource directory.
+    pub fn update_mem(&mut self) -> anyhow::Result<ResourceConfig> {
+        let resource_dir = self.path.clone();
+        let project_path = resource_dir.parent().unwrap_or(&resource_dir).to_path_buf();
+        let updated_config = ResourceConfig {
+            path: resource_dir.clone(),
+            nodes: collect_nodes(&resource_dir, &project_path, vec!["thumbnails"].as_slice()),
+        };
+        Ok(updated_config)
+    }
+
+    /// # Parameters
+    /// - path: The location to the **resources.eucc** file
+    pub fn read_from(path: impl AsRef<Path>) -> anyhow::Result<Self> {
+        let config_path = path.as_ref().join("resources").join("resources.eucc");
+        let ron_str = fs::read_to_string(&config_path)?;
+        let config: ResourceConfig = ron::de::from_str(&ron_str)
+            .map_err(|e| anyhow::anyhow!("RON deserialization error: {}", e))?;
+        Ok(config)
+    }
+}
+
+#[derive(Default, Debug, Serialize, Deserialize, Clone)]
+pub struct SourceConfig {
+    /// The path to the resource folder.
+    pub path: PathBuf,
+    /// The files and folders of the assets
+    pub nodes: Vec<Node>,
+}
+
+impl SourceConfig {
+    /// Builds a source path from the ProjectConfiguration's project_path (or a string)
+    #[allow(dead_code)]
+    pub fn build_path(project_path: String) -> PathBuf {
+        PathBuf::from(project_path).join("src/source.eucc")
+    }
+
+    /// # Parameters
+    /// - path: The root **folder** of the project
+    pub fn write_to(&self, path: impl AsRef<Path>) -> anyhow::Result<()> {
+        let resource_dir = path.as_ref().join("src");
+        let updated_config = SourceConfig {
+            path: resource_dir.clone(),
+            nodes: collect_nodes(&resource_dir, path.as_ref(), vec!["scripts"].as_slice()),
+        };
+
+        let ron_str = ron::ser::to_string_pretty(&updated_config, PrettyConfig::default())
+            .map_err(|e| anyhow::anyhow!("RON serialisation error: {}", e))?;
+        let config_path = path.as_ref().join("src").join("source.eucc");
+        fs::create_dir_all(config_path.parent().unwrap())?;
+        fs::write(&config_path, ron_str).map_err(|e| anyhow::anyhow!(e.to_string()))?;
+        Ok(())
+    }
+
+    /// # Parameters
+    /// - path: The location to the **source.eucc** file
+    pub fn read_from(path: impl AsRef<Path>) -> anyhow::Result<Self> {
+        let config_path = path.as_ref().join("src").join("source.eucc");
+        let ron_str = fs::read_to_string(&config_path)?;
+        let config: SourceConfig = ron::de::from_str(&ron_str)
+            .map_err(|e| anyhow::anyhow!("RON deserialization error: {}", e))?;
+        Ok(config)
+    }
+}
+
+fn collect_nodes(
+    dir: impl AsRef<Path>,
+    project_path: impl AsRef<Path>,
+    exclude_list: &[&str],
+) -> Vec<Node> {
+    let mut nodes = Vec::new();
+    if let Ok(entries) = fs::read_dir(dir) {
+        for entry in entries.flatten() {
+            let entry_path = entry.path();
+            let name = entry_path
+                .file_name()
+                .unwrap_or_default()
+                .to_string_lossy()
+                .to_string();
+
+            if entry_path.is_dir() && exclude_list.iter().any(|ex| ex.to_string() == *name) {
+                log::debug!("Skipped past folder {:?}", name);
+                continue;
+            }
+
+            if entry_path.is_dir() {
+                let folder_nodes = collect_nodes(&entry_path, project_path.as_ref(), exclude_list);
+                nodes.push(Node::Folder(Folder {
+                    name,
+                    path: entry_path.clone(),
+                    nodes: folder_nodes,
+                }));
+            } else {
+                let parent_folder = entry_path
+                    .parent()
+                    .and_then(|p| p.file_name())
+                    .map(|n| n.to_string_lossy().to_lowercase())
+                    .unwrap_or_default();
+
+                let resource_type = if parent_folder.contains("model") {
+                    ResourceType::Model
+                } else if parent_folder.contains("texture") {
+                    ResourceType::Texture
+                } else if parent_folder.contains("shader") {
+                    ResourceType::Shader
+                } else if entry_path
+                    .extension()
+                    .map(|e| e.to_string_lossy().to_lowercase())
+                    == Some("kt".to_string())
+                {
+                    ResourceType::Script
+                } else if entry_path
+                    .extension()
+                    .map(|e| e.to_string_lossy().to_lowercase().contains("eu"))
+                    .unwrap_or_default()
+                {
+                    ResourceType::Config
+                } else {
+                    ResourceType::Unknown
+                };
+
+                // Store relative path from the project root instead of absolute path
+                let relative_path = entry_path
+                    .strip_prefix(project_path.as_ref())
+                    .unwrap_or(&entry_path)
+                    .to_path_buf();
+
+                nodes.push(Node::File(File::ResourceFile {
+                    name,
+                    path: relative_path,
+                    resource_type,
+                }));
+            }
+        }
+    }
+    nodes
+}
diff --git a/eucalyptus-core/src/lib.rs b/eucalyptus-core/src/lib.rs
index b0ef223..5a867d0 100644
--- a/eucalyptus-core/src/lib.rs
+++ b/eucalyptus-core/src/lib.rs
@@ -11,7 +11,8 @@ pub mod states;
 pub mod utils;
 pub mod window;
 pub mod scene;
-mod component;
+pub mod component;
+pub mod config;
 
 pub use dropbear_traits as traits;
 pub use dropbear_macro as macros;
diff --git a/eucalyptus-core/src/scripting/jni/exports.rs b/eucalyptus-core/src/scripting/jni/exports.rs
index 2c1a42c..bc08e2a 100644
--- a/eucalyptus-core/src/scripting/jni/exports.rs
+++ b/eucalyptus-core/src/scripting/jni/exports.rs
@@ -27,7 +27,6 @@ use jni::sys::{
 use parking_lot::Mutex;
 use std::collections::{HashMap, HashSet};
 use std::sync::Arc;
-use dropbear_engine::lighting::Light;
 use crate::hierarchy::EntityTransformExt;
 
 /// `JNIEXPORT jlong JNICALL Java_com_dropbear_ffi_JNINative_getEntity
diff --git a/eucalyptus-core/src/scripting/native/exports.rs b/eucalyptus-core/src/scripting/native/exports.rs
index 765e42f..b97f8e6 100644
--- a/eucalyptus-core/src/scripting/native/exports.rs
+++ b/eucalyptus-core/src/scripting/native/exports.rs
@@ -6,8 +6,8 @@ use crate::states::{Label, ModelProperties, Value};
 use crate::utils::keycode_from_ordinal;
 use crate::window::{GraphicsCommand, WindowCommand};
 use dropbear_engine::camera::Camera;
-use dropbear_engine::entity::{MeshRenderer, Transform};
-use glam::{DQuat, DVec3};
+use dropbear_engine::entity::{EntityTransform, MeshRenderer};
+use glam::{DVec3};
 use hecs::World;
 use std::ffi::{CStr, c_char};
 
@@ -60,9 +60,10 @@ pub unsafe extern "C" fn dropbear_get_world_transform(
     let world = unsafe { &*world_ptr };
     let entity = unsafe { world.find_entity_from_id(entity_id as u32) };
 
-    match world.query_one::<&WorldTransform>(entity) {
+    match world.query_one::<&EntityTransform>(entity) {
         Ok(mut q) => {
             if let Some(transform) = q.get() {
+                let transform = transform.world();
                 unsafe {
                     (*out_transform).position_x = transform.position.x;
                     (*out_transform).position_y = transform.position.y;
@@ -80,12 +81,12 @@ pub unsafe extern "C" fn dropbear_get_world_transform(
                 eprintln!(
                     "[dropbear_get_transform] [ERROR] Entity has no WorldTransform component"
                 );
-                -4
+                DropbearNativeError::NoSuchComponent as i32
             }
         }
         Err(_) => {
             eprintln!("[dropbear_get_transform] [ERROR] Failed to query entity");
-            -2
+            DropbearNativeError::QueryFailed as i32
         }
     }
 }
@@ -104,9 +105,10 @@ pub unsafe extern "C" fn dropbear_get_local_transform(
     let world = unsafe { &*world_ptr };
     let entity = unsafe { world.find_entity_from_id(entity_id as u32) };
 
-    match world.query_one::<&LocalTransform>(entity) {
+    match world.query_one::<&EntityTransform>(entity) {
         Ok(mut q) => {
             if let Some(transform) = q.get() {
+                let transform = transform.local();
                 unsafe {
                     (*out_transform).position_x = transform.position.x;
                     (*out_transform).position_y = transform.position.y;
@@ -124,88 +126,12 @@ pub unsafe extern "C" fn dropbear_get_local_transform(
                 eprintln!(
                     "[dropbear_get_local_transform] [ERROR] Entity has no LocalTransform component"
                 );
-                return DropbearNativeError::NoSuchComponent as i32;
+                DropbearNativeError::NoSuchComponent as i32
             }
         }
         Err(_) => {
             eprintln!("[dropbear_get_local_transform] [ERROR] Failed to query entity");
-            return DropbearNativeError::QueryFailed as i32;
-        }
-    }
-}
-
-#[unsafe(no_mangle)]
-pub unsafe extern "C" fn dropbear_commit_world_transform(
-    world_ptr: *mut World,
-    entity_id: i64,
-    transform: NativeTransform,
-) -> i32 {
-    if world_ptr.is_null() {
-        eprintln!("[dropbear_commit_world_transform] [ERROR] World pointer is null");
-        return -1;
-    }
-
-    let world = unsafe { &mut *world_ptr };
-    let entity = unsafe { world.find_entity_from_id(entity_id as u32) };
-
-    let rust_transform = WorldTransform::new(Transform {
-        position: DVec3::new(
-            transform.position_x,
-            transform.position_y,
-            transform.position_z,
-        ),
-        rotation: DQuat::from_xyzw(
-            transform.rotation_x,
-            transform.rotation_y,
-            transform.rotation_z,
-            transform.rotation_w,
-        ),
-        scale: DVec3::new(transform.scale_x, transform.scale_y, transform.scale_z),
-    });
-
-    match world.insert_one(entity, rust_transform) {
-        Ok(_) => 0,
-        Err(_) => {
-            eprintln!("[dropbear_commit_world_transform] [ERROR] Failed to insert transform");
-            DropbearNativeError::WorldInsertError as i32;
-        }
-    }
-}
-
-#[unsafe(no_mangle)]
-pub unsafe extern "C" fn dropbear_commit_local_transform(
-    world_ptr: *mut World,
-    entity_id: i64,
-    transform: NativeTransform,
-) -> i32 {
-    if world_ptr.is_null() {
-        eprintln!("[dropbear_commit_local_transform] [ERROR] World pointer is null");
-        return -1;
-    }
-
-    let world = unsafe { &mut *world_ptr };
-    let entity = unsafe { world.find_entity_from_id(entity_id as u32) };
-
-    let rust_transform = LocalTransform::new(Transform {
-        position: DVec3::new(
-            transform.position_x,
-            transform.position_y,
-            transform.position_z,
-        ),
-        rotation: DQuat::from_xyzw(
-            transform.rotation_x,
-            transform.rotation_y,
-            transform.rotation_z,
-            transform.rotation_w,
-        ),
-        scale: DVec3::new(transform.scale_x, transform.scale_y, transform.scale_z),
-    });
-
-    match world.insert_one(entity, rust_transform) {
-        Ok(_) => 0,
-        Err(_) => {
-            eprintln!("[dropbear_commit_local_transform] [ERROR] Failed to insert transform");
-            -6
+            DropbearNativeError::QueryFailed as i32
         }
     }
 }
diff --git a/eucalyptus-core/src/spawn.rs b/eucalyptus-core/src/spawn.rs
index 3065738..31e5fe9 100644
--- a/eucalyptus-core/src/spawn.rs
+++ b/eucalyptus-core/src/spawn.rs
@@ -1,10 +1,8 @@
-use crate::states::ModelProperties;
-use dropbear_engine::entity::{EntityTransform};
 use dropbear_engine::future::{FutureHandle, FutureQueue};
 use dropbear_engine::graphics::SharedGraphicsContext;
-use dropbear_engine::utils::ResourceReference;
 use parking_lot::Mutex;
 use std::sync::{Arc, LazyLock};
+use crate::scene::SceneEntity;
 
 /// All spawns that are waiting to be spawned in.
 pub static PENDING_SPAWNS: LazyLock<Mutex<Vec<PendingSpawn>>> =
@@ -13,14 +11,7 @@ pub static PENDING_SPAWNS: LazyLock<Mutex<Vec<PendingSpawn>>> =
 /// A spawn that's waiting to be added into the world.
 #[derive(Clone, Debug)]
 pub struct PendingSpawn {
-    /// A [`ResourceReference`] to the asset
-    pub asset_path: ResourceReference,
-    /// The name/label of the asset
-    pub asset_name: String,
-    /// The [`EntityTransform`] properties (position)
-    pub transform: EntityTransform,
-    /// The properties of a model, as specified in [`ModelProperties`]
-    pub properties: ModelProperties,
+    pub scene_entity: SceneEntity,
     /// An optional future handle to an object.
     ///
     /// If one is specified, it is assumed that the returned object is a [`MeshRenderer`](dropbear_engine::entity::MeshRenderer).
diff --git a/eucalyptus-core/src/states.rs b/eucalyptus-core/src/states.rs
index 716ad25..5bf7e55 100644
--- a/eucalyptus-core/src/states.rs
+++ b/eucalyptus-core/src/states.rs
@@ -1,33 +1,21 @@
 use crate::traits::SerializableComponent;
 use crate::camera::{CameraComponent, CameraType};
-use crate::hierarchy::{Parent, SceneHierarchy};
-use crate::utils::{ResolveReference, PROTO_TEXTURE};
-use chrono::Utc;
-use dropbear_engine::asset::ASSET_REGISTRY;
-use dropbear_engine::camera::{Camera, CameraBuilder, CameraSettings};
+use dropbear_engine::camera::Camera;
 use dropbear_engine::entity::{MaterialOverride, MeshRenderer, Transform};
-use dropbear_engine::graphics::SharedGraphicsContext;
-use dropbear_engine::lighting::{Light, LightComponent};
-use dropbear_engine::model::Model;
-use dropbear_engine::procedural::plane::PlaneBuilder;
-use dropbear_engine::utils::{ResourceReference, ResourceReferenceType};
+use dropbear_engine::lighting::{LightComponent};
+use dropbear_engine::utils::{ResourceReference};
 use egui::Ui;
-use egui_dock::DockState;
-use glam::{DQuat, DVec3};
 use once_cell::sync::Lazy;
 use parking_lot::RwLock;
-use rayon::prelude::*;
-use ron::ser::PrettyConfig;
 use serde::{Deserialize, Serialize};
 use std::borrow::Borrow;
 use std::collections::HashMap;
 use std::fmt::{Display, Formatter};
 use std::ops::{Deref, DerefMut};
-use std::path::{Path, PathBuf};
-use std::sync::Arc;
-use std::{fmt, fs};
-use tokio::sync::mpsc::UnboundedSender;
+use std::path::{PathBuf};
+use std::{fmt};
 use dropbear_macro::SerializableComponent;
+use crate::config::{ProjectConfig, ResourceConfig, SourceConfig};
 use crate::scene::SceneConfig;
 
 pub static PROJECT: Lazy<RwLock<ProjectConfig>> =
@@ -97,229 +85,6 @@ pub fn load_scene_into_memory(scene_name: &str) -> anyhow::Result<()> {
     Ok(())
 }
 
-/// The root config file, responsible for building and other metadata.
-///
-/// # Location
-/// This file is {project_name}.eucp and is located at {project_dir}/{project_name}.eucp
-#[derive(Debug, Deserialize, Serialize, Default, Clone)]
-pub struct ProjectConfig {
-    pub project_name: String,
-    pub project_path: PathBuf,
-    pub date_created: String,
-    pub date_last_accessed: String,
-    #[serde(default)]
-    pub dock_layout: Option<DockState<EditorTab>>,
-    #[serde(default)]
-    pub editor_settings: EditorSettings,
-    #[serde(default)]
-    pub last_opened_scene: Option<String>,
-}
-
-impl ProjectConfig {
-    /// Creates a new instance of the ProjectConfig. This function is typically used when creating
-    /// a new project, with it creating new defaults for everything.
-    pub fn new(project_name: String, project_path: impl AsRef<Path>) -> Self {
-        let date_created = format!("{}", Utc::now().format("%Y-%m-%d %H:%M:%S"));
-        let date_last_accessed = format!("{}", Utc::now().format("%Y-%m-%d %H:%M:%S"));
-
-        let mut result = Self {
-            project_name,
-            project_path: project_path.as_ref().to_path_buf(),
-            date_created,
-            date_last_accessed,
-            editor_settings: Default::default(),
-            dock_layout: None,
-            last_opened_scene: None,
-        };
-        let _ = result.load_config_to_memory();
-        result
-    }
-
-    /// This function writes the [`ProjectConfig`] struct (and other PathBufs) to a file of the choice
-    /// under the PathBuf path parameter.
-    ///
-    /// # Parameters
-    /// * path - The root **folder** of the project.
-    pub fn write_to(&mut self, path: impl AsRef<Path>) -> anyhow::Result<()> {
-        self.load_config_to_memory()?;
-        self.date_last_accessed = format!("{}", Utc::now().format("%Y-%m-%d %H:%M:%S"));
-        // self.assets = Assets::walk(path);
-        let ron_str = ron::ser::to_string_pretty(&self, PrettyConfig::default())
-            .map_err(|e| anyhow::anyhow!("RON serialization error: {}", e))?;
-        let config_path = path
-            .as_ref()
-            .join(format!("{}.eucp", self.project_name.clone().to_lowercase()));
-        self.project_path = path.as_ref().to_path_buf();
-
-        fs::write(&config_path, ron_str).map_err(|e| anyhow::anyhow!(e.to_string()))?;
-        Ok(())
-    }
-
-    /// This function reads from the RON and traverses down the different folders to add more information
-    /// to the ProjectConfig, such as Assets location and other stuff.
-    ///
-    /// # Parameters
-    /// * path - The root config **file** for the project
-    pub fn read_from(path: impl AsRef<Path>) -> anyhow::Result<Self> {
-        let ron_str = fs::read_to_string(path.as_ref())?;
-        let mut config: ProjectConfig = ron::de::from_str(ron_str.as_str())?;
-        config.project_path = path.as_ref().parent().unwrap().to_path_buf();
-        log::info!("Loaded project!");
-        log::debug!("Loaded config info");
-        log::debug!("Updating with new content");
-        config.load_config_to_memory()?;
-        config.write_to_all()?;
-        log::debug!("Successfully updated!");
-        Ok(config)
-    }
-
-    /// This function loads a `source.eucc`, `resources.eucc` or a `{scene}.eucs` config file into memory, allowing
-    /// you to reference and load the nodes located inside them.
-    pub fn load_config_to_memory(&mut self) -> anyhow::Result<()> {
-        let project_root = PathBuf::from(&self.project_path);
-
-        // resource config
-        match ResourceConfig::read_from(&project_root) {
-            Ok(resources) => {
-                let mut cfg = RESOURCES.write();
-                *cfg = resources;
-            }
-            Err(e) => {
-                if let Some(io_err) = e.downcast_ref::<std::io::Error>() {
-                    if io_err.kind() == std::io::ErrorKind::NotFound {
-                        log::warn!("resources.eucc not found, creating default.");
-                        let default = ResourceConfig {
-                            path: project_root.join("resources"),
-                            nodes: vec![],
-                        };
-                        default.write_to(&project_root)?;
-                        {
-                            let mut cfg = RESOURCES.write();
-                            *cfg = default;
-                        }
-                    } else {
-                        log::warn!("Failed to load resources.eucc: {}", e);
-                    }
-                } else {
-                    log::warn!("Failed to load resources.eucc: {}", e);
-                }
-            }
-        }
-
-        // src config
-        let mut source_config = SOURCE.write();
-        match SourceConfig::read_from(&project_root) {
-            Ok(source) => *source_config = source,
-            Err(e) => {
-                if let Some(io_err) = e.downcast_ref::<std::io::Error>() {
-                    if io_err.kind() == std::io::ErrorKind::NotFound {
-                        log::warn!("source.eucc not found, creating default.");
-                        let default = SourceConfig {
-                            path: project_root.join("src"),
-                            nodes: vec![],
-                        };
-                        default.write_to(&project_root)?;
-                        *source_config = default;
-                    } else {
-                        log::warn!("Failed to load source.eucc: {}", e);
-                    }
-                } else {
-                    log::warn!("Failed to load source.eucc: {}", e);
-                }
-            }
-        }
-
-        // scenes
-        let mut scene_configs = SCENES.write();
-        scene_configs.clear();
-
-        // iterate through each scene file in the folder
-        let scene_folder = &project_root.join("scenes");
-
-        if !scene_folder.exists() {
-            fs::create_dir_all(scene_folder)?;
-        }
-
-        for scene_entry in fs::read_dir(scene_folder)? {
-            let scene_entry = scene_entry?;
-            let path = scene_entry.path();
-
-            if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("eucs") {
-                match SceneConfig::read_from(&path) {
-                    Ok(scene) => {
-                        log::debug!("Loaded scene: {}", scene.scene_name);
-                        scene_configs.push(scene);
-                    }
-                    Err(e) => {
-                        if let Some(io_err) = e.downcast_ref::<std::io::Error>() {
-                            if io_err.kind() == std::io::ErrorKind::NotFound {
-                                log::warn!("Scene file {:?} not found", path);
-                            } else {
-                                panic!("Failed to load scene file {:?}: {}", path, e);
-                            }
-                        } else {
-                            panic!("Failed to load scene file {:?}: {}", path, e);
-                        }
-                    }
-                }
-            }
-        }
-
-        if scene_configs.is_empty() {
-            log::info!("No scenes found, creating default scene");
-            let default_scene =
-                SceneConfig::new("Default".to_string(), scene_folder.join("default.eucs"));
-            default_scene.write_to(&project_root)?;
-            self.last_opened_scene = Some(default_scene.scene_name.clone());
-            scene_configs.push(default_scene);
-        }
-
-        if let Some(ref last_scene_name) = self.last_opened_scene {
-            if let Some(pos) = scene_configs
-                .iter()
-                .position(|scene| &scene.scene_name == last_scene_name)
-            {
-                if pos != 0 {
-                    let scene = scene_configs.remove(pos);
-                    scene_configs.insert(0, scene);
-                }
-            } else if let Some(first) = scene_configs.first() {
-                self.last_opened_scene = Some(first.scene_name.clone());
-            }
-        } else if let Some(first) = scene_configs.first() {
-            self.last_opened_scene = Some(first.scene_name.clone());
-        }
-
-        Ok(())
-    }
-
-    /// # Parameters
-    /// * path - The root folder of the project
-    pub fn write_to_all(&mut self) -> anyhow::Result<()> {
-        let path = self.project_path.clone();
-
-        {
-            let resources_config = RESOURCES.read();
-            resources_config.write_to(&path)?;
-        }
-
-        {
-            let source_config = SOURCE.read();
-            source_config.write_to(&path)?;
-        }
-
-        {
-            let scene_configs = SCENES.read();
-            for scene in scene_configs.iter() {
-                scene.write_to(&path)?;
-            }
-        }
-
-        self.write_to(&path)?;
-        Ok(())
-    }
-}
-
 #[derive(Debug, Serialize, Deserialize, Clone)]
 pub enum Node {
     File(File),
@@ -341,13 +106,6 @@ pub enum File {
     },
 }
 
-// #[derive(Default, Debug, Serialize, Deserialize, Clone)]
-// pub struct File {
-//     pub name: String,
-//     pub path: PathBuf,
-//     pub resource_type: Option<ResourceType>,
-// }
-
 #[derive(Default, Debug, Serialize, Deserialize, Clone)]
 pub struct Folder {
     pub name: String,
@@ -382,319 +140,11 @@ impl Display for ResourceType {
     }
 }
 
-/// The resource config.
-#[derive(Default, Debug, Serialize, Deserialize)]
-pub struct ResourceConfig {
-    /// The path to the resource folder.
-    pub path: PathBuf,
-    /// The files and folders of the assets
-    pub nodes: Vec<Node>,
-}
-
-impl ResourceConfig {
-    /// Builds a resource path from the ProjectConfiguration's project_path (or a string)
-    #[allow(dead_code)]
-    pub fn build_path(project_path: String) -> PathBuf {
-        PathBuf::from(project_path).join("resources/resources.eucc")
-    }
-
-    /// # Parameters
-    /// - path: The root **folder** of the project
-    pub fn write_to(&self, path: impl AsRef<Path>) -> anyhow::Result<()> {
-        let resource_dir = path.as_ref().join("resources");
-        let updated_config = ResourceConfig {
-            path: resource_dir.clone(),
-            nodes: collect_nodes(&resource_dir, path.as_ref(), vec!["thumbnails"].as_slice()),
-        };
-        let ron_str = ron::ser::to_string_pretty(&updated_config, PrettyConfig::default())
-            .map_err(|e| anyhow::anyhow!("RON serialization error: {}", e))?;
-        let config_path = path.as_ref().join("resources").join("resources.eucc");
-        fs::create_dir_all(config_path.parent().unwrap())?;
-        fs::write(&config_path, ron_str).map_err(|e| anyhow::anyhow!(e.to_string()))?;
-        Ok(())
-    }
-
-    /// Updates the in-memory ResourceConfig by re-scanning the resource directory.
-    pub fn update_mem(&mut self) -> anyhow::Result<ResourceConfig> {
-        let resource_dir = self.path.clone();
-        let project_path = resource_dir.parent().unwrap_or(&resource_dir).to_path_buf();
-        let updated_config = ResourceConfig {
-            path: resource_dir.clone(),
-            nodes: collect_nodes(&resource_dir, &project_path, vec!["thumbnails"].as_slice()),
-        };
-        Ok(updated_config)
-    }
-
-    /// # Parameters
-    /// - path: The location to the **resources.eucc** file
-    pub fn read_from(path: impl AsRef<Path>) -> anyhow::Result<Self> {
-        let config_path = path.as_ref().join("resources").join("resources.eucc");
-        let ron_str = fs::read_to_string(&config_path)?;
-        let config: ResourceConfig = ron::de::from_str(&ron_str)
-            .map_err(|e| anyhow::anyhow!("RON deserialization error: {}", e))?;
-        Ok(config)
-    }
-}
-
-#[derive(Default, Debug, Serialize, Deserialize, Clone)]
-pub struct SourceConfig {
-    /// The path to the resource folder.
-    pub path: PathBuf,
-    /// The files and folders of the assets
-    pub nodes: Vec<Node>,
-}
-
-impl SourceConfig {
-    /// Builds a source path from the ProjectConfiguration's project_path (or a string)
-    #[allow(dead_code)]
-    pub fn build_path(project_path: String) -> PathBuf {
-        PathBuf::from(project_path).join("src/source.eucc")
-    }
-
-    /// # Parameters
-    /// - path: The root **folder** of the project
-    pub fn write_to(&self, path: impl AsRef<Path>) -> anyhow::Result<()> {
-        let resource_dir = path.as_ref().join("src");
-        let updated_config = SourceConfig {
-            path: resource_dir.clone(),
-            nodes: collect_nodes(&resource_dir, path.as_ref(), vec!["scripts"].as_slice()),
-        };
-
-        let ron_str = ron::ser::to_string_pretty(&updated_config, PrettyConfig::default())
-            .map_err(|e| anyhow::anyhow!("RON serialisation error: {}", e))?;
-        let config_path = path.as_ref().join("src").join("source.eucc");
-        fs::create_dir_all(config_path.parent().unwrap())?;
-        fs::write(&config_path, ron_str).map_err(|e| anyhow::anyhow!(e.to_string()))?;
-        Ok(())
-    }
-
-    /// # Parameters
-    /// - path: The location to the **source.eucc** file
-    pub fn read_from(path: impl AsRef<Path>) -> anyhow::Result<Self> {
-        let config_path = path.as_ref().join("src").join("source.eucc");
-        let ron_str = fs::read_to_string(&config_path)?;
-        let config: SourceConfig = ron::de::from_str(&ron_str)
-            .map_err(|e| anyhow::anyhow!("RON deserialization error: {}", e))?;
-        Ok(config)
-    }
-}
-
-fn collect_nodes(
-    dir: impl AsRef<Path>,
-    project_path: impl AsRef<Path>,
-    exclude_list: &[&str],
-) -> Vec<Node> {
-    let mut nodes = Vec::new();
-    if let Ok(entries) = fs::read_dir(dir) {
-        for entry in entries.flatten() {
-            let entry_path = entry.path();
-            let name = entry_path
-                .file_name()
-                .unwrap_or_default()
-                .to_string_lossy()
-                .to_string();
-
-            if entry_path.is_dir() && exclude_list.iter().any(|ex| ex.to_string() == *name) {
-                log::debug!("Skipped past folder {:?}", name);
-                continue;
-            }
-
-            if entry_path.is_dir() {
-                let folder_nodes = collect_nodes(&entry_path, project_path.as_ref(), exclude_list);
-                nodes.push(Node::Folder(Folder {
-                    name,
-                    path: entry_path.clone(),
-                    nodes: folder_nodes,
-                }));
-            } else {
-                let parent_folder = entry_path
-                    .parent()
-                    .and_then(|p| p.file_name())
-                    .map(|n| n.to_string_lossy().to_lowercase())
-                    .unwrap_or_default();
-
-                let resource_type = if parent_folder.contains("model") {
-                    ResourceType::Model
-                } else if parent_folder.contains("texture") {
-                    ResourceType::Texture
-                } else if parent_folder.contains("shader") {
-                    ResourceType::Shader
-                } else if entry_path
-                    .extension()
-                    .map(|e| e.to_string_lossy().to_lowercase())
-                    == Some("kt".to_string())
-                {
-                    ResourceType::Script
-                } else if entry_path
-                    .extension()
-                    .map(|e| e.to_string_lossy().to_lowercase().contains("eu"))
-                    .unwrap_or_default()
-                {
-                    ResourceType::Config
-                } else {
-                    ResourceType::Unknown
-                };
-
-                // Store relative path from the project root instead of absolute path
-                let relative_path = entry_path
-                    .strip_prefix(project_path.as_ref())
-                    .unwrap_or(&entry_path)
-                    .to_path_buf();
-
-                nodes.push(Node::File(File::ResourceFile {
-                    name,
-                    path: relative_path,
-                    resource_type,
-                }));
-            }
-        }
-    }
-    nodes
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, Hash)]
-pub enum EntityNode {
-    Entity {
-        id: hecs::Entity,
-        name: String,
-    },
-    Script {
-        tags: Vec<String>,
-    },
-    Light {
-        id: hecs::Entity,
-        name: String,
-    },
-    Camera {
-        id: hecs::Entity,
-        name: String,
-        camera_type: CameraType,
-    },
-    Group {
-        name: String,
-        children: Vec<EntityNode>,
-        collapsed: bool,
-    },
-}
-
 #[derive(Default, Debug, Serialize, Deserialize, Clone, SerializableComponent)]
 pub struct ScriptComponent {
     pub tags: Vec<String>,
 }
 
-impl EntityNode {
-    pub fn from_world(world: &hecs::World) -> Vec<Self> {
-        let mut nodes = Vec::new();
-        let mut handled = std::collections::HashSet::new();
-
-        for (id, (label, script, _transform, _renderer)) in world
-            .query::<(
-                &Label,
-                &ScriptComponent,
-                &dropbear_engine::entity::Transform,
-                &dropbear_engine::entity::MeshRenderer,
-            )>()
-            .iter()
-        {
-            let name = label.to_string();
-            let mut children = vec![
-                EntityNode::Entity {
-                    id,
-                    name: name.clone(),
-                },
-                EntityNode::Script {
-                    tags: script.tags.clone(),
-                },
-            ];
-
-            // Check if this entity also has camera components
-            if let Ok(mut camera_query) = world.query_one::<(&Camera, &CameraComponent)>(id)
-                && let Some((camera, component)) = camera_query.get()
-            {
-                children.push(EntityNode::Camera {
-                    id,
-                    name: camera.label.clone(),
-                    camera_type: component.camera_type,
-                });
-            }
-
-            nodes.push(EntityNode::Group {
-                name: name.clone(),
-                children,
-                collapsed: false,
-            });
-            handled.insert(id);
-        }
-
-        // Handle single entities (and potentially cameras)
-        for (id, (label, _renderer)) in world
-            .query::<(&Label, &dropbear_engine::entity::MeshRenderer)>()
-            .iter()
-        {
-            if handled.contains(&id) {
-                continue;
-            }
-            let name = label.to_string();
-
-            // Check if this entity has camera components
-            if let Ok(mut camera_query) = world.query_one::<(&Camera, &CameraComponent)>(id) {
-                if let Some((camera, component)) = camera_query.get() {
-                    // Create a group with the entity and its camera component
-                    nodes.push(EntityNode::Group {
-                        name: name.clone(),
-                        children: vec![
-                            EntityNode::Entity {
-                                id,
-                                name: name.clone(),
-                            },
-                            EntityNode::Camera {
-                                id,
-                                name: camera.label.clone(),
-                                camera_type: component.camera_type,
-                            },
-                        ],
-                        collapsed: false,
-                    });
-                } else {
-                    // Regular entity without camera components
-                    nodes.push(EntityNode::Entity { id, name });
-                }
-            } else {
-                // Regular entity without camera components
-                nodes.push(EntityNode::Entity { id, name });
-            }
-        }
-
-        // lights
-        for (id, (_transform, _light_comp, light)) in world
-            .query::<(&dropbear_engine::entity::Transform, &LightComponent, &Light)>()
-            .iter()
-        {
-            if handled.contains(&id) {
-                continue;
-            }
-            nodes.push(EntityNode::Light {
-                id,
-                name: light.label().to_string(),
-            });
-            handled.insert(id);
-        }
-
-        // Handle standalone cameras (cameras without MeshRenderer - like viewport cameras)
-        for (entity, (camera, component)) in world.query::<(&Camera, &CameraComponent)>().iter() {
-            if world.get::<&MeshRenderer>(entity).is_err() {
-                nodes.push(EntityNode::Camera {
-                    id: entity,
-                    name: camera.label.clone(),
-                    camera_type: component.camera_type,
-                });
-            }
-        }
-
-        nodes
-    }
-}
-
 #[derive(Debug, Serialize, Deserialize, Clone, SerializableComponent)]
 pub struct CameraConfig {
     pub label: String,
@@ -757,12 +207,6 @@ impl CameraConfig {
     }
 }
 
-#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, SerializableComponent)]
-pub struct ModelProperties {
-    pub custom_properties: Vec<Property>,
-    pub next_id: u64,
-}
-
 #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
 pub struct Property {
     pub id: u64,
@@ -798,7 +242,16 @@ impl Display for Value {
     }
 }
 
+/// Properties for an entity, typically queries with `entity.getProperty<Float>` and `entity.setProperty(67)`
+#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, SerializableComponent)]
+pub struct ModelProperties {
+    pub custom_properties: Vec<Property>,
+    pub next_id: u64,
+}
+
+
 impl ModelProperties {
+    /// Creates a new [ModelProperties]
     pub fn new() -> Self {
         Self {
             custom_properties: Vec::new(),
@@ -806,6 +259,10 @@ impl ModelProperties {
         }
     }
 
+    /// Sets the property based on the [Value] (type) and its key.
+    ///
+    /// If the value does NOT exist, it will be created.
+    /// If the value does exist, it will replace the contents of that item.
     pub fn set_property(&mut self, key: String, value: Value) {
         if let Some(prop) = self.custom_properties.iter_mut().find(|p| p.key == key) {
             prop.value = value;
@@ -819,6 +276,7 @@ impl ModelProperties {
         }
     }
 
+    /// Fetches the property by its key.
     pub fn get_property(&self, key: &str) -> Option<&Value> {
         self.custom_properties
             .iter()
@@ -826,6 +284,7 @@ impl ModelProperties {
             .map(|p| &p.value)
     }
 
+    /// Fetches the float property
     pub fn get_float(&self, key: &str) -> Option<f64> {
         match self.get_property(key)? {
             Value::Float(f) => Some(*f),
@@ -833,6 +292,7 @@ impl ModelProperties {
         }
     }
 
+    /// Fetches the integer property
     pub fn get_int(&self, key: &str) -> Option<i64> {
         match self.get_property(key)? {
             Value::Int(i) => Some(*i),
@@ -840,6 +300,9 @@ impl ModelProperties {
         }
     }
 
+    /// Creates a new property based on a key and a value.
+    ///
+    /// It will push that value again to the property vector.
     pub fn add_property(&mut self, key: String, value: Value) {
         self.custom_properties.push(Property {
             id: self.next_id,
@@ -849,6 +312,7 @@ impl ModelProperties {
         self.next_id += 1;
     }
 
+    /// Shows a template of the different values when inspected as a component in the editor.
     pub fn show_value_editor(ui: &mut Ui, value: &mut Value) -> bool {
         match value {
             Value::String(s) => ui.text_edit_singleline(s).changed(),
@@ -896,6 +360,7 @@ impl Default for ModelProperties {
     }
 }
 
+// A serializable configuration struct for the [Light] type
 #[derive(Debug, Serialize, Deserialize, Clone, SerializableComponent)]
 pub struct LightConfig {
     pub label: String,
@@ -919,6 +384,7 @@ impl Default for LightConfig {
     }
 }
 
+/// Describes the settings of the editor, not the project or the scene.
 #[derive(Debug, Serialize, Deserialize, Clone, Default)]
 pub struct EditorSettings {
     pub is_debug_menu_shown: bool,
@@ -1050,8 +516,20 @@ impl DerefMut for Label {
     }
 }
 
+/// A [MeshRenderer] that is serialized into a file to be stored as a value for config. 
 #[derive(Default, Debug, Clone, Serialize, Deserialize, SerializableComponent)]
 pub struct SerializedMeshRenderer {
     pub handle: ResourceReference,
     pub material_override: Vec<MaterialOverride>,
+}
+
+impl SerializedMeshRenderer {
+    /// Creates a new [SerializedMeshRenderer] from an existing [MeshRenderer] by cloning data. 
+    pub fn from_renderer(renderer: &MeshRenderer) -> Self {
+        let handle = renderer.handle();
+        Self {
+            handle: handle.path.clone(),
+            material_override: renderer.material_overrides.clone(),
+        }
+    }
 }
\ No newline at end of file
diff --git a/eucalyptus-editor/Cargo.toml b/eucalyptus-editor/Cargo.toml
index 1c1a5b2..d6c9258 100644
--- a/eucalyptus-editor/Cargo.toml
+++ b/eucalyptus-editor/Cargo.toml
@@ -9,6 +9,7 @@ readme = "README.md"
 
 [dependencies]
 eucalyptus-core = { path = "../eucalyptus-core", features = ["editor"] }
+
 anyhow.workspace = true
 app_dirs2.workspace = true
 bincode.workspace = true
@@ -44,6 +45,7 @@ memory-stats.workspace = true
 env_logger.workspace = true
 colored.workspace = true
 chrono.workspace = true
+egui_ltreeview.workspace = true
 
 [target.'cfg(not(target_os = "android"))'.dependencies]
 rfd.workspace = true
@@ -53,6 +55,6 @@ default = ["editor"]
 editor = ["eucalyptus-core/editor"]
 
 [build-dependencies]
-anyhow = "1.0"
-app_dirs2 = "2.5"
-zip = "4.3"
+anyhow.workspace = true
+app_dirs2.workspace = true
+zip.workspace = true
diff --git a/eucalyptus-editor/src/build.rs b/eucalyptus-editor/src/build.rs
index 067a42b..2a4ac56 100644
--- a/eucalyptus-editor/src/build.rs
+++ b/eucalyptus-editor/src/build.rs
@@ -2,8 +2,8 @@ use clap::ArgMatches;
 use std::path::Path;
 use std::{collections::HashMap, fs, path::PathBuf, process::Command};
 use zip::write::SimpleFileOptions;
-
-use eucalyptus_core::states::{ProjectConfig, RuntimeData, SCENES, SOURCE};
+use eucalyptus_core::config::ProjectConfig;
+use eucalyptus_core::states::{RuntimeData, SCENES, SOURCE};
 
 pub fn package(project_path: PathBuf, _sub_matches: &ArgMatches) -> anyhow::Result<()> {
     if !project_path.exists() {
diff --git a/eucalyptus-editor/src/camera.rs b/eucalyptus-editor/src/camera.rs
index 58c95cc..374dfa7 100644
--- a/eucalyptus-editor/src/camera.rs
+++ b/eucalyptus-editor/src/camera.rs
@@ -1,5 +1,5 @@
 use crate::editor::component::InspectableComponent;
-use crate::editor::{EntityType, Signal, StaticallyKept, UndoableAction};
+use crate::editor::{Signal, StaticallyKept, UndoableAction};
 use dropbear_engine::camera::Camera;
 use egui::{CollapsingHeader, Ui};
 use eucalyptus_core::camera::{CameraComponent, CameraType};
@@ -38,7 +38,7 @@ impl InspectableComponent for Camera {
                                     if let Some(orig) = cfg.label_original.take() {
                                         UndoableAction::push_to_undo(
                                             undo_stack,
-                                            UndoableAction::Label(ent, orig, EntityType::Entity),
+                                            UndoableAction::Label(ent, orig),
                                         );
                                         log::debug!("Pushed camera label change to undo stack");
                                     }
diff --git a/eucalyptus-editor/src/editor/component.rs b/eucalyptus-editor/src/editor/component.rs
index 6bd2da6..995f5d9 100644
--- a/eucalyptus-editor/src/editor/component.rs
+++ b/eucalyptus-editor/src/editor/component.rs
@@ -1,9 +1,9 @@
 //! This module should describe the different components that are editable in the resource inspector.
 
-use crate::editor::{EntityType, Signal, StaticallyKept, UndoableAction};
+use crate::editor::{Signal, StaticallyKept, UndoableAction};
 use dropbear_engine::asset::{ASSET_REGISTRY, AssetHandle};
 use dropbear_engine::attenuation::ATTENUATION_PRESETS;
-use dropbear_engine::entity::{MeshRenderer, Transform};
+use dropbear_engine::entity::{EntityTransform, MeshRenderer, Transform};
 use dropbear_engine::graphics::NO_TEXTURE;
 use dropbear_engine::lighting::{Light, LightComponent, LightType};
 use dropbear_engine::utils::ResourceReference;
@@ -206,6 +206,21 @@ impl InspectableComponent for ModelProperties {
     }
 }
 
+impl InspectableComponent for EntityTransform {
+    fn inspect(
+        &mut self,
+        entity: &mut Entity,
+        cfg: &mut StaticallyKept,
+        ui: &mut Ui,
+        undo_stack: &mut Vec<UndoableAction>,
+        signal: &mut Signal,
+        _label: &mut String
+    ) {
+        self.local_mut().inspect(entity, cfg, ui, undo_stack, signal, &mut "Local Transform".to_string());
+        self.world_mut().inspect(entity, cfg, ui, undo_stack, signal, &mut "World Transform".to_string());
+    }
+}
+
 impl InspectableComponent for Transform {
     fn inspect(
         &mut self,
@@ -214,380 +229,388 @@ impl InspectableComponent for Transform {
         ui: &mut Ui,
         undo_stack: &mut Vec<UndoableAction>,
         _signal: &mut Signal,
-        _label: &mut String,
+        label: &mut String,
     ) {
         ui.vertical(|ui| {
-            CollapsingHeader::new("Transform")
+            CollapsingHeader::new(label.clone())
                 .default_open(true)
                 .show(ui, |ui| {
                     ui.horizontal(|ui| {
                         ui.label("Position:");
                     });
 
-                    ui.horizontal(|ui| {
-                        ui.label("X:");
-                        let response = ui.add(
-                            egui::DragValue::new(&mut self.position.x)
-                                .speed(0.1)
-                                .fixed_decimals(3),
-                        );
+                    ui.horizontal_wrapped(|ui| {
+                        ui.horizontal(|ui| {
+                            ui.label("X:");
+                            let response = ui.add(
+                                egui::DragValue::new(&mut self.position.x)
+                                    .speed(0.1)
+                                    .fixed_decimals(3),
+                            );
 
-                        if response.drag_started() {
-                            cfg.transform_old_entity = Some(*entity);
-                            cfg.transform_original_transform = Some(*self);
-                            cfg.transform_in_progress = true;
-                        }
+                            if response.drag_started() {
+                                cfg.transform_old_entity = Some(*entity);
+                                cfg.transform_original_transform = Some(*self);
+                                cfg.transform_in_progress = true;
+                            }
 
-                        if response.drag_stopped() && cfg.transform_in_progress {
-                            if let Some(ent) = cfg.transform_old_entity.take()
-                                && let Some(orig) = cfg.transform_original_transform.take()
-                            {
-                                UndoableAction::push_to_undo(
-                                    undo_stack,
-                                    UndoableAction::Transform(ent, orig),
-                                );
-                                log::debug!("Pushed X transform change to undo stack");
+                            if response.drag_stopped() && cfg.transform_in_progress {
+                                if let Some(ent) = cfg.transform_old_entity.take()
+                                    && let Some(orig) = cfg.transform_original_transform.take()
+                                {
+                                    UndoableAction::push_to_undo(
+                                        undo_stack,
+                                        UndoableAction::Transform(ent, orig),
+                                    );
+                                    log::debug!("Pushed X transform change to undo stack");
+                                }
+                                cfg.transform_in_progress = false;
                             }
-                            cfg.transform_in_progress = false;
-                        }
-                    });
-                    ui.horizontal(|ui| {
-                        ui.label("Y:");
-                        let response = ui.add(
-                            egui::DragValue::new(&mut self.position.y)
-                                .speed(0.1)
-                                .fixed_decimals(3),
-                        );
+                        });
+                        ui.horizontal(|ui| {
+                            ui.label("Y:");
+                            let response = ui.add(
+                                egui::DragValue::new(&mut self.position.y)
+                                    .speed(0.1)
+                                    .fixed_decimals(3),
+                            );
 
-                        if response.drag_started() {
-                            cfg.transform_old_entity = Some(*entity);
-                            cfg.transform_original_transform = Some(*self);
-                            cfg.transform_in_progress = true;
-                        }
+                            if response.drag_started() {
+                                cfg.transform_old_entity = Some(*entity);
+                                cfg.transform_original_transform = Some(*self);
+                                cfg.transform_in_progress = true;
+                            }
 
-                        if response.drag_stopped() && cfg.transform_in_progress {
-                            if let Some(ent) = cfg.transform_old_entity.take()
-                                && let Some(orig) = cfg.transform_original_transform.take()
-                            {
-                                UndoableAction::push_to_undo(
-                                    undo_stack,
-                                    UndoableAction::Transform(ent, orig),
-                                );
-                                log::debug!("Pushed Y transform change to undo stack");
+                            if response.drag_stopped() && cfg.transform_in_progress {
+                                if let Some(ent) = cfg.transform_old_entity.take()
+                                    && let Some(orig) = cfg.transform_original_transform.take()
+                                {
+                                    UndoableAction::push_to_undo(
+                                        undo_stack,
+                                        UndoableAction::Transform(ent, orig),
+                                    );
+                                    log::debug!("Pushed Y transform change to undo stack");
+                                }
+                                cfg.transform_in_progress = false;
                             }
-                            cfg.transform_in_progress = false;
-                        }
-                    });
+                        });
 
-                    ui.horizontal(|ui| {
-                        ui.label("Z:");
-                        let response = ui.add(
-                            egui::DragValue::new(&mut self.position.z)
-                                .speed(0.1)
-                                .fixed_decimals(3),
-                        );
+                        ui.horizontal(|ui| {
+                            ui.label("Z:");
+                            let response = ui.add(
+                                egui::DragValue::new(&mut self.position.z)
+                                    .speed(0.1)
+                                    .fixed_decimals(3),
+                            );
 
-                        if response.drag_started() {
-                            cfg.transform_old_entity = Some(*entity);
-                            cfg.transform_original_transform = Some(*self);
-                            cfg.transform_in_progress = true;
-                        }
+                            if response.drag_started() {
+                                cfg.transform_old_entity = Some(*entity);
+                                cfg.transform_original_transform = Some(*self);
+                                cfg.transform_in_progress = true;
+                            }
 
-                        if response.drag_stopped() && cfg.transform_in_progress {
-                            if let Some(ent) = cfg.transform_old_entity.take()
-                                && let Some(orig) = cfg.transform_original_transform.take()
-                            {
-                                UndoableAction::push_to_undo(
-                                    undo_stack,
-                                    UndoableAction::Transform(ent, orig),
-                                );
-                                log::debug!("Pushed Z transform change to undo stack");
+                            if response.drag_stopped() && cfg.transform_in_progress {
+                                if let Some(ent) = cfg.transform_old_entity.take()
+                                    && let Some(orig) = cfg.transform_original_transform.take()
+                                {
+                                    UndoableAction::push_to_undo(
+                                        undo_stack,
+                                        UndoableAction::Transform(ent, orig),
+                                    );
+                                    log::debug!("Pushed Z transform change to undo stack");
+                                }
+                                cfg.transform_in_progress = false;
                             }
-                            cfg.transform_in_progress = false;
-                        }
+                        });
                     });
+
                     if ui.button("Reset Position").clicked() {
-                        self.position = glam::DVec3::ZERO;
+                        self.position = DVec3::ZERO;
                     }
 
                     ui.add_space(5.0);
 
-                    ui.horizontal(|ui| {
-                        ui.label("Rotation:");
-                    });
+                    ui.horizontal_wrapped(|ui| {
+                        ui.horizontal(|ui| {
+                            ui.label("Rotation:");
+                        });
 
-                    let cached_rotation = cfg.transform_rotation_cache.get(entity).copied();
+                        let cached_rotation = cfg.transform_rotation_cache.get(entity).copied();
 
-                    let mut rotation_deg: DVec3 = if cfg.transform_in_progress {
-                        cached_rotation.unwrap_or_else(|| {
+                        let mut rotation_deg: DVec3 = if cfg.transform_in_progress {
+                            cached_rotation.unwrap_or_else(|| {
+                                let (x, y, z) = self.rotation.to_euler(glam::EulerRot::YXZ);
+                                DVec3::new(x.to_degrees(), y.to_degrees(), z.to_degrees())
+                            })
+                        } else {
                             let (x, y, z) = self.rotation.to_euler(glam::EulerRot::YXZ);
-                            DVec3::new(x.to_degrees(), y.to_degrees(), z.to_degrees())
-                        })
-                    } else {
-                        let (x, y, z) = self.rotation.to_euler(glam::EulerRot::YXZ);
-                        let mut degrees =
-                            DVec3::new(x.to_degrees(), y.to_degrees(), z.to_degrees());
-
-                        if let Some(prev) = cached_rotation {
-                            degrees.x = reconcile_angle(degrees.x, prev.x);
-                            degrees.y = reconcile_angle(degrees.y, prev.y);
-                            degrees.z = reconcile_angle(degrees.z, prev.z);
-                        }
+                            let mut degrees =
+                                DVec3::new(x.to_degrees(), y.to_degrees(), z.to_degrees());
 
-                        degrees.x = wrap_angle_degrees(degrees.x);
-                        degrees.y = wrap_angle_degrees(degrees.y);
-                        degrees.z = wrap_angle_degrees(degrees.z);
+                            if let Some(prev) = cached_rotation {
+                                degrees.x = reconcile_angle(degrees.x, prev.x);
+                                degrees.y = reconcile_angle(degrees.y, prev.y);
+                                degrees.z = reconcile_angle(degrees.z, prev.z);
+                            }
 
-                        cfg.transform_rotation_cache.insert(*entity, degrees);
-                        degrees
-                    };
+                            degrees.x = wrap_angle_degrees(degrees.x);
+                            degrees.y = wrap_angle_degrees(degrees.y);
+                            degrees.z = wrap_angle_degrees(degrees.z);
 
-                    let mut rotation_changed = false;
+                            cfg.transform_rotation_cache.insert(*entity, degrees);
+                            degrees
+                        };
 
-                    ui.horizontal(|ui| {
-                        ui.label("X:");
-                        let response = ui.add(
-                            egui::DragValue::new(&mut rotation_deg.x)
-                                .speed(0.5)
-                                .suffix("°")
-                                .range(-180.0..=180.0)
-                                .fixed_decimals(2),
-                        );
+                        let mut rotation_changed = false;
 
-                        if response.drag_started() {
-                            cfg.transform_old_entity = Some(*entity);
-                            cfg.transform_original_transform = Some(*self);
-                            cfg.transform_in_progress = true;
-                        }
+                        ui.horizontal(|ui| {
+                            ui.label("Pitch (X):");
+                            let response = ui.add(
+                                egui::DragValue::new(&mut rotation_deg.x)
+                                    .speed(0.5)
+                                    .suffix("°")
+                                    .range(-180.0..=180.0)
+                                    .fixed_decimals(2),
+                            );
 
-                        if response.changed() {
-                            rotation_changed = true;
-                        }
+                            if response.drag_started() {
+                                cfg.transform_old_entity = Some(*entity);
+                                cfg.transform_original_transform = Some(*self);
+                                cfg.transform_in_progress = true;
+                            }
 
-                        if response.drag_stopped() && cfg.transform_in_progress {
-                            if let Some(ent) = cfg.transform_old_entity.take()
-                                && let Some(orig) = cfg.transform_original_transform.take()
-                            {
-                                UndoableAction::push_to_undo(
-                                    undo_stack,
-                                    UndoableAction::Transform(ent, orig),
-                                );
-                                log::debug!("Pushed X rotation change to undo stack");
+                            if response.changed() {
+                                rotation_changed = true;
                             }
-                            cfg.transform_in_progress = false;
-                        }
-                    });
 
-                    ui.horizontal(|ui| {
-                        ui.label("Y:");
-                        let response = ui.add(
-                            egui::DragValue::new(&mut rotation_deg.y)
-                                .speed(0.5)
-                                .suffix("°")
-                                .range(-180.0..=180.0)
-                                .fixed_decimals(2),
-                        );
+                            if response.drag_stopped() && cfg.transform_in_progress {
+                                if let Some(ent) = cfg.transform_old_entity.take()
+                                    && let Some(orig) = cfg.transform_original_transform.take()
+                                {
+                                    UndoableAction::push_to_undo(
+                                        undo_stack,
+                                        UndoableAction::Transform(ent, orig),
+                                    );
+                                    log::debug!("Pushed X rotation change to undo stack");
+                                }
+                                cfg.transform_in_progress = false;
+                            }
+                        });
 
-                        if response.drag_started() {
-                            cfg.transform_old_entity = Some(*entity);
-                            cfg.transform_original_transform = Some(*self);
-                            cfg.transform_in_progress = true;
-                        }
+                        ui.horizontal(|ui| {
+                            ui.label("Yaw (Y):");
+                            let response = ui.add(
+                                egui::DragValue::new(&mut rotation_deg.y)
+                                    .speed(0.5)
+                                    .suffix("°")
+                                    .range(-180.0..=180.0)
+                                    .fixed_decimals(2),
+                            );
 
-                        if response.changed() {
-                            rotation_changed = true;
-                        }
+                            if response.drag_started() {
+                                cfg.transform_old_entity = Some(*entity);
+                                cfg.transform_original_transform = Some(*self);
+                                cfg.transform_in_progress = true;
+                            }
 
-                        if response.drag_stopped() && cfg.transform_in_progress {
-                            if let Some(ent) = cfg.transform_old_entity.take()
-                                && let Some(orig) = cfg.transform_original_transform.take()
-                            {
-                                UndoableAction::push_to_undo(
-                                    undo_stack,
-                                    UndoableAction::Transform(ent, orig),
-                                );
-                                log::debug!("Pushed Y rotation change to undo stack");
+                            if response.changed() {
+                                rotation_changed = true;
                             }
-                            cfg.transform_in_progress = false;
-                        }
-                    });
 
-                    ui.horizontal(|ui| {
-                        ui.label("Z:");
-                        let response = ui.add(
-                            egui::DragValue::new(&mut rotation_deg.z)
-                                .speed(0.5)
-                                .suffix("°")
-                                .range(-180.0..=180.0)
-                                .fixed_decimals(2),
-                        );
+                            if response.drag_stopped() && cfg.transform_in_progress {
+                                if let Some(ent) = cfg.transform_old_entity.take()
+                                    && let Some(orig) = cfg.transform_original_transform.take()
+                                {
+                                    UndoableAction::push_to_undo(
+                                        undo_stack,
+                                        UndoableAction::Transform(ent, orig),
+                                    );
+                                    log::debug!("Pushed Y rotation change to undo stack");
+                                }
+                                cfg.transform_in_progress = false;
+                            }
+                        });
 
-                        if response.drag_started() {
-                            cfg.transform_old_entity = Some(*entity);
-                            cfg.transform_original_transform = Some(*self);
-                            cfg.transform_in_progress = true;
-                        }
+                        ui.horizontal(|ui| {
+                            ui.label("Roll (Z):");
+                            let response = ui.add(
+                                egui::DragValue::new(&mut rotation_deg.z)
+                                    .speed(0.5)
+                                    .suffix("°")
+                                    .range(-180.0..=180.0)
+                                    .fixed_decimals(2),
+                            );
 
-                        if response.changed() {
-                            rotation_changed = true;
-                        }
+                            if response.drag_started() {
+                                cfg.transform_old_entity = Some(*entity);
+                                cfg.transform_original_transform = Some(*self);
+                                cfg.transform_in_progress = true;
+                            }
 
-                        if response.drag_stopped() && cfg.transform_in_progress {
-                            if let Some(ent) = cfg.transform_old_entity.take()
-                                && let Some(orig) = cfg.transform_original_transform.take()
-                            {
-                                UndoableAction::push_to_undo(
-                                    undo_stack,
-                                    UndoableAction::Transform(ent, orig),
-                                );
-                                log::debug!("Pushed Z rotation change to undo stack");
+                            if response.changed() {
+                                rotation_changed = true;
+                            }
+
+                            if response.drag_stopped() && cfg.transform_in_progress {
+                                if let Some(ent) = cfg.transform_old_entity.take()
+                                    && let Some(orig) = cfg.transform_original_transform.take()
+                                {
+                                    UndoableAction::push_to_undo(
+                                        undo_stack,
+                                        UndoableAction::Transform(ent, orig),
+                                    );
+                                    log::debug!("Pushed Z rotation change to undo stack");
+                                }
+                                cfg.transform_in_progress = false;
                             }
-                            cfg.transform_in_progress = false;
+                        });
+
+                        if rotation_changed {
+                            rotation_deg.x = wrap_angle_degrees(rotation_deg.x);
+                            rotation_deg.y = wrap_angle_degrees(rotation_deg.y);
+                            rotation_deg.z = wrap_angle_degrees(rotation_deg.z);
+
+                            cfg.transform_rotation_cache.insert(*entity, rotation_deg);
+                            self.rotation = glam::DQuat::from_euler(
+                                glam::EulerRot::YXZ,
+                                rotation_deg.x.to_radians(),
+                                rotation_deg.y.to_radians(),
+                                rotation_deg.z.to_radians(),
+                            );
                         }
                     });
 
-                    if rotation_changed {
-                        rotation_deg.x = wrap_angle_degrees(rotation_deg.x);
-                        rotation_deg.y = wrap_angle_degrees(rotation_deg.y);
-                        rotation_deg.z = wrap_angle_degrees(rotation_deg.z);
-
-                        cfg.transform_rotation_cache.insert(*entity, rotation_deg);
-                        self.rotation = glam::DQuat::from_euler(
-                            glam::EulerRot::YXZ,
-                            rotation_deg.x.to_radians(),
-                            rotation_deg.y.to_radians(),
-                            rotation_deg.z.to_radians(),
-                        );
-                    }
                     if ui.button("Reset Rotation").clicked() {
                         self.rotation = glam::DQuat::IDENTITY;
                         cfg.transform_rotation_cache.insert(*entity, DVec3::ZERO);
                     }
                     ui.add_space(5.0);
 
-                    ui.horizontal(|ui| {
-                        ui.label("Scale:");
-                        ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
-                            let lock_icon = if cfg.scale_locked { "🔒" } else { "🔓" };
-                            if ui
-                                .button(lock_icon)
-                                .on_hover_text("Lock uniform scaling")
-                                .clicked()
-                            {
-                                cfg.scale_locked = !cfg.scale_locked;
-                            }
+                    ui.horizontal_wrapped(|ui| {
+                        ui.horizontal(|ui| {
+                            ui.label("Scale:");
+                            ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
+                                let lock_icon = if cfg.scale_locked { "🔒" } else { "🔓" };
+                                if ui
+                                    .button(lock_icon)
+                                    .on_hover_text("Lock uniform scaling")
+                                    .clicked()
+                                {
+                                    cfg.scale_locked = !cfg.scale_locked;
+                                }
+                            });
                         });
-                    });
 
-                    let mut scale_changed = false;
-                    let mut new_scale = self.scale;
+                        let mut scale_changed = false;
+                        let mut new_scale = self.scale;
 
-                    ui.horizontal(|ui| {
-                        ui.label("X:");
-                        let response = ui.add(
-                            egui::DragValue::new(&mut new_scale.x)
-                                .speed(0.01)
-                                .fixed_decimals(3),
-                        );
+                        ui.horizontal(|ui| {
+                            ui.label("X:");
+                            let response = ui.add(
+                                DragValue::new(&mut new_scale.x)
+                                    .speed(0.01)
+                                    .fixed_decimals(3),
+                            );
 
-                        if response.drag_started() {
-                            cfg.transform_old_entity = Some(*entity);
-                            cfg.transform_original_transform = Some(*self);
-                            cfg.transform_in_progress = true;
-                        }
+                            if response.drag_started() {
+                                cfg.transform_old_entity = Some(*entity);
+                                cfg.transform_original_transform = Some(*self);
+                                cfg.transform_in_progress = true;
+                            }
 
-                        if response.changed() {
-                            scale_changed = true;
-                            if cfg.scale_locked {
-                                let scale_factor = new_scale.x / self.scale.x;
-                                new_scale.y = self.scale.y * scale_factor;
-                                new_scale.z = self.scale.z * scale_factor;
+                            if response.changed() {
+                                scale_changed = true;
+                                if cfg.scale_locked {
+                                    let scale_factor = new_scale.x / self.scale.x;
+                                    new_scale.y = self.scale.y * scale_factor;
+                                    new_scale.z = self.scale.z * scale_factor;
+                                }
                             }
-                        }
 
-                        if response.drag_stopped() && cfg.transform_in_progress {
-                            if let Some(ent) = cfg.transform_old_entity.take()
-                                && let Some(orig) = cfg.transform_original_transform.take()
-                            {
-                                UndoableAction::push_to_undo(
-                                    undo_stack,
-                                    UndoableAction::Transform(ent, orig),
-                                );
-                                log::debug!("Pushed X scale change to undo stack");
+                            if response.drag_stopped() && cfg.transform_in_progress {
+                                if let Some(ent) = cfg.transform_old_entity.take()
+                                    && let Some(orig) = cfg.transform_original_transform.take()
+                                {
+                                    UndoableAction::push_to_undo(
+                                        undo_stack,
+                                        UndoableAction::Transform(ent, orig),
+                                    );
+                                    log::debug!("Pushed X scale change to undo stack");
+                                }
+                                cfg.transform_in_progress = false;
                             }
-                            cfg.transform_in_progress = false;
-                        }
-                    });
+                        });
 
-                    ui.horizontal(|ui| {
-                        ui.label("Y:");
-                        let y_slider = egui::DragValue::new(&mut new_scale.y)
-                            .speed(0.01)
-                            .fixed_decimals(3);
+                        ui.horizontal(|ui| {
+                            ui.label("Y:");
+                            let y_slider = egui::DragValue::new(&mut new_scale.y)
+                                .speed(0.01)
+                                .fixed_decimals(3);
 
-                        let response = ui.add_enabled(!cfg.scale_locked, y_slider);
+                            let response = ui.add_enabled(!cfg.scale_locked, y_slider);
 
-                        if response.drag_started() && !cfg.scale_locked {
-                            cfg.transform_old_entity = Some(*entity);
-                            cfg.transform_original_transform = Some(*self);
-                            cfg.transform_in_progress = true;
-                        }
+                            if response.drag_started() && !cfg.scale_locked {
+                                cfg.transform_old_entity = Some(*entity);
+                                cfg.transform_original_transform = Some(*self);
+                                cfg.transform_in_progress = true;
+                            }
 
-                        if response.changed() {
-                            scale_changed = true;
-                        }
+                            if response.changed() {
+                                scale_changed = true;
+                            }
 
-                        if response.drag_stopped() && cfg.transform_in_progress {
-                            if let Some(ent) = cfg.transform_old_entity.take()
-                                && let Some(orig) = cfg.transform_original_transform.take()
-                            {
-                                UndoableAction::push_to_undo(
-                                    undo_stack,
-                                    UndoableAction::Transform(ent, orig),
-                                );
-                                log::debug!("Pushed Y scale change to undo stack");
+                            if response.drag_stopped() && cfg.transform_in_progress {
+                                if let Some(ent) = cfg.transform_old_entity.take()
+                                    && let Some(orig) = cfg.transform_original_transform.take()
+                                {
+                                    UndoableAction::push_to_undo(
+                                        undo_stack,
+                                        UndoableAction::Transform(ent, orig),
+                                    );
+                                    log::debug!("Pushed Y scale change to undo stack");
+                                }
+                                cfg.transform_in_progress = false;
                             }
-                            cfg.transform_in_progress = false;
-                        }
-                    });
+                        });
 
-                    ui.horizontal(|ui| {
-                        ui.label("Z:");
-                        let z_slider = egui::DragValue::new(&mut new_scale.z)
-                            .speed(0.01)
-                            .fixed_decimals(3);
+                        ui.horizontal(|ui| {
+                            ui.label("Z:");
+                            let z_slider = egui::DragValue::new(&mut new_scale.z)
+                                .speed(0.01)
+                                .fixed_decimals(3);
 
-                        let response = ui.add_enabled(!cfg.scale_locked, z_slider);
+                            let response = ui.add_enabled(!cfg.scale_locked, z_slider);
 
-                        if response.drag_started() && !cfg.scale_locked {
-                            cfg.transform_old_entity = Some(*entity);
-                            cfg.transform_original_transform = Some(*self);
-                            cfg.transform_in_progress = true;
-                        }
+                            if response.drag_started() && !cfg.scale_locked {
+                                cfg.transform_old_entity = Some(*entity);
+                                cfg.transform_original_transform = Some(*self);
+                                cfg.transform_in_progress = true;
+                            }
 
-                        if response.changed() {
-                            scale_changed = true;
-                        }
+                            if response.changed() {
+                                scale_changed = true;
+                            }
 
-                        if response.drag_stopped() && cfg.transform_in_progress {
-                            if let Some(ent) = cfg.transform_old_entity.take()
-                                && let Some(orig) = cfg.transform_original_transform.take()
-                            {
-                                UndoableAction::push_to_undo(
-                                    undo_stack,
-                                    UndoableAction::Transform(ent, orig),
-                                );
-                                log::debug!("Pushed Z scale change to undo stack");
+                            if response.drag_stopped() && cfg.transform_in_progress {
+                                if let Some(ent) = cfg.transform_old_entity.take()
+                                    && let Some(orig) = cfg.transform_original_transform.take()
+                                {
+                                    UndoableAction::push_to_undo(
+                                        undo_stack,
+                                        UndoableAction::Transform(ent, orig),
+                                    );
+                                    log::debug!("Pushed Z scale change to undo stack");
+                                }
+                                cfg.transform_in_progress = false;
                             }
-                            cfg.transform_in_progress = false;
+                        });
+
+                        if scale_changed {
+                            self.scale = new_scale;
                         }
                     });
-
-                    if scale_changed {
-                        self.scale = new_scale;
-                    }
                     if ui.button("Reset Scale").clicked() {
-                        self.scale = glam::DVec3::ONE;
+                        self.scale = DVec3::ONE;
                     }
                     ui.add_space(5.0);
                 });
@@ -669,7 +692,7 @@ impl InspectableComponent for MeshRenderer {
                             if let Some(orig) = cfg.label_original.take() {
                                 UndoableAction::push_to_undo(
                                     undo_stack,
-                                    UndoableAction::Label(ent, orig, EntityType::Entity),
+                                    UndoableAction::Label(ent, orig),
                                 );
                                 log::debug!("Pushed label change to undo stack (immediate)");
                             }
@@ -997,7 +1020,7 @@ impl InspectableComponent for Light {
                             if let Some(orig) = cfg.label_original.take() {
                                 UndoableAction::push_to_undo(
                                     undo_stack,
-                                    UndoableAction::Label(ent, orig, EntityType::Light),
+                                    UndoableAction::Label(ent, orig),
                                 );
                                 log::debug!("Pushed label change to undo stack (immediate)");
                             }
diff --git a/eucalyptus-editor/src/editor/dock.rs b/eucalyptus-editor/src/editor/dock.rs
index 0da165c..478db68 100644
--- a/eucalyptus-editor/src/editor/dock.rs
+++ b/eucalyptus-editor/src/editor/dock.rs
@@ -4,7 +4,7 @@ use crate::editor::{
     console_error::{ConsoleItem, ErrorLevel},
 };
 use std::{
-    collections::{HashMap, HashSet},
+    collections::{HashMap},
     path::PathBuf,
     sync::LazyLock,
 };
@@ -18,17 +18,14 @@ use dropbear_engine::{
 };
 use egui::{self, CollapsingHeader, Margin, RichText};
 use egui_dock::TabViewer;
-use egui_extras;
-use eucalyptus_core::spawn::{PendingSpawn, push_pending_spawn};
-use eucalyptus_core::states::{File, Label, Node, RESOURCES, ResourceType};
-use eucalyptus_core::{APP_INFO, utils::ResolveReference};
+use indexmap::Equivalent;
+use eucalyptus_core::states::{Label};
 use log;
 use parking_lot::Mutex;
-use transform_gizmo_egui::{EnumSet, Gizmo, GizmoConfig, GizmoExt, GizmoMode, math::DVec3};
+use transform_gizmo_egui::{EnumSet, Gizmo, GizmoConfig, GizmoExt, GizmoMode};
 
 pub struct EditorTabViewer<'a> {
     pub view: egui::TextureId,
-    pub nodes: Vec<EntityNode>,
     pub tex_size: Extent3d,
     pub gizmo: &'a mut Gizmo,
     pub world: &'a mut World,
@@ -45,40 +42,6 @@ pub struct EditorTabViewer<'a> {
     pub editor: *mut Editor,
 }
 
-impl<'a> EditorTabViewer<'a> {
-    fn spawn_entity_at_pos(
-        &mut self,
-        asset: &DraggedAsset,
-        position: DVec3,
-        properties: Option<ModelProperties>,
-    ) -> anyhow::Result<()> {
-        let transform = Transform {
-            position,
-            ..Default::default()
-        };
-        {
-            if let Some(props) = properties {
-                push_pending_spawn(PendingSpawn {
-                    asset_path: asset.path.clone(),
-                    asset_name: asset.name.clone(),
-                    transform,
-                    properties: props,
-                    handle: None,
-                });
-            } else {
-                push_pending_spawn(PendingSpawn {
-                    asset_path: asset.path.clone(),
-                    asset_name: asset.name.clone(),
-                    transform,
-                    properties: ModelProperties::default(),
-                    handle: None,
-                });
-            }
-            Ok(())
-        }
-    }
-}
-
 #[derive(Clone, Debug)]
 pub struct DraggedAsset {
     pub name: String,
@@ -202,181 +165,7 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                             .fit_to_exact_size([display_width, display_height].into()),
                     )
                 });
-
-                let image_response = ui.interact(
-                    image_rect,
-                    ui.id().with("viewport_image"),
-                    egui::Sense::click_and_drag(),
-                );
-
-                if image_response.clicked() {
-                    let active_cam = self.active_camera.lock();
-                    if let Some(active_camera) = *active_cam {
-                        {
-                            if let Ok(mut q) = self
-                                .world
-                                .query_one::<(&Camera, &CameraComponent)>(active_camera)
-                            {
-                                if let Some((camera, _)) = q.get() {
-                                    if let Some(click_pos) =
-                                        ui.ctx().input(|i| i.pointer.interact_pos())
-                                    {
-                                        let viewport_rect = image_response.rect;
-                                        let local_pos = click_pos - viewport_rect.min;
-
-                                        let ndc_x =
-                                            (2.0 * local_pos.x / viewport_rect.width()) - 1.0;
-                                        let ndc_y =
-                                            1.0 - (2.0 * local_pos.y / viewport_rect.height());
-
-                                        let view_matrix = glam::DMat4::look_at_lh(
-                                            camera.eye,
-                                            camera.target,
-                                            camera.up,
-                                        );
-
-                                        let proj_matrix = glam::DMat4::perspective_lh(
-                                            camera.settings.fov_y.to_radians(),
-                                            camera.aspect,
-                                            camera.znear,
-                                            camera.zfar,
-                                        );
-
-                                        if !view_matrix.is_finite() {
-                                            log::error!("Invalid view matrix");
-                                            return;
-                                        }
-                                        if !proj_matrix.is_finite() {
-                                            log::error!("Invalid projection matrix");
-                                            return;
-                                        }
-
-                                        let view_proj = proj_matrix * view_matrix;
-                                        let inv_view_proj = view_proj.inverse();
-
-                                        if !inv_view_proj.is_finite() {
-                                            log::error!("Cannot invert view-projection matrix");
-                                            return;
-                                        }
-
-                                        let ray_start_ndc =
-                                            glam::DVec4::new(ndc_x as f64, ndc_y as f64, 0.0, 1.0);
-                                        let ray_end_ndc =
-                                            glam::DVec4::new(ndc_x as f64, ndc_y as f64, 1.0, 1.0);
-
-                                        let ray_start_world = inv_view_proj * ray_start_ndc;
-                                        let ray_end_world = inv_view_proj * ray_end_ndc;
-
-                                        if ray_start_world.w == 0.0 || ray_end_world.w == 0.0 {
-                                            log::error!("Invalid homogeneous coordinates");
-                                            return;
-                                        }
-
-                                        let ray_start =
-                                            ray_start_world.truncate() / ray_start_world.w;
-                                        let ray_end = ray_end_world.truncate() / ray_end_world.w;
-
-                                        if !ray_start.is_finite() || !ray_end.is_finite() {
-                                            log::error!(
-                                                "Invalid ray points - start: {:?}, end: {:?}",
-                                                ray_start,
-                                                ray_end
-                                            );
-                                            return;
-                                        }
-
-                                        let ray_direction = (ray_end - ray_start).normalize();
-
-                                        if !ray_direction.is_finite() {
-                                            log::error!(
-                                                "Invalid ray direction: {:?}",
-                                                ray_direction
-                                            );
-                                            return;
-                                        }
-
-                                        let (selected_entity_id, entity_count) = {
-                                            let mut closest_distance = f64::INFINITY;
-                                            let mut selected_entity_id: Option<hecs::Entity> = None;
-                                            let mut entity_count = 0;
-
-                                            {
-                                                for (entity_id, (transform, _)) in self
-                                                    .world
-                                                    .query::<(&Transform, &MeshRenderer)>()
-                                                    .iter()
-                                                {
-                                                    entity_count += 1;
-                                                    let entity_pos = transform.position;
-                                                    let sphere_radius =
-                                                        transform.scale.max_element() * 1.5;
-                                                    let to_sphere = entity_pos - ray_start;
-                                                    let projection = to_sphere.dot(ray_direction);
-                                                    if projection > 0.0 {
-                                                        let closest_point =
-                                                            ray_start + ray_direction * projection;
-                                                        let distance_to_sphere =
-                                                            (closest_point - entity_pos).length();
-                                                        if distance_to_sphere <= sphere_radius {
-                                                            let discriminant = sphere_radius
-                                                                * sphere_radius
-                                                                - distance_to_sphere
-                                                                    * distance_to_sphere;
-                                                            if discriminant >= 0.0 {
-                                                                let intersection_distance =
-                                                                    projection
-                                                                        - discriminant.sqrt();
-                                                                if intersection_distance
-                                                                    < closest_distance
-                                                                {
-                                                                    closest_distance =
-                                                                        intersection_distance;
-                                                                    selected_entity_id =
-                                                                        Some(entity_id);
-                                                                }
-                                                            }
-                                                        }
-                                                    }
-                                                }
-                                            }
-
-                                            (selected_entity_id, entity_count)
-                                        };
-
-                                        log::debug!("Total entities checked: {}", entity_count);
-
-                                        if !matches!(self.editor_mode, EditorState::Playing) {
-                                            if let Some(entity_id) = selected_entity_id {
-                                                *self.selected_entity = Some(entity_id);
-                                                log::debug!("Selected entity: {:?}", entity_id);
-                                            } else if entity_count == 0 {
-                                                log::debug!("No entities in world to select");
-                                            } else {
-                                                log::debug!(
-                                                    "No entity hit by ray (checked {} entities)",
-                                                    entity_count
-                                                );
-                                            }
-                                        }
-                                    }
-                                } else {
-                                    log_once::warn_once!(
-                                        "Unable to fetch the query result of camera: {:?}",
-                                        active_camera
-                                    )
-                                }
-                            } else {
-                                log_once::warn_once!(
-                                    "Unable to query camera, component and option<camerafollowtarget> for active camera: {:?}",
-                                    active_camera
-                                );
-                            }
-                        }
-                    } else {
-                        log_once::warn_once!("No active camera found");
-                    }
-                }
-
+                
                 let snapping = ui.input(|input| input.modifiers.shift);
 
                 // Note to self: fuck you >:(
@@ -464,312 +253,49 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                 }
             }
             EditorTab::ModelEntityList => {
-                ui.label("Model/Entity List");
-                show_entity_tree(
-                    ui,
-                    &mut self.nodes,
-                    self.selected_entity,
-                    "Model Entity Asset List",
-                );
+                // todo: use egui_ltreeview to create a component graph
+                // egui_ltreeview::TreeView::new(egui::Id::new("model_entity_list")).show(ui, |builder| {
+                //     builder.dir()
+                //     // entity is entity.id()
+                //     // component is entity.id() * -100 *
+                // });
             }
             EditorTab::AssetViewer => {
-                egui_extras::install_image_loaders(ui.ctx());
-
-                let mut assets: Vec<(String, String, PathBuf, ResourceType)> = Vec::new();
-                {
-                    let res = RESOURCES.read();
-                    egui_extras::install_image_loaders(ui.ctx());
-
-                    fn recursive_search_nodes_and_attach_thumbnail(
-                        res: &Vec<Node>,
-                        assets: &mut Vec<(String, String, PathBuf, ResourceType)>,
-                        logged: &mut HashSet<String>,
-                    ) {
-                        for node in res {
-                            match node {
-                                Node::File(file) => {
-                                    match file {
-                                        File::Unknown => {}
-                                        File::ResourceFile {
-                                            name,
-                                            path,
-                                            resource_type,
-                                        } => {
-                                            if !logged.contains(name) {
-                                                logged.insert(name.clone());
-                                                log::debug!(
-                                                    "Adding image for {} of type {}",
-                                                    name,
-                                                    resource_type
-                                                );
-                                            }
-                                            match resource_type {
-                                                ResourceType::Model => {
-                                                    let ad_dir = app_dirs2::get_app_root(
-                                                        app_dirs2::AppDataType::UserData,
-                                                        &APP_INFO,
-                                                    )
-                                                    .unwrap();
-
-                                                    let model_thumbnail =
-                                                        ad_dir.join(format!("{}.png", name));
-
-                                                    if !model_thumbnail.exists() {
-                                                        // gen image
-                                                        log::debug!(
-                                                            "Model thumbnail [{}] does not exist, generating one now",
-                                                            name
-                                                        );
-                                                        let path = ResourceReference::from_path(
-                                                            path,
-                                                        ) // cuts off everything to the /resources folder
-                                                        .unwrap()
-                                                        .resolve() // resovles path to reference of resource
-                                                        .unwrap();
-                                                        let mut model = match model_to_image::ModelToImageBuilder::new(&path)
-                                                            .with_size((600, 600))
-                                                            .build() {
-                                                            Ok(v) => v,
-                                                            Err(e) => panic!("Error occurred while loading file from path: {}", e),
-                                                        };
-                                                        if let Err(e) =
-                                                            model.render().unwrap().write_to(Some(
-                                                                &ad_dir
-                                                                    .join(format!("{}.png", name)),
-                                                            ))
-                                                        {
-                                                            log::error!(
-                                                                "Failed to write model thumbnail for {}: {}",
-                                                                name,
-                                                                e
-                                                            );
-                                                        }
-                                                    }
-
-                                                    let image_uri = model_thumbnail
-                                                        .to_string_lossy()
-                                                        .to_string();
-
-                                                    assets.push((
-                                                        format!("file://{}", image_uri),
-                                                        name.clone(),
-                                                        path.clone(),
-                                                        resource_type.clone(),
-                                                    ))
-                                                }
-                                                ResourceType::Texture => assets.push((
-                                                    format!("file://{}", path.to_string_lossy()),
-                                                    name.clone(),
-                                                    path.clone(),
-                                                    resource_type.clone(),
-                                                )),
-                                                _ => {
-                                                    if path
-                                                        .clone()
-                                                        .extension()
-                                                        .unwrap()
-                                                        .to_str()
-                                                        .unwrap()
-                                                        .contains("euc")
-                                                    {
-                                                        continue;
-                                                    }
-                                                    assets.push((
-                                                        "NO_TEXTURE".into(),
-                                                        name.clone(),
-                                                        path.clone(),
-                                                        resource_type.clone(),
-                                                    ))
-                                                }
-                                            }
-                                        }
-                                        File::SourceFile { .. } => {}
-                                    }
-                                }
-                                Node::Folder(folder) => {
-                                    recursive_search_nodes_and_attach_thumbnail(
-                                        &folder.nodes,
-                                        assets,
-                                        logged,
-                                    )
-                                }
-                            }
-                        }
-                    }
-
-                    let mut logged = LOGGED.lock();
-                    recursive_search_nodes_and_attach_thumbnail(
-                        &res.nodes,
-                        &mut assets,
-                        &mut logged,
-                    );
-                }
-
-                egui::ScrollArea::vertical().show(ui, |ui| {
-                    let max_columns = 6;
-                    let available_width = ui.clip_rect().width() - ui.spacing().indent;
-                    let margin = 16.0;
-                    let usable_width = available_width - margin;
-                    let label_height = 20.0;
-                    let padding = 8.0;
-                    let min_card_width = 60.0;
-
-                    let mut columns = max_columns;
-                    for test_columns in (1..=max_columns).rev() {
-                        let card_width = usable_width / test_columns as f32;
-                        if card_width >= min_card_width {
-                            columns = test_columns;
-                            break;
-                        }
-                    }
-
-                    let card_width = usable_width / columns as f32;
-                    let image_size = (card_width - label_height - padding).max(32.0);
-                    let card_height = image_size + label_height + padding;
-
-                    for row_start in (0..assets.len()).step_by(columns) {
-                        let row_end = (row_start + columns).min(assets.len());
-                        let row_items = &mut assets[row_start..row_end];
-
-                        ui.horizontal(|ui| {
-                            ui.set_max_width(usable_width);
-
-                            egui_dnd::dnd(ui, format!("asset_row_{}", row_start / columns))
-                                .show_vec(
-                                    row_items,
-                                    |ui, (image, asset_name, asset_path, asset_type), handle, state| {
-                                        let card_size = egui::vec2(card_width, card_height);
-                                        handle.ui(ui, |ui| {
-                                            let (rect, card_response) = ui.allocate_exact_size(
-                                                card_size,
-                                                egui::Sense::click(),
-                                            );
-
-                                            let mut card_ui = ui.new_child(
-                                                egui::UiBuilder::new().max_rect(rect).layout(
-                                                    egui::Layout::top_down(egui::Align::Center),
-                                                ),
-                                            );
-
-                                            let image_response = card_ui.add_sized(
-                                                [image_size, image_size],
-                                                egui::Button::image(image.clone()).frame(false),
-                                            );
-
-                                            let is_hovered = card_response.hovered() || image_response.hovered() || state.dragged;
-                                            let is_d_clicked = card_response.double_clicked() || image_response.double_clicked();
-
-                                            if is_d_clicked
-                                                && matches!(asset_type, ResourceType::Model) {
-                                                    let mut spawn_position = DVec3::default();
-                                                    {
-                                                        let active_cam = self.active_camera.lock();
-                                                        if let Some(active_camera) = *active_cam {
-                                                            if let Ok(mut q) = self.world.query_one::<(&Camera, &CameraComponent)>(active_camera) {
-                                                                if let Some((camera, _)) = q.get() {
-                                                                    spawn_position = camera.eye;
-                                                                } else {
-                                                                    log_once::warn_once!("Unable to fetch the query result of camera: {:?}", active_camera)
-                                                                }
-                                                            } else {
-                                                                log_once::warn_once!("Unable to query camera, component and option<camerafollowtarget> for active camera: {:?}", active_camera);
-                                                            }
-                                                        } else {
-                                                            log_once::warn_once!("No active camera found");
-                                                        }
-                                                    }
-
-                                                    let asset = DraggedAsset {
-                                                        name: asset_name.clone(),
-                                                        path: ResourceReference::from_path(asset_path.clone()).unwrap_or_else(|_e| {
-                                                            log::warn!("Unable to create ResourceReference from path: {:?}", asset_path);
-                                                            Default::default()
-                                                        }),
-                                                    };
-
-                                                    match self.spawn_entity_at_pos(&asset, spawn_position, None) {
-                                                        Ok(()) => {
-                                                            log::debug!("double click spawned {} at camera pos {:?}",
-                                                                asset.name, spawn_position
-                                                            );
-
-                                                            success!("Pushing spawn \"{}\" at camera", asset.name);
-                                                        }
-                                                        Err(e) => {
-                                                            log::error!(
-                                                            "Failed to spawn {} at camera: {}",
-                                                            asset.name,
-                                                            e);
-
-                                                            fatal!("Failed to spawn {}: {}",
-                                                                        asset.name, e);
-                                                        }
-                                                    }
-                                                }
-
-                                            if is_hovered || state.dragged {
-                                                ui.painter().rect_filled(
-                                                    rect,
-                                                    6.0,
-                                                    if state.dragged {
-                                                        egui::Color32::from_rgb(80, 80, 100)
-                                                    } else {
-                                                        egui::Color32::from_rgb(60, 60, 80)
-                                                    },
-                                                );
-                                            }
-
-                                            card_ui.vertical_centered(|ui| {
-                                                ui.label(
-                                                    egui::RichText::new(asset_name.clone())
-                                                        .strong()
-                                                        .color(egui::Color32::WHITE),
-                                                );
-                                            });
-                                        });
-                                    },
-                                );
-                        });
-                        ui.add_space(8.0);
-                    }
-                });
+                // // todo: use egui_ltreeview to create a asset viewer
+                // egui_ltreeview::TreeView::new(egui::Id::new("asset_viewer")).show(ui, |builder| {
+                //
+                // });
             }
             EditorTab::ResourceInspector => {
                 if let Some(entity) = self.selected_entity {
                     let mut local_set_initial_camera = false;
                     if let Ok(mut q) = self.world.query_one::<(
                         &mut Label,
-                        &mut MeshRenderer,
-                        Option<&mut Transform>,
-                        Option<&mut ModelProperties>,
-                        Option<&mut ScriptComponent>,
-                        Option<&mut Camera>,
-                        Option<&mut CameraComponent>,
-                        // Option<&mut CameraFollowTarget>,
                     )>(*entity)
                     {
                         if let Some((
                             label,
-                            e,
-                            transform,
-                            _props,
-                            script,
-                            camera,
-                            camera_component,
-                            // follow_target,
                         )) = q.get()
                         {
-                            // entity
-                            e.inspect(
-                                entity,
-                                &mut cfg,
-                                ui,
-                                self.undo_stack,
-                                self.signal,
-                                label.as_mut_string(),
-                            );
-                            // transform
-                            if let Some(t) = transform {
+
+                            if let Ok(mut q) = self.world.query_one::<&mut MeshRenderer>(*entity)
+                                && let Some(e) = q.get()
+                            {
+                                // entity
+                                e.inspect(
+                                    entity,
+                                    &mut cfg,
+                                    ui,
+                                    self.undo_stack,
+                                    self.signal,
+                                    label.as_mut_string(),
+                                );
+                            }
+
+                            if let Ok(mut q) = self.world.query_one::<&mut EntityTransform>(*entity)
+                                && let Some(t) = q.get()
+                            {
+                                // transform
                                 t.inspect(
                                     entity,
                                     &mut cfg,
@@ -780,8 +306,10 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                                 );
                             }
 
-                            // properties
-                            if let Some(props) = _props {
+                            if let Ok(mut q) = self.world.query_one::<&mut ModelProperties>(*entity)
+                                && let Some(props) = q.get()
+                            {
+                                // properties
                                 props.inspect(
                                     entity,
                                     &mut cfg,
@@ -792,97 +320,68 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                                 );
                             }
 
-                            // camera
-                            if let (Some(camera), Some(camera_component)) =
-                                (camera, camera_component)
+
+                            if let Ok(mut q) = self.world.query_one::<(&mut Camera, &mut CameraComponent)>(*entity)
+                                && let Some((camera, camera_component)) = q.get()
                             {
-                                ui.separator();
                                 CollapsingHeader::new("Camera Components")
-                                .default_open(true)
-                                .show(ui, |ui| {
-                                    ui.horizontal(|ui| {
-                                        ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
-                                            if ui.button("Remove Component ❌").clicked() {
-                                                    *self.signal = Signal::RemoveComponent(
-                                                        *entity,
-                                                        Box::new(ComponentType::Camera(
-                                                            Box::new(camera.clone()),
-                                                            camera_component.clone(),
-                                                            // None,
-                                                        )),
-                                                    );
-                                                // }
-                                            }
-                                        });
-                                    });
-
-                                    camera.inspect(
-                                        entity,
-                                        &mut cfg,
-                                        ui,
-                                        self.undo_stack,
-                                        self.signal,
-                                        &mut String::new(),
-                                    );
-                                    camera_component.camera_type = CameraType::Player; // it will always be a player if attached to an entity, never normal
-                                    camera_component.inspect(
-                                        entity,
-                                        &mut cfg,
-                                        ui,
-                                        self.undo_stack,
-                                        self.signal,
-                                        &mut camera.label.clone(),
-                                    );
+                                    .default_open(true)
+                                    .show(ui, |ui| {
+                                        camera.inspect(
+                                            entity,
+                                            &mut cfg,
+                                            ui,
+                                            self.undo_stack,
+                                            self.signal,
+                                            &mut String::new(),
+                                        );
 
-                                    ui.separator();
-                                    ui.label("Camera Controls:");
-                                    let mut active_camera = self.active_camera.lock();
+                                        camera_component.inspect(
+                                            entity,
+                                            &mut cfg,
+                                            ui,
+                                            self.undo_stack,
+                                            self.signal,
+                                            &mut camera.label.clone(),
+                                        );
 
-                                    if *active_camera == Some(*entity) {
-                                        ui.label("Status: Currently viewing through camera");
-                                    } else {
-                                        ui.label("Status: Not viewing through this camera");
-                                    }
+                                        ui.separator();
 
-                                    if ui.button("Set as active camera").clicked() {
-                                        *active_camera = Some(*entity);
-                                        log::info!("Currently viewing from camera angle '{}'", camera.label);
-                                    }
+                                        // camera controller
+                                        ui.label("Camera Controls:");
+                                        let mut active_camera = self.active_camera.lock();
 
-                                    if camera_component.starting_camera {
-                                        if ui.button("Stop making camera initial").clicked() {
-                                            log::debug!("'Stop making camera initial' button clicked");
-                                            camera_component.starting_camera = false;
-                                            success!("Removed {} from starting camera", camera.label);
-                                        }
-                                    } else if ui.button("Set as initial camera").clicked() {
-                                        log::debug!("'Set as initial camera' button clicked");
-                                        if matches!(camera_component.camera_type, CameraType::Debug) {
-                                            warn!("Cannot set any cameras of type 'Debug' to initial camera");
+                                        if active_camera.equivalent(&Some(*entity)) {
+                                            ui.label("Status: Currently viewing through camera");
                                         } else {
-                                            local_set_initial_camera = true
+                                            ui.label("Status: Not viewing through this camera");
+                                        }
+
+                                        if ui.button("Set as active camera").clicked() {
+                                            *active_camera = Some(*entity);
+                                            log::info!("Currently viewing from camera angle '{}'", camera.label);
                                         }
-                                    }
-                                });
-                            }
 
-                            // scripting
-                            if let Some(script) = script {
-                                ui.separator();
-                                ui.horizontal(|ui| {
-                                    ui.with_layout(
-                                        egui::Layout::right_to_left(egui::Align::Center),
-                                        |ui| {
-                                            if ui.button("Remove Component ❌").clicked() {
-                                                *self.signal = Signal::RemoveComponent(
-                                                    *entity,
-                                                    Box::new(ComponentType::Script(script.clone())),
-                                                )
+                                        if camera_component.starting_camera {
+                                            if ui.button("Stop making camera initial").clicked() {
+                                                log::debug!("'Stop making camera initial' button clicked");
+                                                camera_component.starting_camera = false;
+                                                success!("Removed {} from starting camera", camera.label);
                                             }
-                                        },
-                                    );
-                                });
+                                        } else if ui.button("Set as initial camera").clicked() {
+                                            log::debug!("'Set as initial camera' button clicked");
+                                            if matches!(camera_component.camera_type, CameraType::Debug) {
+                                                warn!("Cannot set any cameras of type 'Debug' to initial camera");
+                                            } else {
+                                                local_set_initial_camera = true
+                                            }
+                                        }
+                                    });
+                            }
 
+                            if let Ok(mut q) = self.world.query_one::<&mut ScriptComponent>(*entity)
+                                && let Some(script) = q.get()
+                            {
                                 script.inspect(
                                     entity,
                                     &mut cfg,
@@ -893,6 +392,28 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                                 );
                             }
 
+                            if let Ok(mut q) = self.world.query_one::<(&mut Light, &mut LightComponent)>(*entity)
+                                && let Some((light, comp)) = q.get()
+                            {
+                                light.inspect(
+                                    entity,
+                                    &mut cfg,
+                                    ui,
+                                    self.undo_stack,
+                                    self.signal,
+                                    &mut String::new(),
+                                );
+
+                                comp.inspect(
+                                    entity,
+                                    &mut cfg,
+                                    ui,
+                                    self.undo_stack,
+                                    self.signal,
+                                    &mut light.label,
+                                );
+                            }
+
                             if let Some(t) = cfg.label_last_edit
                                 && t.elapsed() >= Duration::from_millis(500)
                             {
@@ -901,7 +422,7 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                                 {
                                     UndoableAction::push_to_undo(
                                         self.undo_stack,
-                                        UndoableAction::Label(ent, orig, EntityType::Entity),
+                                        UndoableAction::Label(ent, orig),
                                     );
                                     log::debug!(
                                         "Pushed label change to undo stack after 500ms debounce period"
@@ -927,123 +448,6 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                             comp.starting_camera = true;
                         }
                     }
-
-                    // lighting system
-                    if let Ok(mut q) = self
-                        .world
-                        .query_one::<(&mut Light, &mut Transform, &mut LightComponent)>(*entity)
-                    {
-                        if let Some((light, transform, props)) = q.get() {
-                            light.inspect(
-                                entity,
-                                &mut cfg,
-                                ui,
-                                self.undo_stack,
-                                self.signal,
-                                &mut String::new(),
-                            );
-                            transform.inspect(
-                                entity,
-                                &mut cfg,
-                                ui,
-                                self.undo_stack,
-                                self.signal,
-                                &mut light.label,
-                            );
-                            props.inspect(
-                                entity,
-                                &mut cfg,
-                                ui,
-                                self.undo_stack,
-                                self.signal,
-                                &mut light.label,
-                            );
-                            if let Some(t) = cfg.label_last_edit
-                                && t.elapsed() >= Duration::from_millis(500)
-                            {
-                                if let Some(ent) = cfg.old_label_entity.take()
-                                    && let Some(orig) = cfg.label_original.take()
-                                {
-                                    UndoableAction::push_to_undo(
-                                        self.undo_stack,
-                                        UndoableAction::Label(ent, orig, EntityType::Light),
-                                    );
-                                    log::debug!(
-                                        "Pushed label change to undo stack after 500ms debounce period"
-                                    );
-                                }
-                                cfg.label_last_edit = None;
-                            }
-                        }
-                    } else {
-                        log_once::debug_once!("Unable to query light inside resource inspector");
-                    }
-
-                    // camera
-                    if let Ok(mut q) = self.world.query_one::<(
-                        &mut Camera,
-                        &mut CameraComponent,
-                        // Option<&mut CameraFollowTarget>,
-                    )>(*entity)
-                        && let Some((camera, camera_component)) = q.get()
-                        && self.world.get::<&MeshRenderer>(*entity).is_err()
-                    {
-                        ui.vertical(|ui| {
-                            camera.inspect(
-                                entity,
-                                &mut cfg,
-                                ui,
-                                self.undo_stack,
-                                self.signal,
-                                &mut String::new(),
-                            );
-                            camera_component.inspect(
-                                entity,
-                                &mut cfg,
-                                ui,
-                                self.undo_stack,
-                                self.signal,
-                                &mut camera.label.clone(),
-                            );
-
-                            ui.separator();
-
-                            let mut active_camera = self.active_camera.lock();
-
-                            ui.label("Camera Controls:");
-                            if *active_camera == Some(*entity) {
-                                ui.label("Status: Currently viewing through camera");
-                            } else {
-                                ui.label("Status: Not viewing through this camera");
-                            }
-
-                            if ui.button("Set as active camera").clicked() {
-                                *active_camera = Some(*entity);
-                                log::info!("Currently viewing from camera angle '{}'", camera.label);
-                            }
-
-                            if camera_component.starting_camera {
-                                if ui.button("Stop making camera initial").clicked() {
-                                    log::debug!("'Stop making camera initial' button clicked");
-                                    success!("Removed {} from starting camera", camera.label);
-                                    camera_component.starting_camera = false;
-                                }
-                            } else {
-                                #[allow(clippy::collapsible_else_if)]
-                                if ui.button("Set as initial camera").clicked() {
-                                    log::debug!("'Set as initial camera' button clicked");
-                                    if matches!(camera_component.camera_type, CameraType::Debug) {
-                                        info!("Cannot set any cameras of type 'Debug' to initial camera");
-                                    } else {
-                                        success!("Set {} at the starting camera. When you start your game, \
-                                                expect to see through this camera!", camera.label);
-                                        camera_component.starting_camera = true;
-                                    }
-                                }
-                            }
-                        });
-                    }
-                    ui.separator();
                 } else {
                     ui.label("No entity selected, therefore no info to provide. Go on, what are you waiting for? Click an entity!");
                 }
@@ -1185,210 +589,6 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                     });
             }
         }
-
-        let mut menu_action: Option<EditorTabMenuAction> = None;
-        let area = egui::Area::new("context_menu".into())
-            .fixed_pos(cfg.context_menu_pos)
-            .order(egui::Order::Foreground);
-
-        if cfg.show_context_menu {
-            let menu_tab = cfg
-                .context_menu_tab
-                .clone()
-                .unwrap_or(EditorTab::ModelEntityList);
-
-            let mut popup_rect = None;
-
-            area.show(ui.ctx(), |ui| {
-                egui::Frame::popup(ui.style()).show(ui, |ui| {
-                    popup_rect.replace(ui.max_rect());
-
-                    match menu_tab {
-                        EditorTab::AssetViewer => {
-                            ui.set_min_width(150.0);
-                            if ui.selectable_label(false, "Import resource").clicked() {
-                                menu_action = Some(EditorTabMenuAction::ImportResource);
-                            }
-                            if ui.selectable_label(false, "Refresh assets").clicked() {
-                                menu_action = Some(EditorTabMenuAction::RefreshAssets);
-                            }
-                        }
-                        EditorTab::ModelEntityList => {
-                            ui.set_min_width(150.0);
-                            if ui.selectable_label(false, "Add Entity").clicked() {
-                                menu_action = Some(EditorTabMenuAction::AddEntity);
-                            }
-                            if ui.selectable_label(false, "Delete Entity").clicked() {
-                                menu_action = Some(EditorTabMenuAction::DeleteEntity);
-                            }
-                        }
-                        EditorTab::ResourceInspector => {
-                            ui.set_min_width(150.0);
-                            if ui.selectable_label(false, "Add Component").clicked() {
-                                menu_action = Some(EditorTabMenuAction::AddComponent);
-                            }
-                        }
-                        EditorTab::Viewport => {
-                            ui.set_min_width(150.0);
-                            if ui.selectable_label(false, "Viewport Option").clicked() {
-                                menu_action = Some(EditorTabMenuAction::ViewportOption);
-                            }
-                        }
-                        EditorTab::ErrorConsole => {
-                            ui.set_min_width(150.0);
-                            ui.label("No actions available");
-                        }
-                        EditorTab::Plugin(dock_info) => {
-                            if self.editor.is_null() {
-                                panic!("Editor pointer is null, unexpected behaviour");
-                            }
-
-                            let editor = unsafe { &mut *self.editor };
-                            if let Some((_, plugin)) =
-                                self.plugin_registry.plugins.get_index_mut(dock_info)
-                            {
-                                plugin.context_menu(ui, editor);
-                            } else {
-                                ui.colored_label(
-                                    egui::Color32::RED,
-                                    format!("Plugin at index '{}' not found", dock_info),
-                                );
-                            }
-                        }
-                    }
-                })
-            });
-
-            if let Some(action) = menu_action
-                && Some(tab.clone()) == cfg.context_menu_tab
-            {
-                match action {
-                    EditorTabMenuAction::ImportResource => {
-                        log::debug!("Import Resource clicked");
-
-                        match import_object() {
-                            Ok(_) => {
-                                success!("Resource(s) imported successfully!");
-                            }
-                            Err(e) => {
-                                warn!("Failed to import resource(s): {e}");
-                            }
-                        }
-                        cfg.show_context_menu = false;
-                        cfg.context_menu_tab = None;
-                        return;
-                    }
-                    EditorTabMenuAction::RefreshAssets => {
-                        log::debug!("Refresh assets clicked");
-                        {
-                            let mut res = RESOURCES.write();
-                            match res.update_mem() {
-                                Ok(res_cfg) => {
-                                    *res = res_cfg;
-                                    success!("Assets refreshed successfully!");
-                                }
-                                Err(e) => {
-                                    fatal!("Failed to refresh assets: {}", e);
-                                }
-                            }
-                        }
-                        cfg.show_context_menu = false;
-                        cfg.context_menu_tab = None;
-                        return;
-                    }
-                    EditorTabMenuAction::AddEntity => {
-                        log::debug!("Add Entity clicked");
-                        *self.signal = Signal::CreateEntity;
-                        cfg.show_context_menu = false;
-                        cfg.context_menu_tab = None;
-                        return;
-                    }
-                    EditorTabMenuAction::DeleteEntity => {
-                        log::debug!("Delete Entity clicked");
-                        *self.signal = Signal::Delete;
-                        cfg.show_context_menu = false;
-                        cfg.context_menu_tab = None;
-                        return;
-                    }
-                    EditorTabMenuAction::AddComponent => {
-                        log::debug!("Add Component clicked");
-                        if let Some(entity) = self.selected_entity {
-                            {
-                                if let Ok(mut q) = self.world.query_one::<&MeshRenderer>(*entity)
-                                    && q.get().is_some()
-                                {
-                                    log::debug!("Queried selected entity, it is an entity");
-                                    *self.signal =
-                                        Signal::AddComponent(*entity, EntityType::Entity);
-                                }
-                            }
-
-                            {
-                                if let Ok(mut q) = self.world.query_one::<&Light>(*entity)
-                                    && q.get().is_some()
-                                {
-                                    log::debug!("Queried selected entity, it is a light");
-                                    *self.signal = Signal::AddComponent(*entity, EntityType::Light);
-                                }
-                            }
-                        } else {
-                            warn!(
-                                "What are you adding a component to? Theres no entity selected..."
-                            );
-                        }
-
-                        cfg.show_context_menu = false;
-                        cfg.context_menu_tab = None;
-                        return;
-                    }
-                    EditorTabMenuAction::ViewportOption => {
-                        log::debug!("Viewport Option clicked");
-                        cfg.show_context_menu = false;
-                        cfg.context_menu_tab = None;
-                        return;
-                    }
-                    EditorTabMenuAction::RemoveComponent => {
-                        log::debug!("Remove Component clicked");
-                        if let Some(entity) = self.selected_entity {
-                            if let Ok(mut q) = self.world.query_one::<&ScriptComponent>(*entity) {
-                                if let Some(script) = q.get() {
-                                    log::debug!(
-                                        "Queried selected entity, it has a script component"
-                                    );
-                                    *self.signal = Signal::RemoveComponent(
-                                        *entity,
-                                        Box::new(ComponentType::Script(script.clone())),
-                                    );
-                                }
-                            } else {
-                                warn!("Selected entity does not have a script component to remove");
-                            }
-                        } else {
-                            panic!(
-                                "Paradoxical error: Cannot remove a component when its not selected..."
-                            );
-                        }
-
-                        cfg.show_context_menu = false;
-                        cfg.context_menu_tab = None;
-                        return;
-                    }
-                }
-            }
-
-            if let Some(rect) = popup_rect
-                && cfg.show_context_menu
-                && Some(tab.clone()) == cfg.context_menu_tab
-                && ui
-                    .ctx()
-                    .input(|i| i.pointer.button_clicked(egui::PointerButton::Primary))
-                && let Some(pos) = ui.ctx().input(|i| i.pointer.interact_pos())
-                && !rect.contains(pos)
-            {
-                cfg.show_context_menu = false;
-                cfg.context_menu_tab = None;
-            }
-        }
     }
 }
 
diff --git a/eucalyptus-editor/src/editor/input.rs b/eucalyptus-editor/src/editor/input.rs
index 9763088..a98a13e 100644
--- a/eucalyptus-editor/src/editor/input.rs
+++ b/eucalyptus-editor/src/editor/input.rs
@@ -1,6 +1,6 @@
 use super::*;
 use dropbear_engine::{
-    entity::{MeshRenderer, Transform},
+    entity::{MeshRenderer},
     input::{Controller, Keyboard, Mouse},
 };
 use eucalyptus_core::states::Label;
@@ -133,20 +133,19 @@ impl Keyboard for Editor {
                             let query = self.world.query_one::<(
                                 &Label,
                                 &MeshRenderer,
-                                &Transform,
+                                &EntityTransform,
                                 &ModelProperties,
                             )>(*entity);
                             if let Ok(mut q) = query {
                                 if let Some((label, renderer, t, props)) = q.get() {
                                     let s_entity = SceneEntity {
-                                        model_path: renderer.handle().path.clone(),
                                         label: label.clone(),
-                                        transform: *t,
-                                        properties: props.clone(),
-                                        script: None,
-                                        camera: None,
-                                        children: None,
-                                        material_overrides: renderer.material_overrides().to_vec(),
+                                        components: vec![
+                                            Box::new(props.clone()),
+                                            Box::new(SerializedMeshRenderer::from_renderer(&renderer)),
+                                            Box::new(t.clone()),
+
+                                        ],
                                         entity_id: None,
                                     };
                                     self.signal = Signal::Copy(s_entity);
diff --git a/eucalyptus-editor/src/editor/mod.rs b/eucalyptus-editor/src/editor/mod.rs
index 9ac0e29..eeb4539 100644
--- a/eucalyptus-editor/src/editor/mod.rs
+++ b/eucalyptus-editor/src/editor/mod.rs
@@ -7,7 +7,6 @@ pub mod scene;
 pub(crate) use crate::editor::dock::*;
 
 use crate::build::build;
-use crate::camera::UndoableCameraAction;
 use crate::debug;
 use crate::graphics::OutlineShader;
 use crate::plugin::PluginRegistry;
@@ -37,7 +36,7 @@ use eucalyptus_core::{
     scripting::{BuildStatus, ScriptManager, ScriptTarget},
     states,
     states::{
-        CameraConfig, EditorTab, EntityNode, LightConfig, ModelProperties, ScriptComponent, WorldLoadingStatus,
+        CameraConfig, EditorTab, LightConfig, ModelProperties, ScriptComponent, WorldLoadingStatus,
         PROJECT, SCENES,
     },
     success, success_without_console,
@@ -50,10 +49,10 @@ use parking_lot::Mutex;
 use rfd::FileDialog;
 use std::path::Path;
 use std::{
-    collections::{HashMap, HashSet},
+    collections::{HashMap},
     fs,
     path::PathBuf,
-    sync::{Arc, LazyLock},
+    sync::{Arc},
     time::{Duration, Instant},
 };
 use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
@@ -1019,7 +1018,6 @@ impl Editor {
                     ui,
                     &mut EditorTabViewer {
                         view: self.texture_id.unwrap(),
-                        nodes: EntityNode::from_world(&self.world),
                         gizmo: &mut self.gizmo,
                         tex_size: self.size,
                         world: &mut self.world,
@@ -1435,95 +1433,6 @@ impl Editor {
     }
 }
 
-pub static LOGGED: LazyLock<Mutex<HashSet<String>>> = LazyLock::new(|| Mutex::new(HashSet::new()));
-
-fn show_entity_tree(
-    ui: &mut egui::Ui,
-    nodes: &mut [EntityNode],
-    selected: &mut Option<hecs::Entity>,
-    id_source: &str,
-) {
-    egui_dnd::Dnd::new(ui, id_source).show_vec(nodes, |ui, item, handle, _dragging| {
-        match item.clone() {
-            EntityNode::Entity { id, name } => {
-                ui.horizontal(|ui| {
-                    handle.ui(ui, |ui| {
-                        ui.label("⏹️");
-                    });
-                    let resp = ui.selectable_label(selected.as_ref().eq(&Some(&id)), name);
-                    if resp.clicked() {
-                        *selected = Some(id);
-                    }
-                });
-            }
-            EntityNode::Script { .. } => {
-                ui.horizontal(|ui| {
-                    handle.ui(ui, |ui| {
-                        ui.label("📜");
-                    });
-                    ui.label("Script");
-                });
-            }
-            EntityNode::Group {
-                ref name,
-                ref mut children,
-                ref mut collapsed,
-            } => {
-                ui.horizontal(|ui| {
-                    handle.ui(ui, |ui| {
-                        let header = egui::CollapsingHeader::new(name)
-                            .default_open(!*collapsed)
-                            .show(ui, |ui| {
-                                show_entity_tree(ui, children, selected, name);
-                            });
-                        *collapsed = header.body_returned.is_none();
-                    });
-                });
-            }
-            EntityNode::Light { id, name } => {
-                ui.horizontal(|ui| {
-                    handle.ui(ui, |ui| {
-                        ui.label("💡");
-                    });
-                    let resp = ui.selectable_label(selected.as_ref().eq(&Some(&id)), name);
-                    if resp.clicked() {
-                        *selected = Some(id);
-                    }
-                });
-            }
-            EntityNode::Camera {
-                id,
-                name,
-                camera_type,
-            } => {
-                ui.horizontal(|ui| {
-                    handle.ui(ui, |ui| {
-                        let icon = match camera_type {
-                            CameraType::Debug => "🎥",  // Debug camera
-                            CameraType::Player => "📹", // Player camera
-                            CameraType::Normal => "📷", // Normal camera
-                        };
-                        ui.label(icon);
-                    });
-                    let display_name = format!(
-                        "{} ({})",
-                        name,
-                        match camera_type {
-                            CameraType::Debug => "Debug",
-                            CameraType::Player => "Player",
-                            CameraType::Normal => "Normal",
-                        }
-                    );
-                    let resp = ui.selectable_label(selected.as_ref().eq(&Some(&id)), display_name);
-                    if resp.clicked() {
-                        *selected = Some(id);
-                    }
-                });
-            }
-        }
-    });
-}
-
 /// Describes an action that is undoable
 #[derive(Debug)]
 pub enum UndoableAction {
@@ -1533,21 +1442,8 @@ pub enum UndoableAction {
     /// A spawn of the entity. Undoing will delete the entity
     Spawn(hecs::Entity),
     /// A change of label of the entity. Undoing will revert its label
-    Label(hecs::Entity, String, EntityType),
-    /// Removing a component. Undoing will add back the component.
-    RemoveComponent(hecs::Entity, Box<ComponentType>),
-    #[allow(dead_code)]
-    CameraAction(UndoableCameraAction),
-    RemoveStartingCamera(hecs::Entity),
-}
-
-#[derive(Debug)]
-#[allow(dead_code)]
-// todo: deal with why there is no Camera
-pub enum EntityType {
-    Entity,
-    Light,
-    Camera,
+    Label(hecs::Entity, String),
+    RemoveStartingCamera(Entity),
 }
 
 impl UndoableAction {
@@ -1579,150 +1475,14 @@ impl UndoableAction {
                     Err(anyhow::anyhow!("Failed to despawn entity {:?}", entity))
                 }
             }
-            UndoableAction::Label(entity, original_label, entity_type) => match entity_type {
-                EntityType::Entity => {
-                    let mut updated = false;
-
-                    if let Ok(mut label_query) = world.query_one::<&mut Label>(*entity) {
-                        if let Some(label_component) = label_query.get() {
-                            label_component.set(original_label.clone());
-                            updated = true;
-                        }
-                    }
-
-                    if let Ok(mut renderer_query) = world.query_one::<&mut MeshRenderer>(*entity) {
-                        if let Some(renderer) = renderer_query.get() {
-                            renderer.make_model_mut().label = original_label.clone();
-                            updated = true;
-                        }
-                    }
-
-                    if updated {
-                        log::debug!(
-                            "Reverted label for entity {:?} to '{}'",
-                            entity,
-                            original_label
-                        );
-                        Ok(())
-                    } else {
-                        Err(anyhow::anyhow!(
-                            "Unable to query the entity for label revert"
-                        ))
-                    }
-                }
-                EntityType::Light => {
-                    let mut updated = false;
-
-                    if let Ok(mut label_query) = world.query_one::<&mut Label>(*entity) {
-                        if let Some(label_component) = label_query.get() {
-                            label_component.set(original_label.clone());
-                            updated = true;
-                        }
-                    }
-
-                    if let Ok(mut q) = world.query_one::<&mut Light>(*entity) {
-                        if let Some(adopted) = q.get() {
-                            adopted.label = original_label.clone();
-                            updated = true;
-                        }
-                    }
-
-                    if updated {
-                        log::debug!(
-                            "Reverted label for light {:?} to '{}'",
-                            entity,
-                            original_label
-                        );
-                        Ok(())
-                    } else {
-                        Err(anyhow::anyhow!(
-                            "Could not find a light to query for label revert"
-                        ))
-                    }
-                }
-                EntityType::Camera => {
-                    let mut updated = false;
-
-                    if let Ok(mut label_query) = world.query_one::<&mut Label>(*entity) {
-                        if let Some(label_component) = label_query.get() {
-                            label_component.set(original_label.clone());
-                            updated = true;
-                        }
-                    }
-
-                    if let Ok(mut q) = world.query_one::<&mut Camera>(*entity) {
-                        if let Some(adopted) = q.get() {
-                            adopted.label = original_label.clone();
-                            updated = true;
-                        }
-                    }
-
-                    if updated {
-                        log::debug!(
-                            "Reverted label for camera {:?} to '{}'",
-                            entity,
-                            original_label
-                        );
-                        Ok(())
-                    } else {
-                        Err(anyhow::anyhow!(
-                            "Could not find a camera to query for label revert"
-                        ))
-                    }
+            UndoableAction::Label(entity, original_label) => {
+                if let Ok(label) = world.query_one_mut::<&mut Label>(*entity) {
+                    label.set(original_label.clone());
+                    Ok(())
+                } else {
+                    anyhow::bail!("No entity found (with or without the Label property)");
                 }
             },
-            UndoableAction::RemoveComponent(entity, c_type) => {
-                match &**c_type {
-                    ComponentType::Script(component) => {
-                        world.insert_one(*entity, component.clone())?;
-                    }
-                    ComponentType::Camera(camera, component) => {
-                        world.insert(*entity, (camera.clone(), component.clone()))?;
-                    }
-                }
-                Ok(())
-            }
-            UndoableAction::CameraAction(action) => {
-                match action {
-                    UndoableCameraAction::Speed(entity, speed) => {
-                        if let Ok(mut q) =
-                            world.query_one::<(&mut Camera, &mut CameraComponent)>(*entity)
-                            && let Some((cam, comp)) = q.get()
-                        {
-                            comp.settings.speed = *speed;
-                            comp.update(cam);
-                        }
-                    }
-                    UndoableCameraAction::Sensitivity(entity, sensitivity) => {
-                        if let Ok(mut q) =
-                            world.query_one::<(&mut Camera, &mut CameraComponent)>(*entity)
-                            && let Some((cam, comp)) = q.get()
-                        {
-                            comp.settings.sensitivity = *sensitivity;
-                            comp.update(cam);
-                        }
-                    }
-                    UndoableCameraAction::Fov(entity, fov) => {
-                        if let Ok(mut q) =
-                            world.query_one::<(&mut Camera, &mut CameraComponent)>(*entity)
-                            && let Some((cam, comp)) = q.get()
-                        {
-                            comp.settings.fov_y = *fov;
-                            comp.update(cam);
-                        }
-                    }
-                    UndoableCameraAction::Type(entity, camera_type) => {
-                        if let Ok(mut q) =
-                            world.query_one::<(&mut Camera, &mut CameraComponent)>(*entity)
-                            && let Some((cam, comp)) = q.get()
-                        {
-                            comp.camera_type = *camera_type;
-                            comp.update(cam);
-                        }
-                    }
-                };
-                Ok(())
-            }
             UndoableAction::RemoveStartingCamera(old) => {
                 for (_i, comp) in &mut world.query::<&mut CameraComponent>() {
                     comp.starting_camera = false;
@@ -1747,36 +1507,23 @@ pub enum Signal {
     Paste(SceneEntity),
     Delete,
     Undo,
-    // ScriptAction(ScriptAction),
-    // not actions required because follow target is set through scripting.
-    // CameraAction(CameraAction),
     Play,
     StopPlaying,
-    AddComponent(hecs::Entity, EntityType),
-    RemoveComponent(hecs::Entity, Box<ComponentType>),
     CreateEntity,
     LogEntities,
     Spawn(PendingSpawnType),
 }
 
-#[derive(Debug)]
-#[allow(dead_code)]
-// todo: deal with the Camera and create an implementation
-pub enum ComponentType {
-    Script(ScriptComponent),
-    Camera(Box<Camera>, CameraComponent),
-}
-
 #[derive(Clone)]
 pub struct PlayModeBackup {
     entities: Vec<(
-        hecs::Entity,
+        Entity,
         MeshRenderer,
         Transform,
         ModelProperties,
         Option<ScriptComponent>,
     )>,
-    camera_data: Vec<(hecs::Entity, Camera, CameraComponent)>,
+    camera_data: Vec<(Entity, Camera, CameraComponent)>,
 }
 
 #[derive(Debug)]
@@ -1819,13 +1566,6 @@ impl IsWorldLoadedYet {
         self.project_loaded && self.scene_loaded
     }
 
-    // I don't know whether this should be kept or removed, but
-    // im adding dead code just in case.
-    #[allow(dead_code)]
-    pub fn is_project_ready(&self) -> bool {
-        self.project_loaded
-    }
-
     pub fn mark_project_loaded(&mut self) {
         self.project_loaded = true;
     }
diff --git a/eucalyptus-editor/src/main.rs b/eucalyptus-editor/src/main.rs
index 81dca3e..f764258 100644
--- a/eucalyptus-editor/src/main.rs
+++ b/eucalyptus-editor/src/main.rs
@@ -1,4 +1,5 @@
-#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
+// #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
+// note to self: when it becomes release, remember to readd this back
 
 use clap::{Arg, Command};
 use dropbear_engine::future::FutureQueue;
@@ -22,7 +23,7 @@ async fn main() -> anyhow::Result<()> {
             app_dirs2::app_root(app_dirs2::AppDataType::UserData, &eucalyptus_core::APP_INFO)
                 .expect("Failed to get app data directory")
                 .join("logs");
-        std::fs::create_dir_all(&log_dir).expect("Failed to create log dir");
+        fs::create_dir_all(&log_dir).expect("Failed to create log dir");
 
         let datetime_str = chrono::offset::Local::now().format("%Y-%m-%d_%H-%M-%S");
         let log_filename = format!("{}.{}.log", "eucalyptus-editor", datetime_str);
diff --git a/eucalyptus-editor/src/menu.rs b/eucalyptus-editor/src/menu.rs
index 5296756..a5082c1 100644
--- a/eucalyptus-editor/src/menu.rs
+++ b/eucalyptus-editor/src/menu.rs
@@ -1,4 +1,4 @@
-use anyhow::{Context, anyhow};
+use anyhow::{anyhow, Context};
 use dropbear_engine::{
     future::{FutureHandle, FutureQueue},
     graphics::RenderContext,
@@ -7,7 +7,7 @@ use dropbear_engine::{
 };
 use egui::{self, FontId, Frame, RichText};
 use egui_toast::{ToastOptions, Toasts};
-use eucalyptus_core::states::{PROJECT, ProjectConfig};
+use eucalyptus_core::states::PROJECT;
 use git2::Repository;
 use log::{self, debug};
 use rfd::FileDialog;
@@ -17,6 +17,7 @@ use tokio::sync::watch;
 use winit::{
     dpi::PhysicalPosition, event::MouseButton, event_loop::ActiveEventLoop, keyboard::KeyCode,
 };
+use eucalyptus_core::config::ProjectConfig;
 
 #[derive(Debug, Clone)]
 pub enum ProjectProgress {
diff --git a/eucalyptus-editor/src/signal.rs b/eucalyptus-editor/src/signal.rs
index ba905cf..0c2330b 100644
--- a/eucalyptus-editor/src/signal.rs
+++ b/eucalyptus-editor/src/signal.rs
@@ -1,21 +1,23 @@
 use crate::editor::{
-    ComponentType, Editor, EditorState, EntityType, PendingSpawnType, Signal, UndoableAction,
+    Editor, EditorState, PendingSpawnType, Signal,
 };
 use dropbear_engine::camera::Camera;
-use dropbear_engine::entity::{MeshRenderer, Transform};
+use dropbear_engine::entity::{EntityTransform, MeshRenderer, Transform};
 use dropbear_engine::graphics::SharedGraphicsContext;
 use dropbear_engine::lighting::{Light, LightComponent};
 use dropbear_engine::utils::{ResourceReference, ResourceReferenceType};
-use egui::{Align2, Image};
+use egui::{Align2};
 use eucalyptus_core::camera::{CameraComponent, CameraType};
 use eucalyptus_core::scripting::{BuildStatus, build_jvm};
 use eucalyptus_core::spawn::{PendingSpawn, push_pending_spawn};
-use eucalyptus_core::states::{EditorTab, Label, ModelProperties, PROJECT, ScriptComponent, Value};
+use eucalyptus_core::states::{EditorTab, Label, ModelProperties, PROJECT, ScriptComponent, SerializedMeshRenderer};
 use eucalyptus_core::{fatal, info, success, success_without_console, warn, warn_without_console};
 use std::any::TypeId;
 use std::path::PathBuf;
 use std::sync::Arc;
 use winit::keyboard::KeyCode;
+use eucalyptus_core::scene::SceneEntity;
+use eucalyptus_core::traits::SerializableComponent;
 
 pub trait SignalController {
     fn run_signal(&mut self, graphics: Arc<SharedGraphicsContext>) -> anyhow::Result<()>;
@@ -23,10 +25,8 @@ pub trait SignalController {
 
 impl SignalController for Editor {
     fn run_signal(&mut self, graphics: Arc<SharedGraphicsContext>) -> anyhow::Result<()> {
-        let mut local_insert_script = false;
-        let mut local_insert_camera = (false, String::new());
-        let mut local_signal: Option<Signal> = None;
-        let mut show = true;
+        let local_signal: Option<Signal> = None;
+        let show = true;
 
         match &self.signal {
             Signal::None => {
@@ -36,10 +36,7 @@ impl SignalController for Editor {
             Signal::Copy(_) => Ok(()),
             Signal::Paste(scene_entity) => {
                 let spawn = PendingSpawn {
-                    asset_path: scene_entity.model_path.clone(),
-                    asset_name: scene_entity.label.to_string(),
-                    transform: scene_entity.transform,
-                    properties: scene_entity.properties.clone(),
+                    scene_entity: scene_entity.clone(),
                     handle: None,
                 };
                 push_pending_spawn(spawn);
@@ -442,213 +439,6 @@ impl SignalController for Editor {
                 self.signal = Signal::None;
                 Ok(())
             }
-            Signal::AddComponent(entity, e_type) => {
-                match e_type {
-                    EntityType::Entity => {
-                        if let Ok(mut q) = self.world.query_one::<(&MeshRenderer, &Label)>(*entity)
-                        {
-                            if let Some((_renderer, label)) = q.get() {
-                                let label_text = label.to_string();
-                                egui::Window::new(format!("Add component for {}", label_text))
-                                    .title_bar(true)
-                                    .open(&mut show)
-                                    .scroll([false, true])
-                                    .anchor(Align2::CENTER_CENTER, [0.0, 0.0])
-                                    .enabled(true)
-                                    .show(&graphics.get_egui_context(), |ui| {
-                                        if ui
-                                            .add_sized(
-                                                [ui.available_width(), 30.0],
-                                                egui::Button::new("Scripting"),
-                                            )
-                                            .clicked()
-                                        {
-                                            log::debug!(
-                                                "Adding scripting component to entity [{}]",
-                                                label_text
-                                            );
-                                            local_insert_script = true;
-                                            local_signal = Some(Signal::None);
-                                        }
-                                        if ui
-                                            .add_sized(
-                                                [ui.available_width(), 30.0],
-                                                egui::Button::new("Camera"),
-                                            )
-                                            .clicked()
-                                        {
-                                            log::debug!(
-                                                "Adding camera component to entity [{}]",
-                                                label_text
-                                            );
-
-                                            local_insert_camera = (true, label_text.clone());
-                                            local_signal = Some(Signal::None);
-                                        }
-                                    });
-                            }
-                        } else {
-                            log_once::warn_once!(
-                                "Failed to add component to entity: no entity component found"
-                            );
-                        }
-                        if local_insert_script {
-                            if let Err(e) =
-                                self.world.insert_one(*entity, ScriptComponent::default())
-                            {
-                                warn!("Failed to add scripting component to entity: {}", e);
-                            } else {
-                                success!("Added the scripting component");
-                            }
-                        }
-
-                        if local_insert_camera.0 {
-                            let camera = Camera::predetermined(
-                                graphics.clone(),
-                                Some(&format!("{} Camera", local_insert_camera.1)),
-                            );
-                            let component = CameraComponent::new();
-                            if let Err(e) = self.world.insert(*entity, (camera, component)) {
-                                warn!("Failed to add camera component to entity: {}", e);
-                            } else {
-                                success!("Added the camera component");
-                            }
-                        }
-                        Ok(())
-                    }
-                    EntityType::Light => {
-                        if let Ok(mut q) = self.world.query_one::<&Light>(*entity) {
-                            if let Some(light) = q.get() {
-                                let mut show = true;
-                                egui::Window::new(format!("Add component for {}", light.label))
-                                        .scroll([false, true])
-                                        .anchor(Align2::CENTER_CENTER, [0.0, 0.0])
-                                        .enabled(true)
-                                        .open(&mut show)
-                                        .title_bar(true)
-                                        .show(&graphics.get_egui_context(), |ui| {
-                                            if ui
-                                                .add_sized(
-                                                    [ui.available_width(), 30.0],
-                                                    egui::Button::new("Scripting"),
-                                                )
-                                                .clicked()
-                                            {
-                                                log::debug!(
-                                                    "Adding scripting component to light [{}]",
-                                                    light.label
-                                                );
-
-                                                log::warn!("Its not really added, it's just a dummy button. To be implemented...");
-
-                                                success!(
-                                                    "Added the scripting component to light [{}]",
-                                                    light.label
-                                                );
-                                                self.signal = Signal::None;
-                                            }
-                                        });
-                                if !show {
-                                    self.signal = Signal::None;
-                                }
-                            }
-                            Ok(())
-                        } else {
-                            log_once::warn_once!(
-                                "Failed to add component to light: no light component found"
-                            );
-                            Ok(())
-                        }
-                    }
-                    EntityType::Camera => {
-                        {
-                            if let Ok(mut q) =
-                                self.world.query_one::<(&Camera, &CameraComponent)>(*entity)
-                            {
-                                if let Some((cam, _comp)) = q.get() {
-                                    let mut show = true;
-                                    egui::Window::new(format!("Add component for {}", cam.label))
-                                        .scroll([false, true])
-                                        .anchor(Align2::CENTER_CENTER, [0.0, 0.0])
-                                        .enabled(true)
-                                        .open(&mut show)
-                                        .title_bar(true)
-                                        .show(&graphics.get_egui_context(), |ui| {
-                                            egui_extras::install_image_loaders(ui.ctx());
-                                            ui.add(Image::from_bytes(
-                                                "bytes://theres_nothing.jpg",
-                                                include_bytes!(
-                                                    "../../resources/textures/theres_nothing.jpg"
-                                                ),
-                                            ));
-                                            ui.label("Theres nothing...");
-                                            // scripting could be planned???
-                                            // if ui.add_sized([ui.available_width(), 30.0], egui::Button::new("Scripting")).clicked() {
-                                            //     log::debug!("Adding scripting component to camera [{}]", cam.label);
-
-                                            //     success!("Added the scripting component to camera [{}]", cam.label);
-                                            //     self.signal = Signal::None;
-                                            // }
-                                        });
-                                    if !show {
-                                        self.signal = Signal::None;
-                                    }
-                                }
-                                Ok(())
-                            } else {
-                                log_once::warn_once!(
-                                    "Failed to add component to light: no light component found"
-                                );
-                                Ok(())
-                            }
-                        }
-                    }
-                }
-            }
-            Signal::RemoveComponent(entity, c_type) => match &**c_type {
-                ComponentType::Script(_) => {
-                    match self.world.remove_one::<ScriptComponent>(*entity) {
-                        Ok(component) => {
-                            success!("Removed script component from entity {:?}", entity);
-                            UndoableAction::push_to_undo(
-                                &mut self.undo_stack,
-                                UndoableAction::RemoveComponent(
-                                    *entity,
-                                    Box::new(ComponentType::Script(component)),
-                                ),
-                            );
-                        }
-                        Err(e) => {
-                            warn!("Failed to remove script component from entity: {}", e);
-                        }
-                    };
-                    self.signal = Signal::None;
-                    Ok(())
-                }
-                ComponentType::Camera(_, _) => {
-                    match self.world.remove::<(Camera, CameraComponent)>(*entity) {
-                        Ok(component) => {
-                            success!("Removed camera component from entity {:?}", entity);
-                            UndoableAction::push_to_undo(
-                                &mut self.undo_stack,
-                                UndoableAction::RemoveComponent(
-                                    *entity,
-                                    Box::new(ComponentType::Camera(
-                                        Box::new(component.0),
-                                        component.1,
-                                    )),
-                                ),
-                            );
-                        }
-                        Err(e) => {
-                            warn!("Failed to remove script component from entity: {}", e);
-                            self.signal = Signal::None;
-                        }
-                    };
-                    self.signal = Signal::None;
-                    Ok(())
-                }
-            },
             Signal::CreateEntity => {
                 let mut show = true;
                 egui::Window::new("Add Entity")
@@ -768,7 +558,7 @@ impl SignalController for Editor {
             }
             Signal::Spawn(entity_type) => {
                 match entity_type {
-                    crate::editor::PendingSpawnType::Light => {
+                    PendingSpawnType::Light => {
                         let light = Light::new(
                             graphics.clone(),
                             LightComponent::default(),
@@ -779,33 +569,42 @@ impl SignalController for Editor {
                         self.light_spawn_queue.push(handle);
                         success!("Pushed light to queue");
                     }
-                    crate::editor::PendingSpawnType::Plane => {
-                        let transform = Transform::new();
-                        let mut props = ModelProperties::new();
-                        props.add_property("width".to_string(), Value::Float(500.0));
-                        props.add_property("height".to_string(), Value::Float(200.0));
-                        props.add_property("tiles_x".to_string(), Value::Int(500));
-                        props.add_property("tiles_z".to_string(), Value::Int(200));
-
-                        push_pending_spawn(PendingSpawn {
-                            asset_path: ResourceReference::from_reference(
-                                ResourceReferenceType::Plane,
-                            ),
-                            asset_name: "DefaultPlane".to_string(),
-                            transform,
-                            properties: props,
-                            handle: None,
-                        });
-                        success!("Pushed plane to queue");
+                    PendingSpawnType::Plane => {
+                        fatal!("Plane spawning is not yet supported, sorry! (system being remade)");
+                        // let transform = Transform::new();
+                        // let mut props = ModelProperties::new();
+                        // props.add_property("width".to_string(), Value::Float(500.0));
+                        // props.add_property("height".to_string(), Value::Float(200.0));
+                        // props.add_property("tiles_x".to_string(), Value::Int(500));
+                        // props.add_property("tiles_z".to_string(), Value::Int(200));
+                        //
+                        // push_pending_spawn(PendingSpawn {
+                        //     asset_path: ResourceReference::from_reference(
+                        //         ResourceReferenceType::Plane,
+                        //     ),
+                        //     asset_name: "DefaultPlane".to_string(),
+                        //     transform,
+                        //     properties: props,
+                        //     handle: None,
+                        // });
+                        // success!("Pushed plane to queue");
                     }
                     PendingSpawnType::Cube => {
+                        let mut components: Vec<Box<dyn SerializableComponent>> =
+                            Vec::new();
+                        components.push(Box::new(EntityTransform::default()));
+                        components.push(Box::new(SerializedMeshRenderer {
+                            handle: ResourceReference::from_reference(ResourceReferenceType::Cube),
+                            material_override: Vec::new(),
+                        }));
+                        components.push(Box::new(ModelProperties::new()));
+
                         let pending = PendingSpawn {
-                            asset_path: ResourceReference::from_bytes(include_bytes!(
-                                "../../resources/models/cube.glb"
-                            )),
-                            asset_name: "Default Cube".to_string(),
-                            transform: Default::default(),
-                            properties: Default::default(),
+                            scene_entity: SceneEntity {
+                                label: Label::from("Cube"),
+                                components,
+                                entity_id: None,
+                            },
                             handle: None,
                         };
                         push_pending_spawn(pending);
diff --git a/eucalyptus-editor/src/spawn.rs b/eucalyptus-editor/src/spawn.rs
index 59680a0..8a784af 100644
--- a/eucalyptus-editor/src/spawn.rs
+++ b/eucalyptus-editor/src/spawn.rs
@@ -1,16 +1,29 @@
 use crate::editor::Editor;
-use dropbear_engine::entity::MeshRenderer;
+use dropbear_engine::asset::ASSET_REGISTRY;
+use dropbear_engine::entity::{EntityTransform, MeshRenderer};
 use dropbear_engine::future::FutureQueue;
 use dropbear_engine::graphics::SharedGraphicsContext;
 use dropbear_engine::model::Model;
-use dropbear_engine::procedural::plane::PlaneBuilder;
-use dropbear_engine::utils::{ResourceReference, ResourceReferenceType};
+use dropbear_engine::utils::ResourceReferenceType;
 pub(crate) use eucalyptus_core::spawn::{PENDING_SPAWNS, PendingSpawnController};
-use eucalyptus_core::states::{Label, PROJECT, Value};
-use eucalyptus_core::utils::PROTO_TEXTURE;
+use eucalyptus_core::scene::SceneEntity;
+use eucalyptus_core::states::{ModelProperties, SerializedMeshRenderer, ScriptComponent};
+use eucalyptus_core::utils::ResolveReference;
 use eucalyptus_core::{fatal, success};
+use hecs::EntityBuilder;
 use std::sync::Arc;
 
+fn component_ref<'a, T: 'static>(entity: &'a SceneEntity) -> Option<&'a T> {
+    entity
+        .components
+        .iter()
+        .find_map(|component| component.as_any().downcast_ref::<T>())
+}
+
+fn component_cloned<T: Clone + 'static>(entity: &SceneEntity) -> Option<T> {
+    component_ref::<T>(entity).cloned()
+}
+
 impl PendingSpawnController for Editor {
     fn check_up(
         &mut self,
@@ -19,144 +32,190 @@ impl PendingSpawnController for Editor {
     ) -> anyhow::Result<()> {
         queue.poll();
         let mut spawn_list = PENDING_SPAWNS.lock();
-
         let mut completed = Vec::new();
 
-        for (i, spawn) in spawn_list.iter_mut().enumerate() {
+        for (index, spawn) in spawn_list.iter_mut().enumerate() {
             log_once::debug_once!(
-                "Caught pending spawn! Info: {} of type {}",
-                spawn.asset_name,
-                spawn.asset_path
+                "Processing pending spawn for '{}'",
+                spawn.scene_entity.label
             );
-            if spawn.handle.is_none() {
-                log_once::debug_once!("Pending spawn does NOT have a handle, creating new one now");
-                let graphics_clone = graphics.clone();
-                let asset_name = spawn.asset_name.clone();
-                let asset_path = spawn.asset_path.ref_type.clone();
-
-                let func = async move {
-                    match asset_path {
-                        ResourceReferenceType::None => {
-                            Err(anyhow::anyhow!("No asset path available"))
-                        }
-                        ResourceReferenceType::File(file) => {
-                            let path = {
-                                let _guard = PROJECT.read();
-                                _guard.project_path.clone()
-                            };
-                            let relative = ResourceReference::relative_path_from_uri(&file)?;
-                            let resource = path.join("resources").join(relative);
-                            MeshRenderer::from_path(graphics_clone, resource, Some(&asset_name))
-                                .await
-                        }
-                        ResourceReferenceType::Bytes(bytes) => {
-                            let model = Model::load_from_memory(
-                                graphics_clone.clone(),
-                                &bytes,
-                                Some(&asset_name),
-                            )
-                            .await?;
-                            Ok(MeshRenderer::from_handle(model))
-                        }
-                        ResourceReferenceType::Plane => {
-                            anyhow::bail!("Unable to load plane: Not supported anymore, rebuilding it");
-                            // let get_float = |key: &str| -> anyhow::Result<f32> {
-                            //     let val = properties
-                            //         .custom_properties
-                            //         .iter()
-                            //         .find(|p| p.key == key)
-                            //         .ok_or_else(|| {
-                            //             anyhow::anyhow!("Entity has no {} property", key)
-                            //         })?;
-                            //     match val.value {
-                            //         Value::Float(f) => Ok(f as f32),
-                            //         _ => Err(anyhow::anyhow!("{} is not a float", key)),
-                            //     }
-                            // };
-                            // 
-                            // let get_int = |key: &str| -> anyhow::Result<u32> {
-                            //     let val = properties
-                            //         .custom_properties
-                            //         .iter()
-                            //         .find(|p| p.key == key)
-                            //         .ok_or_else(|| {
-                            //             anyhow::anyhow!("Entity has no {} property", key)
-                            //         })?;
-                            //     match val.value {
-                            //         Value::Int(i) => Ok(i as u32),
-                            //         _ => Err(anyhow::anyhow!("{} is not an int", key)),
-                            //     }
-                            // };
-                            // 
-                            // let width = get_float("width")?;
-                            // let height = get_float("height")?;
-                            // let tiles_x = get_int("tiles_x")?;
-                            // let tiles_z = get_int("tiles_z")?;
-                            // 
-                            // PlaneBuilder::new()
-                            //     .with_size(width, height)
-                            //     .with_tiles(tiles_x, tiles_z)
-                            //     .build(graphics_clone, PROTO_TEXTURE, Some(&asset_name))
-                            //     .await
-                        }
-                        ResourceReferenceType::Cube => {
-                            Model::load_from_memory(graphics_clone, include_bytes!("../../resources/models/cube.glb"), Some(&asset_name)).await.map(MeshRenderer::from_handle)
-                        }
-                    }
-                };
 
-                let handle = queue.push(Box::pin(func));
-                spawn.handle = Some(handle);
-            } else {
-                log_once::debug_once!("Spawn does have handle, using that one");
+            let serialized_renderer = component_cloned::<SerializedMeshRenderer>(&spawn.scene_entity);
+
+            if serialized_renderer.is_none() && spawn.handle.is_none() {
+                log::debug!(
+                    "No renderer component found for '{}', spawning immediately",
+                    spawn.scene_entity.label
+                );
+                self.spawn_scene_entity(&spawn.scene_entity, None);
+                completed.push(index);
+                continue;
+            }
+
+            if spawn.handle.is_none() {
+                if let Some(renderer) = serialized_renderer.clone() {
+                    let graphics_clone = graphics.clone();
+                    let label = spawn.scene_entity.label.to_string();
+                    let future = async move {
+                        load_renderer_from_serialized(renderer, graphics_clone, label).await
+                    };
+                    let handle = queue.push(Box::pin(future));
+                    spawn.handle = Some(handle);
+                }
             }
 
             if let Some(handle) = &spawn.handle {
-                log_once::debug_once!("Handle located");
                 if let Some(result) = queue.exchange_owned(handle) {
-                    log_once::debug_once!("Loading done, located result");
                     if let Ok(r) = result.downcast::<anyhow::Result<MeshRenderer>>() {
-                        log_once::debug_once!("Result has been successfully downcasted");
                         match Arc::try_unwrap(r) {
-                            Ok(entity) => match entity {
-                                Ok(entity) => {
-                                    log::debug!("Entity loaded");
-                                    self.world.spawn((
-                                        Label::from(spawn.asset_name.clone()),
-                                        entity,
-                                        spawn.transform,
-                                        spawn.properties.clone(),
-                                    ));
-                                    success!("Spawned entity successfully");
-                                    completed.push(i);
+                            Ok(outcome) => match outcome {
+                                Ok(renderer) => {
+                                    self.spawn_scene_entity(&spawn.scene_entity, Some(renderer));
+                                    success!(
+                                        "Spawned '{}' from pending queue",
+                                        spawn.scene_entity.label
+                                    );
+                                    completed.push(index);
                                 }
-                                Err(e) => {
-                                    fatal!("Unable to load model: {}", e);
-                                    completed.push(i);
+                                Err(err) => {
+                                    fatal!("Unable to load mesh renderer: {}", err);
+                                    completed.push(index);
                                 }
                             },
                             Err(_) => {
-                                return {
-                                    log_once::warn_once!("Cannot unwrap Arc result");
-                                    completed.push(i);
-                                    Ok(())
-                                };
+                                log_once::warn_once!(
+                                    "Renderer future for '{}' still shared, deferring",
+                                    spawn.scene_entity.label
+                                );
                             }
                         }
+                    } else {
+                        fatal!(
+                            "Future result for '{}' could not be downcasted",
+                            spawn.scene_entity.label
+                        );
+                        completed.push(index);
                     }
-                } else {
-                    log_once::debug_once!("Handle exchanging failed, probably not ready yet");
                 }
-            } else {
-                log_once::debug_once!("Spawn has no handle");
             }
         }
 
         for &i in completed.iter().rev() {
-            log_once::debug_once!("Removing item {} from pending spawn list", i);
             spawn_list.remove(i);
         }
 
         Ok(())
     }
 }
+
+impl Editor {
+    fn spawn_scene_entity(
+        &mut self,
+        scene_entity: &SceneEntity,
+        mesh_renderer: Option<MeshRenderer>,
+    ) {
+        let mut builder = EntityBuilder::new();
+        builder.add(scene_entity.label.clone());
+
+        if let Some(transform) = component_ref::<EntityTransform>(scene_entity).copied() {
+            builder.add(transform);
+        } else {
+            builder.add(EntityTransform::default());
+        }
+
+        if let Some(renderer) = mesh_renderer {
+            builder.add(renderer);
+        }
+
+        if let Some(props) = component_cloned::<ModelProperties>(scene_entity) {
+            builder.add(props);
+        }
+
+        if let Some(script) = component_cloned::<ScriptComponent>(scene_entity) {
+            builder.add(script);
+        }
+
+        self.world.spawn(builder.build());
+    }
+}
+
+async fn load_renderer_from_serialized(
+    renderer: SerializedMeshRenderer,
+    graphics: Arc<SharedGraphicsContext>,
+    label: String,
+) -> anyhow::Result<MeshRenderer> {
+    let mut mesh_renderer = match &renderer.handle.ref_type {
+        ResourceReferenceType::None => anyhow::bail!(
+            "Renderer for '{}' does not specify an asset reference",
+            label
+        ),
+        ResourceReferenceType::File(_) => {
+            let path = renderer.handle.resolve()?;
+            MeshRenderer::from_path(graphics.clone(), &path, Some(&label)).await?
+        }
+        ResourceReferenceType::Bytes(bytes) => {
+            let model = Model::load_from_memory(graphics.clone(), bytes.clone(), Some(&label)).await?;
+            MeshRenderer::from_handle(model)
+        }
+        ResourceReferenceType::Plane => {
+            anyhow::bail!("Procedural planes are not supported in pending spawns yet");
+        }
+        ResourceReferenceType::Cube => {
+            let model = Model::load_from_memory(
+                graphics.clone(),
+                include_bytes!("../../resources/models/cube.glb"),
+                Some(&label),
+            )
+            .await?;
+            MeshRenderer::from_handle(model)
+        }
+    };
+
+    for override_entry in renderer.material_override {
+        if ASSET_REGISTRY
+            .model_handle_from_reference(&override_entry.source_model)
+            .is_none()
+        {
+            if matches!(
+                override_entry.source_model.ref_type,
+                ResourceReferenceType::File(_)
+            ) {
+                let source_path = override_entry.source_model.resolve()?;
+                let label_hint = override_entry.source_model.as_uri();
+                if let Err(err) =
+                    Model::load(graphics.clone(), &source_path, label_hint).await
+                {
+                    log::warn!(
+                        "Failed to preload source model {:?} for override '{}': {}",
+                        override_entry.source_model,
+                        override_entry.target_material,
+                        err
+                    );
+                    continue;
+                }
+            } else {
+                log::warn!(
+                    "Unsupported override source {:?} for '{}'",
+                    override_entry.source_model,
+                    label
+                );
+                continue;
+            }
+        }
+
+        if let Err(err) = mesh_renderer.apply_material_override(
+            &override_entry.target_material,
+            override_entry.source_model.clone(),
+            &override_entry.source_material,
+        ) {
+            log::warn!(
+                "Failed to apply material override '{}' on '{}': {}",
+                override_entry.target_material,
+                label,
+                err
+            );
+        }
+    }
+
+    Ok(mesh_renderer)
+}
diff --git a/eucalyptus-editor/src/utils.rs b/eucalyptus-editor/src/utils.rs
index db91457..5fa1fcc 100644
--- a/eucalyptus-editor/src/utils.rs
+++ b/eucalyptus-editor/src/utils.rs
@@ -3,13 +3,14 @@ use dropbear_engine::camera::Camera;
 use dropbear_engine::scene::SceneCommand;
 use egui::Context;
 use egui_toast::{Toast, ToastOptions, Toasts};
-use eucalyptus_core::states::{PROJECT, ProjectConfig};
+use eucalyptus_core::states::PROJECT;
 use eucalyptus_core::utils::ProjectProgress;
 use git2::Repository;
 use std::fs;
 use std::path::PathBuf;
 use std::sync::mpsc;
 use std::sync::mpsc::Receiver;
+use eucalyptus_core::config::ProjectConfig;
 
 pub fn show_new_project_window<F>(
     ctx: &Context,
diff --git a/headers/dropbear.h b/headers/dropbear.h
index 510baca..b09c8e1 100644
--- a/headers/dropbear.h
+++ b/headers/dropbear.h
@@ -26,6 +26,11 @@ typedef struct {
 } Vector3D;
 
 typedef struct {
+    NativeTransform local;
+    NativeTransform world;
+} NativeEntityTransform;
+
+typedef struct {
     double position_x;
     double position_y;
     double position_z;
@@ -61,28 +66,16 @@ typedef struct {
 
 int dropbear_get_entity(const char* label, const World* world_ptr, int64_t* out_entity);
 
-int dropbear_get_world_transform(
-    const World* world_ptr,
-    int64_t entity_id,
-    NativeTransform* out_transform
-);
-
-int dropbear_commit_world_transform(
-    const World* world_ptr,
-    int64_t entity_id,
-    const NativeTransform transform
-);
-
-int dropbear_get_local_transform(
+int dropbear_get_transform(
     const World* world_ptr,
     int64_t entity_id,
-    NativeTransform* out_transform
+    NativeEntityTransform* out_transform
 );
 
-int dropbear_commit_local_transform(
+int dropbear_set_transform(
     const World* world_ptr,
     int64_t entity_id,
-    const NativeTransform transform
+    const NativeEntityTransform transform
 );
 
 // property management
diff --git a/src/commonMain/kotlin/com/dropbear/EntityRef.kt b/src/commonMain/kotlin/com/dropbear/EntityRef.kt
index e8366aa..b95df19 100644
--- a/src/commonMain/kotlin/com/dropbear/EntityRef.kt
+++ b/src/commonMain/kotlin/com/dropbear/EntityRef.kt
@@ -30,7 +30,9 @@ class EntityRef(val id: EntityId = EntityId(0L)) {
     }
 
     /**
-     * Walks up the hierarchy to find the transform of the parent, then multiply to create a propagated [Transform].
+     * Walks up the world hierarchy to find the transform of the parent, then multiply 
+     * to create a propagated [Transform].
+     * 
      * This will update the entity's world transform based on its parent's world transform.
      */
     fun propagate() {