diff --git a/CMakeLists.txt b/CMakeLists.txt
index a32145ae5595b340090f99acc54a87be81802d83..9ec52c8191afa4ed7f9d38a639c0f64c19019b48 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -270,7 +270,6 @@ message("<<< glfw")
 
 target_link_libraries(lava.frame
         lava::base
-        lava::file
         glfw
         ${GLFW_LIBRARIES}
         )
diff --git a/liblava/app/app.cpp b/liblava/app/app.cpp
index e81aa23593df5a29489efc3c6a79ea95aec6b93e..04ceb02028a7c0346db2681f5f6b34e70939addd 100644
--- a/liblava/app/app.cpp
+++ b/liblava/app/app.cpp
@@ -94,6 +94,15 @@ namespace lava {
         if (!frame::ready())
             return false;
 
+        log()->debug("physfs {}", str(to_string(file_system::get_version())));
+
+        if (!file_system::instance().initialize(str(get_cmd_line()[0]), get_config().org, get_config().app, get_config().ext)) {
+            log()->error("init file system");
+            return false;
+        }
+
+        file_system::instance().mount_res();
+
         handle_config();
 
         auto& cmd_line = get_cmd_line();
@@ -145,6 +154,8 @@ namespace lava {
 
             config_file.save();
             config_file.remove(&config_callback);
+
+            file_system::instance().terminate();
         });
 
         add_run_once([&]() {
@@ -401,4 +412,93 @@ namespace lava {
             window.set_icon(icon.data, icon.size);
     }
 
+    void to_json(json& j, window::state const& w) {
+        j = json{ { _x_, w.x }, { _y_, w.y }, { _width_, w.width }, { _height_, w.height }, { _fullscreen_, w.fullscreen }, { _floating_, w.floating }, { _resizable_, w.resizable }, { _decorated_, w.decorated }, { _maximized_, w.maximized }, { _monitor_, w.monitor } };
+    }
+
+    void from_json(json const& j, window::state& w) {
+        if (j.count(_x_))
+            w.x = j.at(_x_).get<int>();
+        if (j.count(_y_))
+            w.y = j.at(_y_).get<int>();
+        if (j.count(_width_))
+            w.width = j.at(_width_).get<int>();
+        if (j.count(_height_))
+            w.height = j.at(_height_).get<int>();
+        if (j.count(_fullscreen_))
+            w.fullscreen = j.at(_fullscreen_).get<bool>();
+        if (j.count(_floating_))
+            w.floating = j.at(_floating_).get<bool>();
+        if (j.count(_resizable_))
+            w.resizable = j.at(_resizable_).get<bool>();
+        if (j.count(_decorated_))
+            w.decorated = j.at(_decorated_).get<bool>();
+        if (j.count(_maximized_))
+            w.maximized = j.at(_maximized_).get<bool>();
+        if (j.count(_monitor_))
+            w.monitor = j.at(_monitor_).get<int>();
+    }
+
 } // namespace lava
+
+bool lava::window_file() {
+    return file_system::exists(_window_file_);
+}
+
+lava::window::state::optional lava::load_window_state(name save_name) {
+    if (!window_file())
+        return {};
+
+    window::state window_state;
+    if (!load_window_file(window_state, save_name))
+        return {};
+
+    return window_state;
+}
+
+bool lava::load_window_file(window::state& state, name save_name) {
+    scope_data data;
+    if (!load_file_data(_window_file_, data))
+        return false;
+
+    auto j = json::parse(data.ptr, data.ptr + data.size);
+
+    if (!j.count(save_name))
+        return false;
+
+    log()->trace("load window {}", str(j.dump()));
+
+    state = j[save_name];
+    return true;
+}
+
+void lava::save_window_file(window::ref window) {
+    window::state state = window.get_state();
+    auto index = window.get_save_name();
+
+    json j;
+
+    scope_data data;
+    if (load_file_data(_window_file_, data)) {
+        j = json::parse(data.ptr, data.ptr + data.size);
+
+        json d;
+        d[index] = state;
+
+        j.merge_patch(d);
+    } else {
+        j[index] = state;
+    }
+
+    file file(str(_window_file_), true);
+    if (!file.opened()) {
+        log()->error("save window {}", str(j.dump()));
+        return;
+    }
+
+    auto jString = j.dump(4);
+
+    file.write(jString.data(), jString.size());
+
+    log()->trace("save window {}", str(j.dump()));
+}
diff --git a/liblava/app/app.hpp b/liblava/app/app.hpp
index 201458d42285bbab5ef012b2d5f07218f62965db..d47b3c55a9650392cc885c42901206419829c475 100644
--- a/liblava/app/app.hpp
+++ b/liblava/app/app.hpp
@@ -105,4 +105,12 @@ namespace lava {
         id block_command;
     };
 
+    bool window_file();
+
+    window::state::optional load_window_state(name save_name = _default_);
+
+    bool load_window_file(window::state& state, name save_name);
+
+    void save_window_file(window::ref window);
+
 } // namespace lava
