diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt
index a6d93936..3bda82b5 100644
--- a/loader/CMakeLists.txt
+++ b/loader/CMakeLists.txt
@@ -153,13 +153,13 @@ target_link_libraries(${PROJECT_NAME} z TulipHook geode-sdk mat-json)
 # Use precompiled headers for faster builds
 if (NOT GEODE_DISABLE_PRECOMPILED_HEADERS)
 	target_precompile_headers(${PROJECT_NAME} PRIVATE
-		"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/DefaultInclude.hpp"
+		"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Geode.hpp"
 		# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Utils.hpp"
-		"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Loader.hpp"
-		"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/UI.hpp"
+		# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Loader.hpp"
+		# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/UI.hpp"
 		# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Bindings.hpp"
-		"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/include/cocos2d.h"
-		"${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/extensions/cocos-ext.h"
+		# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/include/cocos2d.h"
+		# "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/extensions/cocos-ext.h"
 	)
 endif()
 
diff --git a/loader/include/Geode/Utils.hpp b/loader/include/Geode/Utils.hpp
index 9aadbbee..5aa821cf 100644
--- a/loader/include/Geode/Utils.hpp
+++ b/loader/include/Geode/Utils.hpp
@@ -10,3 +10,4 @@
 #include "utils/file.hpp"
 #include "utils/general.hpp"
 #include "utils/timer.hpp"
