diff --git a/src/commands.rs b/src/commands.rs
index 69cc83a..6066ab7 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -1,282 +1,28 @@
 use std::{
-    fs, iter,
-    path::{Path, PathBuf},
+    fs, path::PathBuf,
 };
 
 use bevy::{
-    ecs::{
-        system::SystemState,
-        world::{Command, CommandQueue},
-    },
+    ecs::
+        world::{Command, CommandQueue}
+    ,
     prelude::*,
     tasks::AsyncComputeTaskPool,
 };
 use crypto::{
     aes::KeySize,
-    blockmodes::{EcbEncryptor, PkcsPadding},
+    blockmodes::PkcsPadding,
     buffer::{BufferResult, ReadBuffer, RefReadBuffer, RefWriteBuffer, WriteBuffer},
 };
 use occule::Error;
 use xz2::read::{XzDecoder, XzEncoder};
 
 use crate::{
-    components::DirworldEntity,
-    events::{DirworldNavigationEvent, DirworldSpawn},
-    payload::{DirworldComponent, DirworldComponentDiscriminants, DirworldEntityPayload},
-    resources::{
-        DirworldCodecs, DirworldCurrentDir, DirworldObservers, DirworldRootDir, DirworldTasks,
-        EntryType,
-    },
-    Extensions,
+    payload::{DirworldComponent, DirworldComponentDiscriminants, DirworldEntityPayload}, resources::{
+        DirworldCodecs, DirworldObservers, DirworldTasks,
+    }, utils::extract_entity_payload, Extensions
 };
 