diff --git a/liblava/core/types.hpp b/liblava/core/types.hpp
index 1a82ea568835489ee02b13e27dfeca7e26259b41..e5e3e174ace7e320ed46528b3fa75f57d151c910 100644
--- a/liblava/core/types.hpp
+++ b/liblava/core/types.hpp
@@ -87,6 +87,7 @@ namespace lava {
 
     constexpr name _lava_ = "lava";
     constexpr name _liblava_ = "liblava";
+    constexpr name _zip_ = "zip";
 
     inline name str(string_ref value) {
         return value.c_str();
diff --git a/liblava/file/file_system.hpp b/liblava/file/file_system.hpp
index 5e5a8032b5eba9a88e068ba4f3aa798b4ff06b1d..319b80ef12a061f2b5fd615afb503eaba3dc5c38 100644
--- a/liblava/file/file_system.hpp
+++ b/liblava/file/file_system.hpp
@@ -9,8 +9,6 @@
 
 namespace lava {
 
-    constexpr name _zip_ = "zip";
-
     namespace fs = std::filesystem;
 
     struct file_system : no_copy_no_move {
diff --git a/liblava/frame/frame.cpp b/liblava/frame/frame.cpp
index b7b373de3a8c722d8f868c79ce6c52096733dc50..d893ed17ba22e55135147b12e18c13fb217c3ec0 100644
--- a/liblava/frame/frame.cpp
+++ b/liblava/frame/frame.cpp
@@ -161,15 +161,6 @@ namespace lava {
             return false;
         }
 
-        log()->debug("physfs {}", str(to_string(file_system::get_version())));
-
-        if (!file_system::instance().initialize(str(cmd_line[0]), config.org, config.app, config.ext)) {
-            log()->error("init file system");
-            return false;
-        }
-
-        file_system::instance().mount_res();
-
         frame_initialized = true;
 
         log()->info("---");
@@ -192,8 +183,6 @@ namespace lava {
         log()->flush();
         spdlog::drop_all();
 
-        file_system::instance().terminate();
-
         frame_initialized = false;
     }
 
diff --git a/liblava/frame/frame.hpp b/liblava/frame/frame.hpp
index d8f2f64fbfda7501d4c99fd2bb203539285284c4..de04cb7f943935318851b2bdca3cefc8581c5f8f 100644
--- a/liblava/frame/frame.hpp
+++ b/liblava/frame/frame.hpp
@@ -7,7 +7,6 @@
 #include <argh.h>
 #include <liblava/base/device.hpp>
 #include <liblava/base/instance.hpp>
-#include <liblava/file.hpp>
 
 namespace lava {
 
diff --git a/liblava/frame/window.cpp b/liblava/frame/window.cpp
index dd6630101a557a41f68f566a5dc3aebd96360b23..d5cfa86cccb61d60d7156aafb6b65cf7733d60da 100644
--- a/liblava/frame/window.cpp
+++ b/liblava/frame/window.cpp
@@ -4,7 +4,6 @@
 
 #include <liblava/base/device.hpp>
 #include <liblava/base/instance.hpp>
-#include <liblava/file.hpp>
 #include <liblava/frame/window.hpp>
 
 #define GLFW_INCLUDE_NONE
@@ -403,97 +402,8 @@ namespace lava {
         glfwSetWindowPos(handle, (mode->width - width) / 2, (mode->height - height) / 2);
     }
 
-    void to_json(json& j, window::state const& w) {
-        j = json{ { _x_, w.x }, { _y_, w.y }, { _width_, w.width }, { _height_, w.height }, { _fullscreen_, w.fullscreen }, { _floating_, w.floating }, { _resizable_, w.resizable }, { _decorated_, w.decorated }, { _maximized_, w.maximized }, { _monitor_, w.monitor } };
-    }
-
-    void from_json(json const& j, window::state& w) {
-        if (j.count(_x_))
-            w.x = j.at(_x_).get<int>();
-        if (j.count(_y_))
-            w.y = j.at(_y_).get<int>();
-        if (j.count(_width_))
-            w.width = j.at(_width_).get<int>();
-        if (j.count(_height_))
-            w.height = j.at(_height_).get<int>();
-        if (j.count(_fullscreen_))
-            w.fullscreen = j.at(_fullscreen_).get<bool>();
-        if (j.count(_floating_))
-            w.floating = j.at(_floating_).get<bool>();
-        if (j.count(_resizable_))
-            w.resizable = j.at(_resizable_).get<bool>();
-        if (j.count(_decorated_))
-            w.decorated = j.at(_decorated_).get<bool>();
-        if (j.count(_maximized_))
-            w.maximized = j.at(_maximized_).get<bool>();
-        if (j.count(_monitor_))
-            w.monitor = j.at(_monitor_).get<int>();
-    }
-
 } // namespace lava
 
-bool lava::window_file() {
-    return file_system::exists(_window_file_);
-}
-
-lava::window::state::optional lava::load_window_state(name save_name) {
-    if (!window_file())
-        return {};
-
-    window::state window_state;
-    if (!load_window_file(window_state, save_name))
-        return {};
-
-    return window_state;
-}
-
-bool lava::load_window_file(window::state& state, name save_name) {
-    scope_data data;
-    if (!load_file_data(_window_file_, data))
-        return false;
-
-    auto j = json::parse(data.ptr, data.ptr + data.size);
-
-    if (!j.count(save_name))
-        return false;
-
-    log()->trace("load window {}", str(j.dump()));
-
-    state = j[save_name];
-    return true;
-}
-
-void lava::save_window_file(window::ref window) {
-    window::state state = window.get_state();
-    auto index = window.get_save_name();
-
-    json j;
-
-    scope_data data;
-    if (load_file_data(_window_file_, data)) {
-        j = json::parse(data.ptr, data.ptr + data.size);
-
-        json d;
-        d[index] = state;
-
-        j.merge_patch(d);
-    } else {
-        j[index] = state;
-    }
-
-    file file(str(_window_file_), true);
-    if (!file.opened()) {
-        log()->error("save window {}", str(j.dump()));
-        return;
-    }
-
-    auto jString = j.dump(4);
-
-    file.write(jString.data(), jString.size());
-
-    log()->trace("save window {}", str(j.dump()));
-}
-
 VkSurfaceKHR lava::create_surface(GLFWwindow* window) {
     VkSurfaceKHR surface = 0;
     if (failed(glfwCreateWindowSurface(instance::get(), window, memory::alloc(), &surface)))
diff --git a/liblava/frame/window.hpp b/liblava/frame/window.hpp
index 3d9cf6804652f98411e17fd4044d1530f7b5efdc..2cb703a2be156a49aadea2de14db10b7b686e7a7 100644
--- a/liblava/frame/window.hpp
+++ b/liblava/frame/window.hpp
@@ -205,14 +205,6 @@ namespace lava {
         ui32 height = 0;
     };
 
-    bool window_file();
-
-    window::state::optional load_window_state(name save_name = _default_);
-
-    bool load_window_file(window::state& state, name save_name);
-
-    void save_window_file(window::ref window);
-
     VkSurfaceKHR create_surface(GLFWwindow* window);
 
 } // namespace lava