+#include "utils/MiniFunction.hpp"
diff --git a/loader/include/Geode/loader/Dispatch.hpp b/loader/include/Geode/loader/Dispatch.hpp
index c020c49f..dec81ba5 100644
--- a/loader/include/Geode/loader/Dispatch.hpp
+++ b/loader/include/Geode/loader/Dispatch.hpp
@@ -28,9 +28,9 @@ namespace geode {
     // template <typename... Args>
     // class DispatchHandler : public EventHandler<DispatchEvent<Args...>> {
     //     std::string m_selector;
-    //     std::function<void(Args...)> m_callback;
+    //     utils::MiniFunction<void(Args...)> m_callback;
 
-    //     DispatchHandler(std::string const& name, std::function<void(Args...)> callback) :
+    //     DispatchHandler(std::string const& name, utils::MiniFunction<void(Args...)> callback) :
     //         m_selector(name), m_callback(callback) {}
 
     // public:
@@ -42,7 +42,7 @@ namespace geode {
     //     }
 
     //     static DispatchHandler* create(
-    //         std::string const& name, std::function<void(Args...)> callback
+    //         std::string const& name, utils::MiniFunction<void(Args...)> callback
     //     ) {
     //         return new DispatchHandler(name, callback);
     //     }
diff --git a/loader/include/Geode/loader/Event.hpp b/loader/include/Geode/loader/Event.hpp
index a95ecf57..7fb0d901 100644
--- a/loader/include/Geode/loader/Event.hpp
+++ b/loader/include/Geode/loader/Event.hpp
@@ -41,7 +41,7 @@ namespace geode {
         using Callback = ListenerResult(T*);
         using Event = T;
 
-        ListenerResult handle(std::function<Callback> fn, T* e) {
+        ListenerResult handle(utils::MiniFunction<Callback> fn, T* e) {
             return fn(e);
         }
     };
@@ -74,7 +74,7 @@ namespace geode {
             this->enable();
         }
 
-        EventListener(std::function<Callback> fn, T filter = T())
+        EventListener(utils::MiniFunction<Callback> fn, T filter = T())
           : m_callback(fn), m_filter(filter)
         {
             this->enable();
@@ -106,7 +106,7 @@ namespace geode {
             this->enable();
         }
 
-        void bind(std::function<Callback> fn) {
+        void bind(utils::MiniFunction<Callback> fn) {
             m_callback = fn;
         }
 
@@ -120,7 +120,7 @@ namespace geode {
         }
 
     protected:
-        std::function<Callback> m_callback = nullptr;
+        utils::MiniFunction<Callback> m_callback = nullptr;
         T m_filter;
     };
 
diff --git a/loader/include/Geode/loader/IPC.hpp b/loader/include/Geode/loader/IPC.hpp
index ff949f75..5802d1b2 100644
--- a/loader/include/Geode/loader/IPC.hpp
+++ b/loader/include/Geode/loader/IPC.hpp
@@ -56,7 +56,7 @@ namespace geode {
         std::string m_messageID;
 
     public:
-        ListenerResult handle(std::function<Callback> fn, IPCEvent* event);
+        ListenerResult handle(utils::MiniFunction<Callback> fn, IPCEvent* event);
 		IPCFilter(
             std::string const& modID,
             std::string const& messageID
diff --git a/loader/include/Geode/loader/Index.hpp b/loader/include/Geode/loader/Index.hpp
index 7ab3a995..7d23f462 100644
--- a/loader/include/Geode/loader/Index.hpp
+++ b/loader/include/Geode/loader/Index.hpp
@@ -26,7 +26,7 @@ namespace geode {
 	public:
 		using Callback = void(ModInstallEvent*);
 	
-        ListenerResult handle(std::function<Callback> fn, ModInstallEvent* event);
+        ListenerResult handle(utils::MiniFunction<Callback> fn, ModInstallEvent* event);
 		ModInstallFilter(std::string const& id);
 	};
 
@@ -39,7 +39,7 @@ namespace geode {
     public:
         using Callback = void(IndexUpdateEvent*);
     
-        ListenerResult handle(std::function<Callback> fn, IndexUpdateEvent* event);
+        ListenerResult handle(utils::MiniFunction<Callback> fn, IndexUpdateEvent* event);
         IndexUpdateFilter();
     };
 
diff --git a/loader/include/Geode/loader/Loader.hpp b/loader/include/Geode/loader/Loader.hpp
index d6856f19..aa178009 100644
--- a/loader/include/Geode/loader/Loader.hpp
+++ b/loader/include/Geode/loader/Loader.hpp
@@ -2,6 +2,7 @@
 
 #include <ghc/fs_fwd.hpp>
 #include "../utils/Result.hpp"
+#include "../utils/MiniFunction.hpp"
 #include "Log.hpp"
 #include "ModInfo.hpp"
 #include "Types.hpp"
@@ -10,7 +11,7 @@
 #include <mutex>
 
 namespace geode {
-    using ScheduledFunction = std::function<void GEODE_CALL(void)>;
+    using ScheduledFunction = utils::MiniFunction<void GEODE_CALL(void)>;
 
     struct InvalidGeodeFile {
         ghc::filesystem::path path;
diff --git a/loader/include/Geode/loader/ModEvent.hpp b/loader/include/Geode/loader/ModEvent.hpp
index 15c63d7c..e77f11e2 100644
--- a/loader/include/Geode/loader/ModEvent.hpp
+++ b/loader/include/Geode/loader/ModEvent.hpp
@@ -37,7 +37,7 @@ namespace geode {
         Mod* m_mod;
 
     public:
-        ListenerResult handle(std::function<Callback> fn, ModStateEvent* event);
+        ListenerResult handle(utils::MiniFunction<Callback> fn, ModStateEvent* event);
         ModStateFilter(Mod* mod, ModEventType type);
     };
 }
diff --git a/loader/include/Geode/loader/Setting.hpp b/loader/include/Geode/loader/Setting.hpp
index 8d540a9a..0c77f265 100644
--- a/loader/include/Geode/loader/Setting.hpp
+++ b/loader/include/Geode/loader/Setting.hpp
@@ -15,9 +15,7 @@ namespace geode {
     class SettingNode;
     class SettingValue;
 
-    template <class Json>
     struct JsonMaybeObject;
-    template <class Json>
     struct JsonMaybeValue;
 
     struct GEODE_DLL BoolSetting final {
@@ -27,7 +25,7 @@ namespace geode {
         std::optional<std::string> description;
         bool defaultValue;
 
-        static Result<BoolSetting> parse(JsonMaybeObject<ModJson>& obj);
+        static Result<BoolSetting> parse(JsonMaybeObject& obj);
     };
 
     struct GEODE_DLL IntSetting final {
@@ -48,7 +46,7 @@ namespace geode {
             bool input = true;
         } controls;
 
-        static Result<IntSetting> parse(JsonMaybeObject<ModJson>& obj);
+        static Result<IntSetting> parse(JsonMaybeObject& obj);
     };
 
     struct GEODE_DLL FloatSetting final {
@@ -69,7 +67,7 @@ namespace geode {
             bool input = true;
         } controls;
 
-        static Result<FloatSetting> parse(JsonMaybeObject<ModJson>& obj);
+        static Result<FloatSetting> parse(JsonMaybeObject& obj);
     };
 
     struct GEODE_DLL StringSetting final {
@@ -80,7 +78,7 @@ namespace geode {
         ValueType defaultValue;
         std::optional<std::string> match;
 
-        static Result<StringSetting> parse(JsonMaybeObject<ModJson>& obj);
+        static Result<StringSetting> parse(JsonMaybeObject& obj);
     };
 
     struct GEODE_DLL FileSetting final {
@@ -94,7 +92,7 @@ namespace geode {
             std::vector<Filter> filters;
         } controls;
 
-        static Result<FileSetting> parse(JsonMaybeObject<ModJson>& obj);
+        static Result<FileSetting> parse(JsonMaybeObject& obj);
     };
 
     struct GEODE_DLL ColorSetting final {
@@ -104,7 +102,7 @@ namespace geode {
         std::optional<std::string> description;
         ValueType defaultValue;
 
-        static Result<ColorSetting> parse(JsonMaybeObject<ModJson>& obj);
+        static Result<ColorSetting> parse(JsonMaybeObject& obj);
     };
 
     struct GEODE_DLL ColorAlphaSetting final {
@@ -114,7 +112,7 @@ namespace geode {
         std::optional<std::string> description;
         ValueType defaultValue;
 
-        static Result<ColorAlphaSetting> parse(JsonMaybeObject<ModJson>& obj);
+        static Result<ColorAlphaSetting> parse(JsonMaybeObject& obj);
     };
 
     struct GEODE_DLL CustomSetting final {
@@ -142,7 +140,7 @@ namespace geode {
     public:
         static Result<Setting> parse(
             std::string const& key,
-            JsonMaybeValue<ModJson>& obj
+            JsonMaybeValue& obj
         );
         Setting(std::string const& key, SettingKind const& kind);
 
diff --git a/loader/include/Geode/loader/SettingEvent.hpp b/loader/include/Geode/loader/SettingEvent.hpp
index 5bb37033..33a396c6 100644
--- a/loader/include/Geode/loader/SettingEvent.hpp
+++ b/loader/include/Geode/loader/SettingEvent.hpp
@@ -22,7 +22,7 @@ namespace geode {
     public:
         using Callback = void(SettingValue*);
 
-        ListenerResult handle(std::function<Callback> fn, SettingChangedEvent* event);
+        ListenerResult handle(utils::MiniFunction<Callback> fn, SettingChangedEvent* event);
         /**
          * Listen to changes on a setting, or all settings
          * @param modID Mod whose settings to listen to
@@ -42,7 +42,7 @@ namespace geode {
     public:
         using Callback = void(T);
 
-        ListenerResult handle(std::function<Callback> fn, SettingChangedEvent* event) {
+        ListenerResult handle(utils::MiniFunction<Callback> fn, SettingChangedEvent* event) {
             if (
                 m_modID == event->mod->getID() &&
                 (!m_targetKey || m_targetKey.value() == event->value->getKey())
diff --git a/loader/include/Geode/modify/Field.hpp b/loader/include/Geode/modify/Field.hpp
index 215ae308..c87b59d4 100644
--- a/loader/include/Geode/modify/Field.hpp
+++ b/loader/include/Geode/modify/Field.hpp
@@ -3,6 +3,7 @@
 #include "Traits.hpp"
 
 #include <Geode/loader/Loader.hpp>
+#include "../utils/MiniFunction.hpp"
 #include <cocos2d.h>
 #include <vector>
 
@@ -19,7 +20,7 @@ namespace geode::modifier {
     class FieldContainer {
     private:
         std::vector<void*> m_containedFields;
-        std::vector<std::function<void(void*)>> m_destructorFunctions;
+        std::vector<utils::MiniFunction<void(void*)>> m_destructorFunctions;
 
     public:
         ~FieldContainer() {
@@ -37,7 +38,7 @@ namespace geode::modifier {
             return m_containedFields.at(index);
         }
 
-        void* setField(size_t index, size_t size, std::function<void(void*)> destructor) {
+        void* setField(size_t index, size_t size, utils::MiniFunction<void(void*)> destructor) {
             m_containedFields.at(index) = operator new(size);
             m_destructorFunctions.at(index) = destructor;
             return m_containedFields.at(index);
diff --git a/loader/include/Geode/ui/EnterLayerEvent.hpp b/loader/include/Geode/ui/EnterLayerEvent.hpp
index 9199f369..08d595f2 100644
--- a/loader/include/Geode/ui/EnterLayerEvent.hpp
+++ b/loader/include/Geode/ui/EnterLayerEvent.hpp
@@ -29,7 +29,7 @@ namespace geode {
 		std::optional<std::string> m_targetID;
 	
 	public:
-        ListenerResult handle(std::function<Callback> fn, AEnterLayerEvent* event);
+        ListenerResult handle(utils::MiniFunction<Callback> fn, AEnterLayerEvent* event);
 
 		AEnterLayerFilter(
 			std::optional<std::string> const& id
@@ -61,7 +61,7 @@ namespace geode {
 		std::optional<std::string> m_targetID;
 	
 	public:
-        ListenerResult handle(std::function<Callback> fn, EnterLayerEvent<N>* event) {
+        ListenerResult handle(utils::MiniFunction<Callback> fn, EnterLayerEvent<N>* event) {
             if (m_targetID == event->getID()) {
                 fn(static_cast<T*>(event));
             }
diff --git a/loader/include/Geode/ui/MDPopup.hpp b/loader/include/Geode/ui/MDPopup.hpp
index 9ee55160..0fb46300 100644
--- a/loader/include/Geode/ui/MDPopup.hpp
+++ b/loader/include/Geode/ui/MDPopup.hpp
@@ -11,13 +11,13 @@ namespace geode {
     class MDPopup :
         public Popup<
             std::string const&, std::string const&, char const*, char const*,
-            std::function<void(bool)>> {
+            utils::MiniFunction<void(bool)>> {
     protected:
-        std::function<void(bool)> m_onClick = nullptr;
+        utils::MiniFunction<void(bool)> m_onClick = nullptr;
 
         bool setup(
             std::string const& title, std::string const& info, char const* btn1, char const* btn2,
-            std::function<void(bool)> onClick
+            utils::MiniFunction<void(bool)> onClick
         ) override;
 
         void onBtn(CCObject*);
@@ -27,7 +27,7 @@ namespace geode {
     public:
         static MDPopup* create(
             std::string const& title, std::string const& content, char const* btn1,
-            char const* btn2 = nullptr, std::function<void(bool)> onClick = nullptr
+            char const* btn2 = nullptr, utils::MiniFunction<void(bool)> onClick = nullptr
         );
     };
 }
diff --git a/loader/include/Geode/ui/SelectList.hpp b/loader/include/Geode/ui/SelectList.hpp
index 595889fc..ffb56dc0 100644
--- a/loader/include/Geode/ui/SelectList.hpp
+++ b/loader/include/Geode/ui/SelectList.hpp
@@ -14,13 +14,13 @@ namespace geode {
     protected:
         std::vector<T> m_list;
         size_t m_index = 0;
-        std::function<void(T const&, size_t)> m_onChange;
+        utils::MiniFunction<void(T const&, size_t)> m_onChange;
         cocos2d::CCLabelBMFont* m_label;
         CCMenuItemSpriteExtra* m_prevBtn;
         CCMenuItemSpriteExtra* m_nextBtn;
 
         bool init(
-            float width, std::vector<T> const& list, std::function<void(T const&, size_t)> onChange
+            float width, std::vector<T> const& list, utils::MiniFunction<void(T const&, size_t)> onChange
         ) {
             if (!cocos2d::CCMenu::init()) return false;
 
@@ -95,7 +95,7 @@ namespace geode {
 
     public:
         static SelectList* create(
-            float width, std::vector<T> const& list, std::function<void(T const&, size_t)> onChange
+            float width, std::vector<T> const& list, utils::MiniFunction<void(T const&, size_t)> onChange
         ) {
             auto ret = new SelectList();
             if (ret && ret->init(width, list, onChange)) {
diff --git a/loader/include/Geode/ui/TextRenderer.hpp b/loader/include/Geode/ui/TextRenderer.hpp
index b0719769..d749d1b5 100644
--- a/loader/include/Geode/ui/TextRenderer.hpp
+++ b/loader/include/Geode/ui/TextRenderer.hpp
@@ -122,7 +122,7 @@ namespace geode {
          * to distinguish between bold, italic and
          * regular text.
          */
-        using Font = std::function<Label(int)>;
+        using Font = utils::MiniFunction<Label(int)>;
 
     protected:
         cocos2d::CCPoint m_origin = cocos2d::CCPointZero;
diff --git a/loader/include/Geode/utils/JsonValidation.hpp b/loader/include/Geode/utils/JsonValidation.hpp
index ea5a7b68..eafc44df 100644
--- a/loader/include/Geode/utils/JsonValidation.hpp
+++ b/loader/include/Geode/utils/JsonValidation.hpp
@@ -7,7 +7,6 @@
 #include <variant>
 
 namespace geode {
-    template <class Json>
     struct JsonChecker;
 
     template <typename T, typename = void>
@@ -73,31 +72,28 @@ namespace geode {
     }
 
     template <class T>
-    using JsonValueValidator = std::function<bool(T const&)>;
+    using JsonValueValidator = utils::MiniFunction<bool(T const&)>;
 
-    template <class Json>
     struct JsonMaybeObject;
-    template <class Json>
     struct JsonMaybeValue;
 
-    template <class Json>
     struct JsonMaybeSomething {
     protected:
-        JsonChecker<Json>& m_checker;
-        Json& m_json;
+        JsonChecker& m_checker;
+        json::Value& m_json;
         std::string m_hierarchy;
         bool m_hasValue;
 
-        friend struct JsonMaybeObject<Json>;
-        friend struct JsonMaybeValue<Json>;
+        friend struct JsonMaybeObject;
+        friend struct JsonMaybeValue;
 
         GEODE_DLL void setError(std::string const& error);
 
     public:
-        GEODE_DLL Json& json();
+        GEODE_DLL json::Value& json();
 
         GEODE_DLL JsonMaybeSomething(
-            JsonChecker<Json>& checker, Json& json, std::string const& hierarchy, bool hasValue
+            JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
         );
 
         GEODE_DLL bool isError() const;
@@ -106,18 +102,17 @@ namespace geode {
         GEODE_DLL operator bool() const;
     };
 
-    template <class Json>
-    struct JsonMaybeValue : public JsonMaybeSomething<Json> {
+    struct JsonMaybeValue : public JsonMaybeSomething {
         bool m_inferType = true;
 
         GEODE_DLL JsonMaybeValue(
-            JsonChecker<Json>& checker, Json& json, std::string const& hierarchy, bool hasValue
+            JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
         );
 
-        GEODE_DLL JsonMaybeSomething<Json>& self();
+        GEODE_DLL JsonMaybeSomething& self();
 
         template <json::Type T>
-        JsonMaybeValue<Json>& as() {
+        JsonMaybeValue& as() {
             if (this->isError()) return *this;
             if (!jsonConvertibleTo(self().m_json.type(), T)) {
                 this->setError(
@@ -129,10 +124,10 @@ namespace geode {
             return *this;
         }
 
-        GEODE_DLL JsonMaybeValue<Json>& array();
+        GEODE_DLL JsonMaybeValue& array();
 
         template <json::Type... T>
-        JsonMaybeValue<Json>& asOneOf() {
+        JsonMaybeValue& asOneOf() {
             if (this->isError()) return *this;
             bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T));
             if (!isOneOf) {
@@ -146,7 +141,7 @@ namespace geode {
         }
 
         template <json::Type T>
-        JsonMaybeValue<Json>& is() {
+        JsonMaybeValue& is() {
             if (this->isError()) return *this;
             self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T);
             m_inferType = false;
@@ -154,7 +149,7 @@ namespace geode {
         }
 
         template <class T>
-        JsonMaybeValue<Json>& validate(JsonValueValidator<T> validator) {
+        JsonMaybeValue& validate(JsonValueValidator<T> validator) {
             if (this->isError()) return *this;
             try {
                 if (!validator(self().m_json.template as<T>())) {
@@ -171,35 +166,30 @@ namespace geode {
         }
 
         template <class T>
-        JsonMaybeValue<Json>& validate(bool (*validator)(T const&)) {
-            return this->validate(std::function(validator));
-        }
-
-        template <class T>
-        JsonMaybeValue<Json>& inferType() {
+        JsonMaybeValue& inferType() {
             if (this->isError() || !m_inferType) return *this;
             return this->as<getJsonType<T>()>();
         }
 
         template <class T>
-        JsonMaybeValue<Json>& intoRaw(T& target) {
+        JsonMaybeValue& intoRaw(T& target) {
             if (this->isError()) return *this;
             target = self().m_json;
             return *this;
         }
 
         template <class T>
-        JsonMaybeValue<Json>& into(T& target) {
+        JsonMaybeValue& into(T& target) {
             return this->intoAs<T, T>(target);
         }
 
         template <class T>
-        JsonMaybeValue<Json>& into(std::optional<T>& target) {
+        JsonMaybeValue& into(std::optional<T>& target) {
             return this->intoAs<T, std::optional<T>>(target);
         }
 
         template <class A, class T>
-        JsonMaybeValue<Json>& intoAs(T& target) {
+        JsonMaybeValue& intoAs(T& target) {
             this->inferType<A>();
             if (this->isError()) return *this;
 
@@ -241,7 +231,7 @@ namespace geode {
             return T();
         }
 
-        GEODE_DLL JsonMaybeObject<Json> obj();
+        GEODE_DLL JsonMaybeObject obj();
 
         template <class T>
         struct Iterator {
@@ -267,48 +257,46 @@ namespace geode {
             }
         };
 
-        GEODE_DLL JsonMaybeValue<Json> at(size_t i);
+        GEODE_DLL JsonMaybeValue at(size_t i);
 
-        GEODE_DLL Iterator<JsonMaybeValue<Json>> iterate();
+        GEODE_DLL Iterator<JsonMaybeValue> iterate();
 
-        GEODE_DLL Iterator<std::pair<std::string, JsonMaybeValue<Json>>> items();
+        GEODE_DLL Iterator<std::pair<std::string, JsonMaybeValue>> items();
     };
 
-    template <class Json>
-    struct JsonMaybeObject : JsonMaybeSomething<Json> {
+    struct JsonMaybeObject : JsonMaybeSomething {
         std::set<std::string> m_knownKeys;
 
         GEODE_DLL JsonMaybeObject(
-            JsonChecker<Json>& checker, Json& json, std::string const& hierarchy, bool hasValue
+            JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
         );
 
-        GEODE_DLL JsonMaybeSomething<Json>& self();
+        GEODE_DLL JsonMaybeSomething& self();
 
         GEODE_DLL void addKnownKey(std::string const& key);
 
-        GEODE_DLL Json& json();
+        GEODE_DLL json::Value& json();
 
-        GEODE_DLL JsonMaybeValue<Json> emptyValue();
+        GEODE_DLL JsonMaybeValue emptyValue();
 
-        GEODE_DLL JsonMaybeValue<Json> has(std::string const& key);
+        GEODE_DLL JsonMaybeValue has(std::string const& key);
 
-        GEODE_DLL JsonMaybeValue<Json> needs(std::string const& key);
+        GEODE_DLL JsonMaybeValue needs(std::string const& key);
 
         GEODE_DLL void checkUnknownKeys();
     };
 
-    template <class Json = json::Value>
     struct JsonChecker {
         std::variant<std::monostate, std::string> m_result;
-        Json& m_json;
+        json::Value& m_json;
 
-        GEODE_DLL JsonChecker(Json& json);
+        GEODE_DLL JsonChecker(json::Value& json);
 
         GEODE_DLL bool isError() const;
 
         GEODE_DLL std::string getError() const;
 
-        GEODE_DLL JsonMaybeValue<Json> root(std::string const& hierarchy);
+        GEODE_DLL JsonMaybeValue root(std::string const& hierarchy);
     };
 
 }
diff --git a/loader/include/Geode/utils/MiniFunction.hpp b/loader/include/Geode/utils/MiniFunction.hpp
index 0dd12e46..b6e335dd 100644
--- a/loader/include/Geode/utils/MiniFunction.hpp
+++ b/loader/include/Geode/utils/MiniFunction.hpp
@@ -21,7 +21,7 @@ namespace geode::utils {
     public:
         Type m_func;
 
-        explicit MiniFunctionState(Type func) : m_func(std::move(func)) {}
+        explicit MiniFunctionState(Type func) : m_func(func) {}
 
         Ret call(Args... args) const override {
             return const_cast<Type&>(m_func)(args...);
@@ -31,6 +31,38 @@ namespace geode::utils {
             return new MiniFunctionState(*this);
         }
     };
+
+    template <class Type, class Ret, class... Args>
+    class MiniFunctionStatePointer final : public MiniFunctionStateBase<Ret, Args...> {
+    public:
+        Type m_func;
+
+        explicit MiniFunctionStatePointer(Type func) : m_func(func) {}
+
+        Ret call(Args... args) const override {
+            return const_cast<Type&>(*m_func)(args...);
+        }
+
+        MiniFunctionStateBase<Ret, Args...>* clone() const override {
+            return new MiniFunctionStatePointer(*this);
+        }
+    };
+
+    template <class Type, class Ret, class Class, class... Args>
+    class MiniFunctionStateMemberPointer final : public MiniFunctionStateBase<Ret, Class, Args...> {
+    public:
+        Type m_func;
+
+        explicit MiniFunctionStateMemberPointer(Type func) : m_func(func) {}
+
+        Ret call(Class self, Args... args) const override {
+            return const_cast<Type&>(self->*m_func)(args...);
+        }
+
+        MiniFunctionStateBase<Ret, Class, Args...>* clone() const override {
+            return new MiniFunctionStateMemberPointer(*this);
+        }
+    };
     
     template <class Callable, class Ret, class... Args>
     concept MiniFunctionCallable = requires(Callable&& func, Args... args) {
@@ -49,6 +81,8 @@ namespace geode::utils {
     public:
         MiniFunction() : m_state(nullptr) {}
 
+        MiniFunction(std::nullptr_t) : MiniFunction() {}
+
         MiniFunction(MiniFunction const& other) :
             m_state(other.m_state ? other.m_state->clone() : nullptr) {}
 
@@ -65,6 +99,16 @@ namespace geode::utils {
         MiniFunction(Callable&& func) :
             m_state(new MiniFunctionState<std::decay_t<Callable>, Ret, Args...>(std::forward<Callable>(func))) {}
 
+        template <class FunctionPointer> 
+        requires(!MiniFunctionCallable<FunctionPointer, Ret, Args...> && std::is_pointer_v<FunctionPointer> && std::is_function_v<std::remove_pointer_t<FunctionPointer>>)
+        MiniFunction(FunctionPointer func) :
+            m_state(new MiniFunctionStatePointer<FunctionPointer, Ret, Args...>(func)) {}
+
+        template <class MemberFunctionPointer> 
+        requires(std::is_member_function_pointer_v<MemberFunctionPointer>)
+        MiniFunction(MemberFunctionPointer func) :
+            m_state(new MiniFunctionStateMemberPointer<MemberFunctionPointer, Ret, Args...>(func)) {}
+
         MiniFunction& operator=(MiniFunction const& other) {
             delete m_state;
             m_state = other.m_state ? other.m_state->clone() : nullptr;
@@ -79,6 +123,7 @@ namespace geode::utils {
         }
 
         Ret operator()(Args... args) const {
+            if (!m_state) return Ret();
             return m_state->call(args...);
         }
 
diff --git a/loader/include/Geode/utils/cocos.hpp b/loader/include/Geode/utils/cocos.hpp
index 52b09c78..401400fb 100644
--- a/loader/include/Geode/utils/cocos.hpp
+++ b/loader/include/Geode/utils/cocos.hpp
@@ -8,6 +8,7 @@
 #include <functional>
 #include <type_traits>
 #include "../loader/Event.hpp"
+#include "MiniFunction.hpp"
 
 // support converting ccColor3B / ccColor4B to / from json
 
@@ -468,7 +469,7 @@ namespace geode::cocos {
      */
     GEODE_DLL cocos2d::CCScene* switchToScene(cocos2d::CCLayer* layer);
 
-    using CreateLayerFunc = std::function<cocos2d::CCLayer*()>;
+    using CreateLayerFunc = utils::MiniFunction<cocos2d::CCLayer*()>;
 
     /**
      * Reload textures, overwriting the scene to return to after the loading
@@ -518,7 +519,7 @@ namespace geode::cocos {
      * there is none
      */
     template <class Type = cocos2d::CCNode>
-    Type* findFirstChildRecursive(cocos2d::CCNode* node, std::function<bool(Type*)> predicate) {
+    Type* findFirstChildRecursive(cocos2d::CCNode* node, utils::MiniFunction<bool(Type*)> predicate) {
         if (cast::safe_cast<Type*>(node) && predicate(static_cast<Type*>(node)))
             return static_cast<Type*>(node);
 
@@ -707,7 +708,7 @@ namespace geode::cocos {
     }
 
     template <typename T, typename C, typename = std::enable_if_t<std::is_pointer_v<C>>>
-    static cocos2d::CCArray* vectorToCCArray(std::vector<T> const& vec, std::function<C(T)> convFunc) {
+    static cocos2d::CCArray* vectorToCCArray(std::vector<T> const& vec, utils::MiniFunction<C(T)> convFunc) {
         auto res = cocos2d::CCArray::createWithCapacity(vec.size());
         for (auto const& item : vec)
             res->addObject(convFunc(item));
@@ -734,7 +735,7 @@ namespace geode::cocos {
     template <
         typename K, typename V, typename C,
         typename = std::enable_if_t<std::is_same_v<C, std::string> || std::is_same_v<C, intptr_t>>>
-    static cocos2d::CCDictionary* mapToCCDict(std::map<K, V> const& map, std::function<C(K)> convFunc) {
+    static cocos2d::CCDictionary* mapToCCDict(std::map<K, V> const& map, utils::MiniFunction<C(K)> convFunc) {
         auto res = cocos2d::CCDictionary::create();
         for (auto const& [key, value] : map)
             res->setObject(value, convFunc(key));
diff --git a/loader/include/Geode/utils/map.hpp b/loader/include/Geode/utils/map.hpp
index e5110a27..f426fe7d 100644
--- a/loader/include/Geode/utils/map.hpp
+++ b/loader/include/Geode/utils/map.hpp
@@ -20,7 +20,7 @@ namespace geode::utils::map {
      * false if not.
      */
     template <typename T, typename R>
-    bool contains(std::unordered_map<T, R> const& map, std::function<bool(R)> containFunc) {
+    bool contains(std::unordered_map<T, R> const& map, utils::MiniFunction<bool(R)> containFunc) {
         for (auto const& [_, r] : map) {
             if (containFunc(r)) return true;
         }
@@ -39,7 +39,7 @@ namespace geode::utils::map {
      * a pointer.
      */
     template <class T, class R>
-    R select(std::unordered_map<T, R> const& map, std::function<bool(R)> selectFunc) {
+    R select(std::unordered_map<T, R> const& map, utils::MiniFunction<bool(R)> selectFunc) {
         for (auto const& [_, r] : map) {
             if (selectFunc(r)) return r;
         }
@@ -59,7 +59,7 @@ namespace geode::utils::map {
      */
     template <class T, class R>
     std::vector<R> selectAll(
-        std::unordered_map<T, R> const& map, std::function<bool(R)> selectFunc
+        std::unordered_map<T, R> const& map, utils::MiniFunction<bool(R)> selectFunc
     ) {
         std::vector<R> res;
         for (auto const& [_, r] : map) {
@@ -111,7 +111,7 @@ namespace geode::utils::map {
     template <class T1, class V1, class T2, class V2>
     std::unordered_map<T2, V2> remap(
         std::unordered_map<T1, V1> const& map,
-        std::function<std::pair<T2, V2>(std::pair<T1, V1>)> remapFunc
+        utils::MiniFunction<std::pair<T2, V2>(std::pair<T1, V1>)> remapFunc
     ) {
         std::unordered_map<T2, V2> res;
         for (auto const& [t, v] : map) {
diff --git a/loader/include/Geode/utils/web.hpp b/loader/include/Geode/utils/web.hpp
index 05c18bea..286142ae 100644
--- a/loader/include/Geode/utils/web.hpp
+++ b/loader/include/Geode/utils/web.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "../DefaultInclude.hpp"
+#include "MiniFunction.hpp"
 #include <json.hpp>
 #include "Result.hpp"
 #include "general.hpp"
@@ -11,7 +12,7 @@
 namespace geode::utils::web {
     GEODE_DLL void openLinkInBrowser(std::string const& url);
 
-    using FileProgressCallback = std::function<bool(double, double)>;
+    using FileProgressCallback = utils::MiniFunction<bool(double, double)>;
 
     /**
      * Synchronously fetch data from the internet
@@ -54,11 +55,11 @@ namespace geode::utils::web {
     class AsyncWebResponse;
     class AsyncWebRequest;
 
-    using AsyncProgress = std::function<void(SentAsyncWebRequest&, double, double)>;
-    using AsyncExpect = std::function<void(std::string const&)>;
-    using AsyncExpectCode = std::function<void(std::string const&, int)>;
-    using AsyncThen = std::function<void(SentAsyncWebRequest&, ByteVector const&)>;
-    using AsyncCancelled = std::function<void(SentAsyncWebRequest&)>;
+    using AsyncProgress = utils::MiniFunction<void(SentAsyncWebRequest&, double, double)>;
+    using AsyncExpect = utils::MiniFunction<void(std::string const&)>;
+    using AsyncExpectCode = utils::MiniFunction<void(std::string const&, int)>;
+    using AsyncThen = utils::MiniFunction<void(SentAsyncWebRequest&, ByteVector const&)>;
+    using AsyncCancelled = utils::MiniFunction<void(SentAsyncWebRequest&)>;
 
     /**
      * A handle to an in-progress sent asynchronous web request. Use this to
@@ -217,7 +218,7 @@ namespace geode::utils::web {
          * @returns The original AsyncWebRequest, where you can specify more
          * aspects about the request like failure and progress callbacks
          */
-        AsyncWebRequest& then(std::function<void(T)> handle);
+        AsyncWebRequest& then(utils::MiniFunction<void(T)> handle);
         /**
          * Specify a callback to run after a download is finished. Runs in the
          * GD thread, so interacting with UI is safe
@@ -225,7 +226,7 @@ namespace geode::utils::web {
          * @returns The original AsyncWebRequest, where you can specify more
          * aspects about the request like failure and progress callbacks
          */
-        AsyncWebRequest& then(std::function<void(SentAsyncWebRequest&, T)> handle);
+        AsyncWebRequest& then(utils::MiniFunction<void(SentAsyncWebRequest&, T)> handle);
     };
 
     class GEODE_DLL AsyncWebResponse {
@@ -294,7 +295,7 @@ namespace geode::utils::web {
     };
 
     template <class T>
-    AsyncWebRequest& AsyncWebResult<T>::then(std::function<void(T)> handle) {
+    AsyncWebRequest& AsyncWebResult<T>::then(utils::MiniFunction<void(T)> handle) {
         m_request.m_then = [converter = m_converter,
                             handle](SentAsyncWebRequest& req, ByteVector const& arr) {
             auto conv = converter(arr);
@@ -309,7 +310,7 @@ namespace geode::utils::web {
     }
 
     template <class T>
-    AsyncWebRequest& AsyncWebResult<T>::then(std::function<void(SentAsyncWebRequest&, T)> handle) {
+    AsyncWebRequest& AsyncWebResult<T>::then(utils::MiniFunction<void(SentAsyncWebRequest&, T)> handle) {
         m_request.m_then = [converter = m_converter,
                             handle](SentAsyncWebRequest& req, ByteVector const& arr) {
             auto conv = converter(arr);
diff --git a/loader/src/internal/FileWatcher.hpp b/loader/src/internal/FileWatcher.hpp
index 427f8949..c42b62bf 100644
--- a/loader/src/internal/FileWatcher.hpp
+++ b/loader/src/internal/FileWatcher.hpp
@@ -2,14 +2,15 @@
 
 #include <Geode/DefaultInclude.hpp>
 //#include <Geode/utils/general.hpp>
+#include <Geode/utils/MiniFunction.hpp>
 #include <ghc/fs_fwd.hpp>
 #include <functional>
 #include <string>
 
 class FileWatcher {
 public:
-    using FileWatchCallback = std::function<void(ghc::filesystem::path)>;
-    using ErrorCallback = std::function<void(std::string)>;
+    using FileWatchCallback = geode::utils::MiniFunction<void(ghc::filesystem::path)>;
+    using ErrorCallback = geode::utils::MiniFunction<void(std::string)>;
 
 protected:
     ghc::filesystem::path m_file;
diff --git a/loader/src/loader/IPC.cpp b/loader/src/loader/IPC.cpp
index 1dd71e23..ea26d467 100644
--- a/loader/src/loader/IPC.cpp
+++ b/loader/src/loader/IPC.cpp
@@ -24,7 +24,7 @@ IPCEvent::IPCEvent(
 
 IPCEvent::~IPCEvent() {}
 
-ListenerResult IPCFilter::handle(std::function<Callback> fn, IPCEvent* event) {
+ListenerResult IPCFilter::handle(utils::MiniFunction<Callback> fn, IPCEvent* event) {
     if (event->targetModID == m_modID && event->messageID == m_messageID) {
         event->replyData = fn(event);
         return ListenerResult::Stop;
diff --git a/loader/src/loader/Index.cpp b/loader/src/loader/Index.cpp
index 871b9d31..e9488aca 100644
--- a/loader/src/loader/Index.cpp
+++ b/loader/src/loader/Index.cpp
@@ -17,7 +17,7 @@ ModInstallEvent::ModInstallEvent(
     std::string const& id, const UpdateStatus status
 ) : modID(id), status(status) {}
 
-ListenerResult ModInstallFilter::handle(std::function<Callback> fn, ModInstallEvent* event) {
+ListenerResult ModInstallFilter::handle(utils::MiniFunction<Callback> fn, ModInstallEvent* event) {
     if (m_id == event->modID) {
         fn(event);
     }
@@ -67,7 +67,7 @@ class SourceUpdateFilter : public EventFilter<SourceUpdateEvent> {
 public:
     using Callback = void(SourceUpdateEvent*);
 
-    ListenerResult handle(std::function<Callback> fn, SourceUpdateEvent* event) {
+    ListenerResult handle(utils::MiniFunction<Callback> fn, SourceUpdateEvent* event) {
         fn(event);
         return ListenerResult::Propagate;
     }
@@ -79,7 +79,7 @@ public:
 IndexUpdateEvent::IndexUpdateEvent(const UpdateStatus status) : status(status) {}
 
 ListenerResult IndexUpdateFilter::handle(
-    std::function<Callback> fn,
+    utils::MiniFunction<Callback> fn,
     IndexUpdateEvent* event
 ) {
     fn(event);
diff --git a/loader/src/loader/LoaderImpl.cpp b/loader/src/loader/LoaderImpl.cpp
index e915c4d6..b75d138a 100644
--- a/loader/src/loader/LoaderImpl.cpp
+++ b/loader/src/loader/LoaderImpl.cpp
@@ -467,8 +467,8 @@ bool Loader::Impl::platformConsoleOpen() const {
 }
 
 void Loader::Impl::fetchLatestGithubRelease(
-    std::function<void(json::Value const&)> then,
-    std::function<void(std::string const&)> expect
+    utils::MiniFunction<void(json::Value const&)> then,
+    utils::MiniFunction<void(std::string const&)> expect
 ) {
     if (m_latestGithubRelease) {
         return then(m_latestGithubRelease.value());
@@ -735,7 +735,7 @@ ResourceDownloadEvent::ResourceDownloadEvent(
 ) : status(status) {}
 
 ListenerResult ResourceDownloadFilter::handle(
-    std::function<Callback> fn,
+    utils::MiniFunction<Callback> fn,
     ResourceDownloadEvent* event
 ) {
     fn(event);
@@ -749,7 +749,7 @@ LoaderUpdateEvent::LoaderUpdateEvent(
 ) : status(status) {}
 
 ListenerResult LoaderUpdateFilter::handle(
-    std::function<Callback> fn,
+    utils::MiniFunction<Callback> fn,
     LoaderUpdateEvent* event
 ) {
     fn(event);
diff --git a/loader/src/loader/LoaderImpl.hpp b/loader/src/loader/LoaderImpl.hpp
index 548f9c40..fde4ae6f 100644
--- a/loader/src/loader/LoaderImpl.hpp
+++ b/loader/src/loader/LoaderImpl.hpp
@@ -9,6 +9,7 @@
 #include <Geode/utils/Result.hpp>
 #include <Geode/utils/map.hpp>
 #include <Geode/utils/ranges.hpp>
+#include <Geode/utils/MiniFunction.hpp>
 #include "ModImpl.hpp"
 #include <about.hpp>
 #include <crashlog.hpp>
@@ -31,7 +32,7 @@ namespace geode {
     public:
         using Callback = void(ResourceDownloadEvent*);
 
-        ListenerResult handle(std::function<Callback> fn, ResourceDownloadEvent* event);
+        ListenerResult handle(utils::MiniFunction<Callback> fn, ResourceDownloadEvent* event);
         ResourceDownloadFilter();
     };
 
@@ -44,7 +45,7 @@ namespace geode {
     public:
         using Callback = void(LoaderUpdateEvent*);
 
-        ListenerResult handle(std::function<Callback> fn, LoaderUpdateEvent* event);
+        ListenerResult handle(utils::MiniFunction<Callback> fn, LoaderUpdateEvent* event);
         LoaderUpdateFilter();
     };
 
@@ -67,7 +68,7 @@ namespace geode {
         std::condition_variable m_earlyLoadFinishedCV;
         std::mutex m_earlyLoadFinishedMutex;
         std::atomic_bool m_earlyLoadFinished = false;
-        std::vector<std::function<void(void)>> m_gdThreadQueue;
+        std::vector<utils::MiniFunction<void(void)>> m_gdThreadQueue;
         mutable std::mutex m_gdThreadMutex;
         bool m_platformConsoleOpen = false;
         std::vector<std::pair<Hook*, Mod*>> m_internalHooks;
@@ -94,8 +95,8 @@ namespace geode {
         void downloadLoaderResources(bool useLatestRelease = false);
         void downloadLoaderUpdate(std::string const& url);
         void fetchLatestGithubRelease(
-            std::function<void(json::Value const&)> then,
-            std::function<void(std::string const&)> expect
+            utils::MiniFunction<void(json::Value const&)> then,
+            utils::MiniFunction<void(std::string const&)> expect
         );
 
         bool loadHooks();
diff --git a/loader/src/loader/ModEvent.cpp b/loader/src/loader/ModEvent.cpp
index 753d8e5d..d83e02a5 100644
--- a/loader/src/loader/ModEvent.cpp
+++ b/loader/src/loader/ModEvent.cpp
@@ -12,7 +12,7 @@ Mod* ModStateEvent::getMod() const {
     return m_mod;
 }
 
-ListenerResult ModStateFilter::handle(std::function<Callback> fn, ModStateEvent* event) {
+ListenerResult ModStateFilter::handle(utils::MiniFunction<Callback> fn, ModStateEvent* event) {
     if (event->getMod() == m_mod && event->getType() == m_type) {
         fn(event);
     }
diff --git a/loader/src/loader/ModInfo.cpp b/loader/src/loader/ModInfo.cpp
index 0529b8f8..9bd7e477 100644
--- a/loader/src/loader/ModInfo.cpp
+++ b/loader/src/loader/ModInfo.cpp
@@ -87,7 +87,7 @@ Result<ModInfo> ModInfo::Impl::createFromSchemaV010(ModJson const& rawJson) {
 
     root.addKnownKey("geode");
 
-    root.needs("id").validate(&ModInfo::validateID).into(impl->m_id);
+    root.needs("id").validate(MiniFunction<bool(std::string const&)>(&ModInfo::validateID)).into(impl->m_id);
     root.needs("version").into(impl->m_version);
     root.needs("name").into(impl->m_name);
     root.needs("developer").into(impl->m_developer);
@@ -105,7 +105,7 @@ Result<ModInfo> ModInfo::Impl::createFromSchemaV010(ModJson const& rawJson) {
         auto obj = dep.obj();
 
         auto depobj = Dependency{};
-        obj.needs("id").validate(&ModInfo::validateID).into(depobj.id);
+        obj.needs("id").validate(MiniFunction<bool(std::string const&)>(&ModInfo::validateID)).into(depobj.id);
         obj.needs("version").into(depobj.version);
         obj.has("required").into(depobj.required);
         obj.checkUnknownKeys();
diff --git a/loader/src/loader/Setting.cpp b/loader/src/loader/Setting.cpp
index 63709414..4b5d0b3e 100644
--- a/loader/src/loader/Setting.cpp
+++ b/loader/src/loader/Setting.cpp
@@ -11,19 +11,19 @@
 USE_GEODE_NAMESPACE();
 
 template<class T>
-static void parseCommon(T& sett, JsonMaybeObject<ModJson>& obj) {
+static void parseCommon(T& sett, JsonMaybeObject& obj) {
     obj.has("name").into(sett.name);
     obj.has("description").into(sett.description);
     obj.has("default").into(sett.defaultValue);
 }
 
-Result<BoolSetting> BoolSetting::parse(JsonMaybeObject<ModJson>& obj) {
+Result<BoolSetting> BoolSetting::parse(JsonMaybeObject& obj) {
     BoolSetting sett;
     parseCommon(sett, obj);
     return Ok(sett);
 }
 
-Result<IntSetting> IntSetting::parse(JsonMaybeObject<ModJson>& obj) {
+Result<IntSetting> IntSetting::parse(JsonMaybeObject& obj) {
     IntSetting sett;
     parseCommon(sett, obj);
     obj.has("min").into(sett.min);
@@ -40,7 +40,7 @@ Result<IntSetting> IntSetting::parse(JsonMaybeObject<ModJson>& obj) {
     return Ok(sett);
 }
 
-Result<FloatSetting> FloatSetting::parse(JsonMaybeObject<ModJson>& obj) {
+Result<FloatSetting> FloatSetting::parse(JsonMaybeObject& obj) {
     FloatSetting sett;
     parseCommon(sett, obj);
     obj.has("min").into(sett.min);
@@ -57,14 +57,14 @@ Result<FloatSetting> FloatSetting::parse(JsonMaybeObject<ModJson>& obj) {
     return Ok(sett);
 }
 
-Result<StringSetting> StringSetting::parse(JsonMaybeObject<ModJson>& obj) {
+Result<StringSetting> StringSetting::parse(JsonMaybeObject& obj) {
     StringSetting sett;
     parseCommon(sett, obj);
     obj.has("match").into(sett.match);
     return Ok(sett);
 }
 
-Result<FileSetting> FileSetting::parse(JsonMaybeObject<ModJson>& obj) {
+Result<FileSetting> FileSetting::parse(JsonMaybeObject& obj) {
     FileSetting sett;
     parseCommon(sett, obj);
     if (auto controls = obj.has("control").obj()) {
@@ -87,13 +87,13 @@ Result<FileSetting> FileSetting::parse(JsonMaybeObject<ModJson>& obj) {
     return Ok(sett);
 }
 
-Result<ColorSetting> ColorSetting::parse(JsonMaybeObject<ModJson>& obj) {
+Result<ColorSetting> ColorSetting::parse(JsonMaybeObject& obj) {
     ColorSetting sett;
     parseCommon(sett, obj);
     return Ok(sett);
 }
 
-Result<ColorAlphaSetting> ColorAlphaSetting::parse(JsonMaybeObject<ModJson>& obj) {
+Result<ColorAlphaSetting> ColorAlphaSetting::parse(JsonMaybeObject& obj) {
     ColorAlphaSetting sett;
     parseCommon(sett, obj);
     return Ok(sett);
@@ -101,7 +101,7 @@ Result<ColorAlphaSetting> ColorAlphaSetting::parse(JsonMaybeObject<ModJson>& obj
 
 Result<Setting> Setting::parse(
     std::string const& key,
-    JsonMaybeValue<ModJson>& value
+    JsonMaybeValue& value
 ) {
     auto sett = Setting();
     sett.m_key = key;
@@ -378,7 +378,7 @@ SettingChangedEvent::SettingChangedEvent(Mod* mod, SettingValue* value)
 // SettingChangedFilter
 
 ListenerResult SettingChangedFilter::handle(
-    std::function<Callback> fn, SettingChangedEvent* event
+    utils::MiniFunction<Callback> fn, SettingChangedEvent* event
 ) {
     if (m_modID == event->mod->getID() &&
         (!m_targetKey || m_targetKey.value() == event->value->getKey())
diff --git a/loader/src/ui/nodes/EnterLayerEvent.cpp b/loader/src/ui/nodes/EnterLayerEvent.cpp
index 8583b626..3805cae2 100644
--- a/loader/src/ui/nodes/EnterLayerEvent.cpp
+++ b/loader/src/ui/nodes/EnterLayerEvent.cpp
@@ -8,7 +8,7 @@ AEnterLayerEvent::AEnterLayerEvent(
 ) : layerID(layerID),
     layer(layer) {}
 
-ListenerResult AEnterLayerFilter::handle(std::function<Callback> fn, AEnterLayerEvent* event) {
+ListenerResult AEnterLayerFilter::handle(utils::MiniFunction<Callback> fn, AEnterLayerEvent* event) {
     if (m_targetID == event->layerID) {
         fn(event);
     }
diff --git a/loader/src/ui/nodes/MDPopup.cpp b/loader/src/ui/nodes/MDPopup.cpp
index 96426985..64b23545 100644
--- a/loader/src/ui/nodes/MDPopup.cpp
+++ b/loader/src/ui/nodes/MDPopup.cpp
@@ -6,7 +6,7 @@ USE_GEODE_NAMESPACE();
 
 bool MDPopup::setup(
     std::string const& title, std::string const& info, char const* btn1Text, char const* btn2Text,
-    std::function<void(bool)> onClick
+    utils::MiniFunction<void(bool)> onClick
 ) {
     this->setTitle(title.c_str(), "goldFont.fnt", .9f, 33.f);
 
@@ -65,7 +65,7 @@ float MDPopup::estimateHeight(std::string const& content) {
 
 MDPopup* MDPopup::create(
     std::string const& title, std::string const& content, char const* btn1, char const* btn2,
-    std::function<void(bool)> onClick
+    utils::MiniFunction<void(bool)> onClick
 ) {
     auto ret = new MDPopup();
     if (ret &&
diff --git a/loader/src/utils/JsonValidation.cpp b/loader/src/utils/JsonValidation.cpp
index b0ef31bb..0a592fc3 100644
--- a/loader/src/utils/JsonValidation.cpp
+++ b/loader/src/utils/JsonValidation.cpp
@@ -2,52 +2,52 @@
 
 USE_GEODE_NAMESPACE();
 
-template <class Json>
-Json& JsonMaybeSomething<Json>::json() {
+
+json::Value& JsonMaybeSomething::json() {
     return m_json;
 }
 
-template <class Json>
-JsonMaybeSomething<Json>::JsonMaybeSomething(
-    JsonChecker<Json>& checker, Json& json, std::string const& hierarchy, bool hasValue
+
+JsonMaybeSomething::JsonMaybeSomething(
+    JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
 ) :
     m_checker(checker),
     m_json(json), m_hierarchy(hierarchy), m_hasValue(hasValue) {}
 
-template <class Json>
-bool JsonMaybeSomething<Json>::isError() const {
+
+bool JsonMaybeSomething::isError() const {
     return m_checker.isError() || !m_hasValue;
 }
 
-template <class Json>
-std::string JsonMaybeSomething<Json>::getError() const {
+
+std::string JsonMaybeSomething::getError() const {
     return m_checker.getError();
 }
 
-template <class Json>
-JsonMaybeSomething<Json>::operator bool() const {
+
+JsonMaybeSomething::operator bool() const {
     return !isError();
 }
 
-template <class Json>
-void JsonMaybeSomething<Json>::setError(std::string const& error) {
+
+void JsonMaybeSomething::setError(std::string const& error) {
     m_checker.m_result = error;
 }
 
-template <class Json>
-JsonMaybeValue<Json>::JsonMaybeValue(
-    JsonChecker<Json>& checker, Json& json, std::string const& hierarchy, bool hasValue
-) :
-    JsonMaybeSomething<Json>(checker, json, hierarchy, hasValue) {}
 
-template <class Json>
-JsonMaybeSomething<Json>& JsonMaybeValue<Json>::self() {
-    return *static_cast<JsonMaybeSomething<Json>*>(this);
+JsonMaybeValue::JsonMaybeValue(
+    JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
+) :
+    JsonMaybeSomething(checker, json, hierarchy, hasValue) {}
+
+
+JsonMaybeSomething& JsonMaybeValue::self() {
+    return *static_cast<JsonMaybeSomething*>(this);
 }
 
 // template<class Json>
 // template<nlohmann::detail::value_t T>
-// JsonMaybeValue<Json>& JsonMaybeValue<Json>::as() {
+// JsonMaybeValue& JsonMaybeValue::as() {
 //     if (this->isError()) return *this;
 //     if (!jsonConvertibleTo(self().m_json.type(), T)) {
 //         this->setError(
@@ -60,15 +60,15 @@ JsonMaybeSomething<Json>& JsonMaybeValue<Json>::self() {
 //     return *this;
 // }
 
-template <class Json>
-JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
+
+JsonMaybeValue& JsonMaybeValue::array() {
     this->as<value_t::Array>();
     return *this;
 }
 
 // template<class Json>
 // template<nlohmann::detail::value_t... T>
-// JsonMaybeValue<Json> JsonMaybeValue<Json>::asOneOf() {
+// JsonMaybeValue JsonMaybeValue::asOneOf() {
 //     if (this->isError()) return *this;
 //     bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T));
 //     if (!isOneOf) {
@@ -84,7 +84,7 @@ JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
 
 // template<class Json>
 // template<nlohmann::detail::value_t T>
-// JsonMaybeValue<Json> JsonMaybeValue<Json>::is() {
+// JsonMaybeValue JsonMaybeValue::is() {
 //     if (this->isError()) return *this;
 //     self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T);
 //     m_inferType = false;
@@ -93,7 +93,7 @@ JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
 
 // template<class Json>
 // template<class T>
-// JsonMaybeValue<Json> JsonMaybeValue<Json>::validate(JsonValueValidator<T> validator) {
+// JsonMaybeValue JsonMaybeValue::validate(JsonValueValidator<T> validator) {
 //     if (this->isError()) return *this;
 //     try {
 //         if (!validator(self().m_json.template get<T>())) {
@@ -110,14 +110,14 @@ JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
 
 // template<class Json>
 // template<class T>
-// JsonMaybeValue<Json> JsonMaybeValue<Json>::inferType() {
+// JsonMaybeValue JsonMaybeValue::inferType() {
 //     if (this->isError() || !m_inferType) return *this;
 //     return this->as<getJsonType<T>()>();
 // }
 
 // template<class Json>
 // template<class T>
-// JsonMaybeValue<Json> JsonMaybeValue<Json>::intoRaw(T& target) {
+// JsonMaybeValue JsonMaybeValue::intoRaw(T& target) {
 //     if (this->isError()) return *this;
 //     target = self().m_json;
 //     return *this;
@@ -125,19 +125,19 @@ JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
 
 // template<class Json>
 // template<class T>
-// JsonMaybeValue<Json> JsonMaybeValue<Json>::into(T& target) {
+// JsonMaybeValue JsonMaybeValue::into(T& target) {
 //     return this->intoAs<T, T>(target);
 // }
 
 // template<class Json>
 // template<class T>
-// JsonMaybeValue<Json> JsonMaybeValue<Json>::into(std::optional<T>& target) {
+// JsonMaybeValue JsonMaybeValue::into(std::optional<T>& target) {
 //     return this->intoAs<T, std::optional<T>>(target);
 // }
 
 // template<class Json>
 // template<class A, class T>
-// JsonMaybeValue<Json> JsonMaybeValue<Json>::intoAs(T& target) {
+// JsonMaybeValue JsonMaybeValue::intoAs(T& target) {
 //     this->inferType<A>();
 //     if (this->isError()) return *this;
 //     try {
@@ -153,7 +153,7 @@ JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
 
 // template<class Json>
 // template<class T>
-// T JsonMaybeValue<Json>::get() {
+// T JsonMaybeValue::get() {
 //     this->inferType<T>();
 //     if (this->isError()) return T();
 //     try {
@@ -167,15 +167,15 @@ JsonMaybeValue<Json>& JsonMaybeValue<Json>::array() {
 //     return T();
 // }
 
-template <class Json>
-JsonMaybeObject<Json> JsonMaybeValue<Json>::obj() {
+
+JsonMaybeObject JsonMaybeValue::obj() {
     this->as<value_t::Object>();
     return JsonMaybeObject(self().m_checker, self().m_json, self().m_hierarchy, self().m_hasValue);
 }
 
 // template<class Json>
 // template<class T>
-// struct JsonMaybeValue<Json>::Iterator {
+// struct JsonMaybeValue::Iterator {
 //     std::vector<T> m_values;
 
 //     using iterator = typename std::vector<T>::iterator;
@@ -196,8 +196,8 @@ JsonMaybeObject<Json> JsonMaybeValue<Json>::obj() {
 //     }
 // };
 
-template <class Json>
-JsonMaybeValue<Json> JsonMaybeValue<Json>::at(size_t i) {
+
+JsonMaybeValue JsonMaybeValue::at(size_t i) {
     this->as<value_t::Array>();
     if (this->isError()) return *this;
 
@@ -211,15 +211,15 @@ JsonMaybeValue<Json> JsonMaybeValue<Json>::at(size_t i) {
         );
         return *this;
     }
-    return JsonMaybeValue<Json>(
+    return JsonMaybeValue(
         self().m_checker, json.at(i), self().m_hierarchy + "." + std::to_string(i), self().m_hasValue
     );
 }
 
-template <class Json>
-typename JsonMaybeValue<Json>::template Iterator<JsonMaybeValue<Json>> JsonMaybeValue<Json>::iterate() {
+
+typename JsonMaybeValue::template Iterator<JsonMaybeValue> JsonMaybeValue::iterate() {
     this->as<value_t::Array>();
-    Iterator<JsonMaybeValue<Json>> iter;
+    Iterator<JsonMaybeValue> iter;
     if (this->isError()) return iter;
 
     auto& json = self().m_json.as_array();
@@ -232,72 +232,71 @@ typename JsonMaybeValue<Json>::template Iterator<JsonMaybeValue<Json>> JsonMaybe
     return iter;
 }
 
-template <class Json>
-typename JsonMaybeValue<Json>::template Iterator<std::pair<std::string, JsonMaybeValue<Json>>> JsonMaybeValue<
-    Json>::items() {
+
+typename JsonMaybeValue::template Iterator<std::pair<std::string, JsonMaybeValue>> JsonMaybeValue::items() {
     this->as<value_t::Object>();
-    Iterator<std::pair<std::string, JsonMaybeValue<Json>>> iter;
+    Iterator<std::pair<std::string, JsonMaybeValue>> iter;
     if (this->isError()) return iter;
 
     for (auto& [k, v] : self().m_json.as_object()) {
         iter.m_values.emplace_back(
             k,
-            JsonMaybeValue<Json>(self().m_checker, v, self().m_hierarchy + "." + k, self().m_hasValue)
+            JsonMaybeValue(self().m_checker, v, self().m_hierarchy + "." + k, self().m_hasValue)
         );
     }
 
     return iter;
 }
 
-template <class Json>
-JsonMaybeObject<Json>::JsonMaybeObject(
-    JsonChecker<Json>& checker, Json& json, std::string const& hierarchy, bool hasValue
-) :
-    JsonMaybeSomething<Json>(checker, json, hierarchy, hasValue) {}
 
-template <class Json>
-JsonMaybeSomething<Json>& JsonMaybeObject<Json>::self() {
-    return *static_cast<JsonMaybeSomething<Json>*>(this);
+JsonMaybeObject::JsonMaybeObject(
+    JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue
+) :
+    JsonMaybeSomething(checker, json, hierarchy, hasValue) {}
+
+
+JsonMaybeSomething& JsonMaybeObject::self() {
+    return *static_cast<JsonMaybeSomething*>(this);
 }
 
-template <class Json>
-void JsonMaybeObject<Json>::addKnownKey(std::string const& key) {
+
+void JsonMaybeObject::addKnownKey(std::string const& key) {
     m_knownKeys.insert(key);
 }
 
-template <class Json>
-Json& JsonMaybeObject<Json>::json() {
+
+json::Value& JsonMaybeObject::json() {
     return self().m_json;
 }
 
-template <class Json>
-JsonMaybeValue<Json> JsonMaybeObject<Json>::emptyValue() {
+
+JsonMaybeValue JsonMaybeObject::emptyValue() {
     return JsonMaybeValue(self().m_checker, self().m_json, "", false);
 }
 
-template <class Json>
-JsonMaybeValue<Json> JsonMaybeObject<Json>::has(std::string const& key) {
+
+JsonMaybeValue JsonMaybeObject::has(std::string const& key) {
     this->addKnownKey(key);
     if (this->isError()) return emptyValue();
     if (!self().m_json.contains(key) || self().m_json[key].is_null()) {
         return emptyValue();
     }
-    return JsonMaybeValue<Json>(self().m_checker, self().m_json[key], key, true);
+    return JsonMaybeValue(self().m_checker, self().m_json[key], key, true);
 }
 
-template <class Json>
-JsonMaybeValue<Json> JsonMaybeObject<Json>::needs(std::string const& key) {
+
+JsonMaybeValue JsonMaybeObject::needs(std::string const& key) {
     this->addKnownKey(key);
     if (this->isError()) return emptyValue();
     if (!self().m_json.contains(key)) {
         this->setError(self().m_hierarchy + " is missing required key \"" + key + "\"");
         return emptyValue();
     }
-    return JsonMaybeValue<Json>(self().m_checker, self().m_json[key], key, true);
+    return JsonMaybeValue(self().m_checker, self().m_json[key], key, true);
 }
 
-template <class Json>
-void JsonMaybeObject<Json>::checkUnknownKeys() {
+
+void JsonMaybeObject::checkUnknownKeys() {
     for (auto& [key, _] : self().m_json.as_object()) {
         if (!m_knownKeys.count(key)) {
             log::warn("{} contains unknown key \"{}\"", self().m_hierarchy, key);
@@ -305,40 +304,20 @@ void JsonMaybeObject<Json>::checkUnknownKeys() {
     }
 }
 
-template <class Json>
-JsonChecker<Json>::JsonChecker(Json& json) : m_json(json), m_result(std::monostate()) {}
 
-template <class Json>
-bool JsonChecker<Json>::isError() const {
+JsonChecker::JsonChecker(json::Value& json) : m_json(json), m_result(std::monostate()) {}
+
+
+bool JsonChecker::isError() const {
     return std::holds_alternative<std::string>(m_result);
 }
 
-template <class Json>
-std::string JsonChecker<Json>::getError() const {
+
+std::string JsonChecker::getError() const {
     return std::get<std::string>(m_result);
 }
 
-template <class Json>
-JsonMaybeValue<Json> JsonChecker<Json>::root(std::string const& hierarchy) {
+
+JsonMaybeValue JsonChecker::root(std::string const& hierarchy) {
     return JsonMaybeValue(*this, m_json, hierarchy, true);
 }
-
-namespace geode {
-
-    template struct JsonMaybeSomething<json::Value>;
-    template struct JsonMaybeSomething<json::Value const>;
-    //template struct JsonMaybeSomething<ModJson>;
-
-    template struct JsonMaybeValue<json::Value>;
-    template struct JsonMaybeValue<json::Value const>;
-    //template struct JsonMaybeValue<ModJson>;
-
-    template struct JsonMaybeObject<json::Value>;
-    template struct JsonMaybeObject<json::Value const>;
-    //template struct JsonMaybeObject<ModJson>;
-
-    template struct JsonChecker<json::Value>;
-    template struct JsonChecker<json::Value const>;
-    //template struct JsonChecker<ModJson>;
-
-}
\ No newline at end of file