-struct DirworldNavigateCommand {
-    pub path: PathBuf,
-}
-
-impl Command for DirworldNavigateCommand {
-    fn apply(self, world: &mut World) {
-        let root_dir = world.remove_resource::<DirworldRootDir>().unwrap();
-        let mut current_dir = world.remove_resource::<DirworldCurrentDir>().unwrap();
-
-        let current_path;
-        let old_dir;
-        if let Some(old_path) = &current_dir.0 {
-            world.send_event(DirworldNavigationEvent::LeftRoom {
-                path: old_path.clone(),
-            });
-
-            current_path = old_path.join(self.path);
-            old_dir = Some(old_path.clone());
-        } else {
-            current_path = self.path;
-            old_dir = None;
-        }
-        current_dir.0 = Some(current_path.clone());
-
-        let mut system_state: SystemState<(
-            Commands,
-            Query<(Entity, &DirworldEntity)>,
-            Res<DirworldObservers>,
-            Res<DirworldCodecs>,
-        )> = SystemState::new(world);
-        let (mut commands, dirworld_entities, observers, codecs) = system_state.get_mut(world);
-        update_entries(
-            &mut commands,
-            &dirworld_entities,
-            old_dir,
-            &current_path,
-            &root_dir.0.clone().unwrap(),
-            &observers,
-            &codecs,
-        );
-        system_state.apply(world);
-
-        world.send_event(DirworldNavigationEvent::EnteredRoom { path: current_path });
-        world.insert_resource(current_dir);
-        world.insert_resource(root_dir);
-    }
-}
-
-pub(crate) fn update_entries(
-    commands: &mut Commands,
-    dirworld_entities: &Query<(Entity, &DirworldEntity)>,
-    old_dir: Option<PathBuf>,
-    current_dir: &PathBuf,
-    project_dir: &PathBuf,
-    observers: &DirworldObservers,
-    codecs: &DirworldCodecs,
-) {
-    let directory = current_dir.read_dir().unwrap();
-
-    if let Some(old_dir) = old_dir {
-        let mut entities_to_despawn = vec![];
-        for (entity, dirworld_entity) in dirworld_entities.iter() {
-            if dirworld_entity.path.parent().unwrap() == old_dir {
-                entities_to_despawn.push(entity);
-            }
-        }
-        for entity in entities_to_despawn {
-            commands.entity(entity).despawn_recursive();
-        }
-    }
-
-    let mut entry_paths: Vec<PathBuf> = directory
-        .flatten()
-        .map(|entry| entry.path().canonicalize().unwrap())
-        .collect::<Vec<_>>();
-    entry_paths.retain(|entry| {
-        !entry
-            .file_name()
-            .is_some_and(|entry| entry.to_string_lossy().starts_with("."))
-    });
-    if current_dir != project_dir {
-        entry_paths = iter::once(current_dir.join(".."))
-            .chain(entry_paths)
-            .collect();
-    }
-
-    for entry_path in entry_paths {
-        process_entry(commands, &entry_path, &observers, &codecs);
-    }
-}
-
-pub(crate) fn process_entry(
-    commands: &mut Commands,
-    entry_path: &PathBuf,
-    observers: &DirworldObservers,
-    codecs: &DirworldCodecs,
-) {
-    let (payload, data) = extract_payload(entry_path, codecs);
-    let transform = if let Some(component) = payload
-        .as_ref()
-        .and_then(|payload| payload.component("Transform"))
-    {
-        if let DirworldComponent::Transform(component) = component {
-            component.clone()
-        } else {
-            panic!("Failed to decompose component")
-        }
-    } else {
-        Transform::default()
-    };
-
-    let entity = commands.spawn((
-        SpatialBundle {
-            transform,
-            ..Default::default()
-        },
-        DirworldEntity {
-            path: entry_path.clone(),
-            payload: payload.clone(),
-        },
-    ));
-
-    let entity = entity.id();
-    let entry_type = if entry_path.is_dir() {
-        EntryType::Folder
-    } else {
-        let extensions = entry_path.extensions();
-        EntryType::File(extensions)
-    };
-    if let Some(observer) = observers.get(&entry_type) {
-        commands.trigger_targets(DirworldSpawn { entity, data }, observer.clone());
-    }
-}
-
-fn extract_payload(
-    entry_path: &PathBuf,
-    codecs: &DirworldCodecs,
-) -> (Option<DirworldEntityPayload>, Option<Vec<u8>>) {
-    let entry_type = if entry_path.is_dir() {
-        EntryType::Folder
-    } else {
-        let extensions = entry_path.extensions();
-        EntryType::File(extensions)
-    };
-
-    let mut data: Option<Vec<u8>> = None;
-    let mut payload: Option<DirworldEntityPayload> = None;
-    match &entry_type {
-        EntryType::File(Some(extension)) => {
-            if let Ok(file_data) = fs::read(entry_path.clone()) {
-                match codecs.get(extension) {
-                    Some(codec) => match codec.decode(&file_data.as_slice()) {
-                        Ok((carrier, extracted_payload)) => {
-                            match rmp_serde::from_slice::<DirworldEntityPayload>(
-                                extracted_payload.as_slice(),
-                            ) {
-                                Ok(deserialized_payload) => {
-                                    data = Some(carrier);
-                                    payload = Some(deserialized_payload);
-                                }
-                                Err(e) => {
-                                    warn!("{:?}", e);
-                                    data = Some(file_data);
-                                }
-                            }
-                        }
-                        Err(e) => match e {
-                            Error::DataNotEncoded => {
-                                data = Some(file_data);
-                            }
-                            _ => error!("{:?}", e),
-                        },
-                    },
-                    None => {
-                        data = Some(file_data);
-                    }
-                }
-            } else {
-                warn!("Failed to read data from {entry_path:?}");
-            }
-        }
-        EntryType::Folder => {
-            let door_path = entry_path.join(".door");
-            if door_path.exists() {
-                let door_file_data = fs::read(door_path).unwrap();
-                match rmp_serde::from_slice::<DirworldEntityPayload>(&door_file_data.as_slice()) {
-                    Ok(deserialized_payload) => {
-                        payload = Some(deserialized_payload);
-                    }
-                    Err(e) => {
-                        warn!("{:?}", e);
-                    }
-                }
-            }
-        }
-        _ => {}
-    }
-    (payload, data)
-}
-
-struct DirworldChangeRootCommand {
-    pub path: PathBuf,
-}
-
-impl Command for DirworldChangeRootCommand {
-    fn apply(self, world: &mut World) {
-        let mut root_dir = world.remove_resource::<DirworldRootDir>().unwrap();
-        let mut current_dir = world.remove_resource::<DirworldCurrentDir>().unwrap();
-
-        let old_root;
-        if let DirworldRootDir(Some(old_dir)) = root_dir {
-            world.send_event(DirworldNavigationEvent::LeftRoom {
-                path: self.path.clone(),
-            });
-            old_root = Some(old_dir);
-        } else {
-            old_root = None;
-        }
-
-        root_dir.0 = Some(self.path.canonicalize().unwrap());
-        current_dir.0 = Some(self.path.canonicalize().unwrap());
-
-        let mut system_state: SystemState<(
-            Commands,
-            Query<(Entity, &DirworldEntity)>,
-            Res<DirworldObservers>,
-            Res<DirworldCodecs>,
-        )> = SystemState::new(world);
-        let (mut commands, dirworld_entities, observers, codecs) = system_state.get_mut(world);
-        update_entries(
-            &mut commands,
-            &dirworld_entities,
-            old_root,
-            &current_dir.0.clone().unwrap(),
-            &root_dir.0.clone().unwrap(),
-            &observers,
-            &codecs,
-        );
-        system_state.apply(world);
-
-        world.send_event(DirworldNavigationEvent::EnteredRoom { path: self.path });
-
-        world.insert_resource(root_dir);
-        world.insert_resource(current_dir);
-    }
-}
-
 struct DirworldLockDoorCommand {
     path: PathBuf,
     key: Vec<u8>,
@@ -287,7 +33,7 @@ impl Command for DirworldLockDoorCommand {
         let path = self.path.clone();
         // Get existing payload
         let codecs = world.remove_resource::<DirworldCodecs>().unwrap();
-        let (payload, _) = extract_payload(&path, &codecs);
+        let (payload, _) = extract_entity_payload(&path, &codecs);
         world.insert_resource(codecs);
         let task = AsyncComputeTaskPool::get().spawn(async move {
             // Tar directory
@@ -357,7 +103,7 @@ impl Command for DirworldUnlockDoorCommand {
         let path = self.path.clone();
         // Get existing payload
         let codecs = world.remove_resource::<DirworldCodecs>().unwrap();
-        let (payload, carrier) = extract_payload(&path, &codecs);
+        let (payload, carrier) = extract_entity_payload(&path, &codecs);
         world.insert_resource(codecs);
         let task = AsyncComputeTaskPool::get().spawn(async move {
             // Decrypt archive
@@ -509,12 +255,6 @@ impl Command for DirworldSaveEntityCommand {
 
 /// Commands for dirworld navigation
 pub trait DirworldCommands {
-    /// Change the root of the world. This will also set the current directory. This is not really meant to be used in-game but is useful for editor applications.
-    fn dirworld_change_root(&mut self, path: PathBuf);
-
-    /// Move to given directory
-    fn dirworld_navigate(&mut self, path: PathBuf);
-
     /// Lock Door
     fn dirworld_lock_door(&mut self, path: PathBuf, key: Vec<u8>);
 
@@ -525,14 +265,6 @@ pub trait DirworldCommands {
 }
 
 impl<'w, 's> DirworldCommands for Commands<'w, 's> {
-    fn dirworld_change_root(&mut self, path: PathBuf) {
-        self.add(DirworldChangeRootCommand { path });
-    }
-
-    fn dirworld_navigate(&mut self, path: PathBuf) {
-        self.add(DirworldNavigateCommand { path });
-    }
-
     fn dirworld_lock_door(&mut self, path: PathBuf, key: Vec<u8>) {
         self.add(DirworldLockDoorCommand { key, path });
     }
diff --git a/src/components.rs b/src/components.rs
index ea76185..8bb2bff 100644
--- a/src/components.rs
+++ b/src/components.rs
@@ -14,3 +14,6 @@ pub struct DirworldEntity {
     pub path: PathBuf,
     pub payload: Option<DirworldEntityPayload>,
 }
+
+#[derive(Debug, Component)]
+pub struct Persist;
diff --git a/src/events.rs b/src/events.rs
index 41a0db3..4d12f5b 100644
--- a/src/events.rs
+++ b/src/events.rs
@@ -17,8 +17,17 @@ pub enum DirworldNavigationEvent {
     },
 }
 
+#[derive(Debug, Event, Deref, DerefMut)]
+pub struct DirworldLeaveRoom(pub PathBuf);
+
+#[derive(Debug, Event, Deref, DerefMut)]
+pub struct DirworldEnterRoom(pub PathBuf);
+
+#[derive(Debug, Event, Deref, DerefMut)]
+pub struct DirworldChangeRoot(pub PathBuf);
+
 #[derive(Event)]
 pub struct DirworldSpawn {
     pub entity: Entity,
     pub data: Option<Vec<u8>>,
-}
\ No newline at end of file
+}
diff --git a/src/lib.rs b/src/lib.rs
index 2bfbc57..cf56ccf 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,8 +6,9 @@ use std::{ffi::OsStr, path::PathBuf};
 
 use bevy::{ecs::system::IntoObserverSystem, prelude::*};
 use bevy_scriptum::{runtimes::lua::LuaRuntime, BuildScriptingRuntime, ScriptingRuntimeBuilder};
-use events::{DirworldNavigationEvent, DirworldSpawn};
+use events::{DirworldChangeRoot, DirworldEnterRoom, DirworldLeaveRoom, DirworldNavigationEvent, DirworldSpawn};
 use occule::Codec;
+use resources::DirworldCache;
 use resources::{
     DirworldCodecs, DirworldCurrentDir, DirworldObservers, DirworldRootDir, DirworldTasks,
     EntryType,
@@ -31,6 +32,10 @@ pub mod commands;
 
 mod systems;
 
+mod observers;
+
+mod utils;
+
 /// Payload for dirworld entities
 pub mod payload;
 
@@ -54,24 +59,27 @@ impl Plugin for DirworldPlugin {
                 Update,
                 (systems::remove_completed_tasks, lua_api::trigger_update),
             )
-            .add_systems(PostUpdate, watcher::update)
-            .add_systems(
-                PreUpdate,
-                watcher::handle_changes,
-            )
+            .add_systems(PostUpdate, (watcher::update, systems::sync_entity_transforms))
             .add_scripting::<LuaRuntime>(|runtime| {
                 let runtime = lua_api::register(runtime);
                 if let Some(register_custom) = &self.register_custom_lua_api {
                     (register_custom)(runtime);
                 }
             })
-            .add_event::<DirworldNavigationEvent>()
+            .init_resource::<DirworldCache>()
             .init_resource::<DirworldRootDir>()
             .init_resource::<DirworldCurrentDir>()
             .init_resource::<DirworldTasks>()
             .init_resource::<DirworldObservers>()
             .init_resource::<DirworldCodecs>()
-            .add_event::<DirworldWatcherEvent>();
+            .add_event::<DirworldEnterRoom>()
+            .add_event::<DirworldLeaveRoom>()
+            .add_event::<DirworldChangeRoot>()
+            .add_event::<DirworldWatcherEvent>()
+            .observe(observers::navigate_to_room)
+            .observe(observers::handle_changes)
+            .observe(observers::change_root)
+            .observe(observers::navigate_from_room);
     }
 }
 
diff --git a/src/observers.rs b/src/observers.rs
new file mode 100644
index 0000000..b321c53
--- /dev/null
+++ b/src/observers.rs
@@ -0,0 +1,142 @@
+use std::ops::Deref;
+
+use bevy::prelude::*;
+use notify::{
+    event::{MetadataKind, ModifyKind, RenameMode},
+    EventKind,
+};
+
+use crate::{
+    components::{DirworldEntity, Persist},
+    events::{DirworldChangeRoot, DirworldEnterRoom, DirworldLeaveRoom},
+    resources::{
+        DirworldCache, DirworldCodecs, DirworldCurrentDir, DirworldObservers, DirworldRootDir,
+    },
+    utils::{despawn_entity_by_path, spawn_entity},
+    DirworldWatcherEvent,
+};
+
+/// On navigation from a room, insert modified payloads into the cache
+pub fn navigate_from_room(
+    _: Trigger<DirworldLeaveRoom>,
+    entities: Query<(Entity, Ref<DirworldEntity>), Without<Persist>>,
+    mut cache: ResMut<DirworldCache>,
+    mut commands: Commands,
+) {
+    for (entity, dirworld_entity) in entities.iter() {
+        if let Some(payload) = &dirworld_entity.payload {
+            info!("Caching {entity:?}");
+            cache.insert(dirworld_entity.path.clone(), payload.clone());
+        }
+        commands.entity(entity).despawn_recursive();
+    }
+}
+
+pub fn navigate_to_room(
+    trigger: Trigger<DirworldEnterRoom>,
+    root_dir: Res<DirworldRootDir>,
+    mut cache: ResMut<DirworldCache>,
+    observers: Res<DirworldObservers>,
+    codecs: Res<DirworldCodecs>,
+    mut commands: Commands,
+) {
+    let path = &trigger.event().0;
+
+    let entries = match path.read_dir() {
+        Ok(entries) => entries
+            .flatten()
+            .map(|entry| entry.path().canonicalize())
+            .flatten()
+            .filter(|entry| {
+                !entry
+                    .file_name()
+                    .is_some_and(|file_name| file_name.to_string_lossy().starts_with("."))
+            })
+            .chain(
+                root_dir
+                    .clone()
+                    .map(|root_dir| {
+                        if root_dir == *path {
+                            None
+                        } else {
+                            Some(path.join(".."))
+                        }
+                    })
+                    .into_iter()
+                    .flatten(),
+            ),
+        Err(e) => {
+            error!("Failed to read directory \"{}\", ({:?})", path.display(), e);
+            return;
+        }
+    };
+
+    for entry in entries {
+        spawn_entity(&entry, &mut cache, &codecs, &observers, &mut commands);
+    }
+}
+
+pub fn handle_changes(
+    trigger: Trigger<DirworldWatcherEvent>,
+    mut commands: Commands,
+    dirworld_entities: Query<(Entity, &DirworldEntity)>,
+    observers: Res<DirworldObservers>,
+    codecs: Res<DirworldCodecs>,
+    mut cache: ResMut<DirworldCache>,
+) {
+    let event = &trigger.event().0;
+    info!("Watcher Event: {event:?}");
+    match event.kind {
+        EventKind::Remove(_) | EventKind::Modify(ModifyKind::Name(RenameMode::From)) => {
+            for path in &event.paths {
+                despawn_entity_by_path(&mut commands, &dirworld_entities, path);
+            }
+        }
+        EventKind::Create(_) | EventKind::Modify(ModifyKind::Name(RenameMode::To)) => {
+            for path in &event.paths {
+                spawn_entity(path, &mut cache, &codecs, &observers, &mut commands);
+            }
+        }
+        EventKind::Modify(ModifyKind::Name(RenameMode::Both)) => {
+            despawn_entity_by_path(&mut commands, &dirworld_entities, &event.paths[0]);
+            spawn_entity(
+                &event.paths[1],
+                &mut cache,
+                &codecs,
+                &observers,
+                &mut commands,
+            );
+        }
+        EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any)) => {
+            despawn_entity_by_path(&mut commands, &dirworld_entities, &event.paths[1]);
+            spawn_entity(
+                &event.paths[0],
+                &mut cache,
+                &codecs,
+                &observers,
+                &mut commands,
+            );
+        }
+        _ => {
+            // warn!("Not Processed.")
+        }
+    }
+}
+
+pub fn change_root(
+    trigger: Trigger<DirworldChangeRoot>,
+    mut root_dir: ResMut<DirworldRootDir>,
+    mut current_dir: ResMut<DirworldCurrentDir>,
+    mut commands: Commands,
+) {
+    if let DirworldRootDir(Some(old_dir)) = root_dir.deref() {
+        commands.trigger(DirworldLeaveRoom(old_dir.to_path_buf()));
+    };
+
+    let new_root = &trigger.event().0;
+    info!("Changing Root to {}", new_root.display());
+    **root_dir = Some(new_root.to_path_buf());
+    **current_dir = Some(new_root.to_path_buf());
+
+    commands.trigger(DirworldEnterRoom(new_root.to_path_buf()));
+}
diff --git a/src/resources.rs b/src/resources.rs
index c9f7b40..152a149 100644
--- a/src/resources.rs
+++ b/src/resources.rs
@@ -1,9 +1,11 @@
-use std::{collections::BTreeMap, path::PathBuf};
+use std::{collections::{BTreeMap, HashMap}, path::PathBuf};
 
 use bevy::{ecs::world::CommandQueue, prelude::*, tasks::Task};
 use multi_key_map::MultiKeyMap;
 use occule::Codec;
 
+use crate::payload::DirworldEntityPayload;
+
 /// Root directory of the world
 #[derive(Resource, Deref, DerefMut, Default)]
 pub struct DirworldRootDir(pub Option<PathBuf>);
@@ -27,3 +29,7 @@ pub enum EntryType {
     File(Option<String>),
     Folder,
 }
+
+/// Structure containing payload data for cached (non-current) rooms
+#[derive(Resource, Default, Debug, Deref, DerefMut)]
+pub struct DirworldCache(pub HashMap<PathBuf, DirworldEntityPayload>);
diff --git a/src/systems.rs b/src/systems.rs
index ac5f667..6c3bc71 100644
--- a/src/systems.rs
+++ b/src/systems.rs
@@ -1,6 +1,9 @@
-use bevy::{prelude::{Commands, ResMut}, tasks::{block_on, futures_lite::future}};
+use bevy::{
+    prelude::*,
+    tasks::{block_on, futures_lite::future},
+};
 
-use crate::resources::DirworldTasks;
+use crate::{components::DirworldEntity, payload::DirworldComponent, resources::DirworldTasks};
 
 pub fn remove_completed_tasks(mut commands: Commands, mut tasks: ResMut<DirworldTasks>) {
     tasks.retain(|_, task| {
@@ -12,3 +15,20 @@ pub fn remove_completed_tasks(mut commands: Commands, mut tasks: ResMut<Dirworld
         !task.is_finished()
     });
 }
+
+pub fn sync_entity_transforms(
+    mut dirworld_entity_query: Query<(&mut DirworldEntity, Ref<Transform>, &GlobalTransform)>,
+) {
+    for (mut dirworld_entity, transform, global_transform) in dirworld_entity_query.iter_mut() {
+        if transform.is_changed() && !transform.is_added() {
+            if let Some(payload) = &mut dirworld_entity.payload {
+                if let Some(DirworldComponent::Transform(payload_transform)) =
+                    payload.component_mut("Transform")
+                {
+                    let transform = global_transform.compute_transform();
+                    *payload_transform = transform;
+                }
+            }
+        }
+    }
+}
diff --git a/src/utils.rs b/src/utils.rs
new file mode 100644
index 0000000..df0a8b6
--- /dev/null
+++ b/src/utils.rs
@@ -0,0 +1,124 @@
+use std::{fs, path::PathBuf};
+
+use bevy::prelude::*;
+
+use crate::{
+    components::DirworldEntity, events::DirworldSpawn, payload::{DirworldComponent, DirworldEntityPayload}, resources::{DirworldCache, DirworldCodecs, DirworldObservers, EntryType}, Extensions
+};
+
+pub fn extract_entity_payload(
+    path: &PathBuf,
+    codecs: &DirworldCodecs,
+) -> (Option<DirworldEntityPayload>, Option<Vec<u8>>) {
+    let mut data = None;
+    let mut payload = None;
+
+    if path.is_dir() {
+        let payload_file_path = path.join(".door");
+        if payload_file_path.exists() {
+            if let Ok(payload_file_data) = fs::read(&payload_file_path) {
+                match rmp_serde::from_slice::<DirworldEntityPayload>(&payload_file_data) {
+                    Ok(deserialized_payload) => {
+                        payload = Some(deserialized_payload);
+                    }
+                    Err(e) => {
+                        warn!("Could not deserialize extracted payload: {e:?}");
+                    }
+                }
+            }
+        }
+    } else {
+        if let Some(extensions) = path.extensions() {
+            if let Ok(file_data) = fs::read(&path) {
+                if let Some(codec) = codecs.get(&extensions) {
+                    match codec.decode(&file_data) {
+                        Ok((carrier, extracted_payload)) => {
+                            match rmp_serde::from_slice::<DirworldEntityPayload>(&extracted_payload)
+                            {
+                                Ok(deserialized_payload) => {
+                                    data = Some(carrier);
+                                    payload = Some(deserialized_payload);
+                                }
+                                Err(e) => {
+                                    warn!("Could not deserialize extracted payload: {e:?}");
+                                    data = Some(file_data);
+                                }
+                            }
+                        }
+                        Err(e) => match e {
+                            occule::Error::DataNotEncoded => {
+                                data = Some(file_data);
+                            }
+                            _ => error!("Could not decode payload: {e:?}"),
+                        },
+                    }
+                } else {
+                    data = Some(file_data);
+                }
+            }
+        }
+    }
+
+    (payload, data)
+}
+
+pub fn spawn_entity(
+    entry: &PathBuf,
+    cache: &mut DirworldCache,
+    codecs: &DirworldCodecs,
+    observers: &DirworldObservers,
+    commands: &mut Commands,
+) {
+    let (mut payload, data) = extract_entity_payload(&entry, &codecs);
+    if let Some(cached_payload) = cache.remove(entry) {
+        payload = Some(cached_payload);
+    }
+
+    let transform = if let Some(component) = payload
+        .as_ref()
+        .and_then(|payload| payload.component("Transform"))
+    {
+        if let DirworldComponent::Transform(transform) = component {
+            transform.clone()
+        } else {
+            panic!("BAD DECOMPOSE: TRANSFORM ({component:?})");
+        }
+    } else {
+        Transform::default()
+    };
+    let entry_type = if entry.is_dir() {
+        EntryType::Folder
+    } else {
+        EntryType::File(entry.extensions())
+    };
+    let entity = commands
+        .spawn((
+            SpatialBundle {
+                transform,
+                ..Default::default()
+            },
+            DirworldEntity {
+                path: entry.clone(),
+                payload,
+            },
+        ))
+        .id();
+    if let Some(observer) = observers.get(&entry_type) {
+        commands.trigger_targets(DirworldSpawn { entity, data }, observer.clone());
+    }
+}
+
+pub fn despawn_entity_by_path(
+    commands: &mut Commands,
+    dirworld_entities: &Query<(Entity, &DirworldEntity)>,
+    path: &PathBuf,
+) {
+    if let Some((entity, _)) = dirworld_entities
+        .iter()
+        .find(|(_, dirworld_entity)| dirworld_entity.path == *path)
+    {
+        commands.entity(entity).despawn_recursive();
+    } else {
+        warn!("Failed to find entity corresponding to path for despawning: {path:?}");
+    }
+}
diff --git a/src/watcher.rs b/src/watcher.rs
index b94c0d4..78d74f2 100644
--- a/src/watcher.rs
+++ b/src/watcher.rs
@@ -1,4 +1,7 @@
-use std::{path::{Path, PathBuf}, time::Duration};
+use std::{
+    path::{Path, PathBuf},
+    time::Duration,
+};
 
 use async_channel::{Receiver, Sender};
 use bevy::{prelude::*, tasks::IoTaskPool};
@@ -9,16 +12,15 @@ use notify::{
 use notify_debouncer_full::{new_debouncer, DebounceEventResult};
 
 use crate::{
-    commands::process_entry,
     components::DirworldEntity,
-    resources::{DirworldCodecs, DirworldObservers, DirworldRootDir},
+    resources::{DirworldCache, DirworldCodecs, DirworldObservers, DirworldRootDir},
 };
 
 #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
 pub struct DirworldWatcherSet;
 
 /// Event fired when a file watcher event is caught.
-#[derive(Event)]
+#[derive(Event, Debug)]
 pub struct DirworldWatcherEvent(pub notify::Event);
 
 #[derive(Resource)]
@@ -42,23 +44,33 @@ pub fn setup(mut commands: Commands) {
 
 async fn file_watcher(rx: Receiver<PathBuf>, tx: Sender<notify::Event>) {
     let (watcher_tx, watcher_rx) = std::sync::mpsc::channel();
-    let mut debouncer = new_debouncer(Duration::from_millis(500), None, move |result: DebounceEventResult| {
-        match result {
-            Ok(events) => for event in events.iter() {
-                watcher_tx.send(event.clone()).unwrap();
+    let mut debouncer = new_debouncer(
+        Duration::from_millis(500),
+        None,
+        move |result: DebounceEventResult| match result {
+            Ok(events) => {
+                for event in events.iter() {
+                    watcher_tx.send(event.clone()).unwrap();
+                }
             }
-            Err(errors) => for error in errors.iter() {
-                error!("{error:?}");
+            Err(errors) => {
+                for error in errors.iter() {
+                    error!("{error:?}");
+                }
             }
-        }
-    }).unwrap();
+        },
+    )
+    .unwrap();
     let mut old_path: Option<PathBuf> = None;
     loop {
         while let Ok(message) = rx.try_recv() {
             if let Some(old_path) = &old_path {
                 debouncer.watcher().unwatch(old_path).unwrap();
             }
-            debouncer.watcher().watch(&message, RecursiveMode::NonRecursive).unwrap();
+            debouncer
+                .watcher()
+                .watch(&message, RecursiveMode::NonRecursive)
+                .unwrap();
             old_path = Some(message);
         }
 
@@ -70,8 +82,8 @@ async fn file_watcher(rx: Receiver<PathBuf>, tx: Sender<notify::Event>) {
 
 pub fn update(
     watcher_channels: Res<WatcherChannels>,
-    mut event_writer: EventWriter<DirworldWatcherEvent>,
     root_dir: Res<DirworldRootDir>,
+    mut commands: Commands,
 ) {
     if root_dir.is_changed() {
         if let Some(project_dir) = &root_dir.0 {
@@ -79,61 +91,8 @@ pub fn update(
         }
     } else {
         while let Ok(event) = watcher_channels.rx_changes.try_recv() {
-            event_writer.send(DirworldWatcherEvent(event));
+            commands.trigger(DirworldWatcherEvent(event));
         }
     }
 }
 
-pub fn handle_changes(
-    mut event_reader: EventReader<DirworldWatcherEvent>,
-    mut commands: Commands,
-    dirworld_entities: Query<(Entity, &DirworldEntity)>,
-    observers: Res<DirworldObservers>,
-    codecs: Res<DirworldCodecs>,
-) {
-    if !event_reader.is_empty() {
-        for DirworldWatcherEvent(event) in event_reader.read() {
-            info!("Watcher Event: {event:?}");
-            match event.kind {
-                EventKind::Remove(_) | EventKind::Modify(ModifyKind::Name(RenameMode::From))  => {
-                    for path in &event.paths {
-                        remove_entity(&mut commands, &dirworld_entities, path);
-                    }
-                }
-                EventKind::Create(_) | EventKind::Modify(ModifyKind::Name(RenameMode::To)) => {
-                    for path in &event.paths {
-                        process_entry(&mut commands, path, &observers, &codecs);
-                    }
-                }
-                EventKind::Modify(ModifyKind::Name(RenameMode::Both)) 
-                => {
-                    remove_entity(&mut commands, &dirworld_entities, &event.paths[0]);
-                    process_entry(&mut commands, &event.paths[1], &observers, &codecs);
-                }
-                // EventKind::Modify(ModifyKind::Data(DataChange::Content))
-                EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any)) => {
-                    remove_entity(&mut commands, &dirworld_entities, &event.paths[0]);
-                    process_entry(&mut commands, &event.paths[0], &observers, &codecs);
-                }
-                _ => {
-                    // warn!("Not Processed.")
-                }
-            }
-        }
-    }
-}
-
-fn remove_entity(
-    commands: &mut Commands,
-    dirworld_entities: &Query<(Entity, &DirworldEntity)>,
-    path: &Path,
-) {
-    if let Some((entity, _)) = dirworld_entities
-        .iter()
-        .find(|(_, dirworld_entity)| dirworld_entity.path == *path)
-    {
-        commands.entity(entity).despawn_recursive();
-    } else {
-        warn!("Failed to find entity corresponding to path for despawning: {path:?}");
-    }
-}