diff --git a/src/nostalgia/modules/core/src/studio/paletteeditor/paletteeditor-imgui.cpp b/src/nostalgia/modules/core/src/studio/paletteeditor/paletteeditor-imgui.cpp
index f02aad86..7d2159e3 100644
--- a/src/nostalgia/modules/core/src/studio/paletteeditor/paletteeditor-imgui.cpp
+++ b/src/nostalgia/modules/core/src/studio/paletteeditor/paletteeditor-imgui.cpp
@@ -30,7 +30,7 @@ ox::CStringView PaletteEditorImGui::itemDisplayName() const noexcept {
 	return m_itemName;
 }
 
-void PaletteEditorImGui::draw(turbine::Context*) noexcept {
+void PaletteEditorImGui::draw(turbine::Context&) noexcept {
 	static constexpr auto flags = ImGuiTableFlags_RowBg;
 	const auto paneSize = ImGui::GetContentRegionAvail();
 	ImGui::BeginChild("Colors", ImVec2(paneSize.x - 208, paneSize.y), true);
@@ -42,14 +42,14 @@ void PaletteEditorImGui::draw(turbine::Context*) noexcept {
 			if (ImGui::Button("Add", sz)) {
 				const auto colorSz = static_cast<int>(m_pal.colors.size());
 				constexpr Color16 c = 0;
-				undoStack()->push(ox::make<AddColorCommand>(&m_pal, c, colorSz));
+				undoStack()->push(ox::make_unique<AddColorCommand>(&m_pal, c, colorSz));
 			}
 			ImGui::SameLine();
 			ImGui::BeginDisabled(m_selectedRow >= m_pal.colors.size());
 			{
 				if (ImGui::Button("Remove", sz)) {
 					undoStack()->push(
-							ox::make<RemoveColorCommand>(
+							ox::make_unique<RemoveColorCommand>(
 								&m_pal,
 								m_pal.colors[static_cast<std::size_t>(m_selectedRow)],
 								static_cast<int>(m_selectedRow)));
@@ -59,7 +59,7 @@ void PaletteEditorImGui::draw(turbine::Context*) noexcept {
 				ImGui::BeginDisabled(m_selectedRow <= 0);
 				{
 					if (ImGui::Button("Move Up", sz)) {
-						undoStack()->push(ox::make<MoveColorCommand>(&m_pal, m_selectedRow, -1));
+						undoStack()->push(ox::make_unique<MoveColorCommand>(&m_pal, m_selectedRow, -1));
 						--m_selectedRow;
 					}
 				}
@@ -68,7 +68,7 @@ void PaletteEditorImGui::draw(turbine::Context*) noexcept {
 				ImGui::BeginDisabled(m_selectedRow >= m_pal.colors.size() - 1);
 				{
 					if (ImGui::Button("Move Down", sz)) {
-						undoStack()->push(ox::make<MoveColorCommand>(&m_pal, m_selectedRow, 1));
+						undoStack()->push(ox::make_unique<MoveColorCommand>(&m_pal, m_selectedRow, 1));
 						++m_selectedRow;
 					}
 				}
@@ -131,7 +131,7 @@ void PaletteEditorImGui::draw(turbine::Context*) noexcept {
 			ImGui::InputInt("Blue", &b, 1, 5);
 			const auto newColor = color16(r, g, b, a);
 			if (c != newColor) {
-				undoStack()->push(ox::make<UpdateColorCommand>(&m_pal, static_cast<int>(m_selectedRow), c, newColor));
+				undoStack()->push(ox::make_unique<UpdateColorCommand>(&m_pal, static_cast<int>(m_selectedRow), c, newColor));
 			}
 		}
 		ImGui::EndChild();
diff --git a/src/nostalgia/modules/core/src/studio/paletteeditor/paletteeditor-imgui.hpp b/src/nostalgia/modules/core/src/studio/paletteeditor/paletteeditor-imgui.hpp
index 0775c34d..0d069e80 100644
--- a/src/nostalgia/modules/core/src/studio/paletteeditor/paletteeditor-imgui.hpp
+++ b/src/nostalgia/modules/core/src/studio/paletteeditor/paletteeditor-imgui.hpp
@@ -30,7 +30,7 @@ class PaletteEditorImGui: public studio::Editor {
 
 		ox::CStringView itemDisplayName() const noexcept final;
 
-		void draw(turbine::Context*) noexcept final;
+		void draw(turbine::Context&) noexcept final;
 
 	protected:
 		ox::Error saveItem() noexcept final;
diff --git a/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp b/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp
index faffc9df..244872c6 100644
--- a/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp
+++ b/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheeteditor-imgui.cpp
@@ -106,7 +106,7 @@ void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
 	}
 }
 
-void TileSheetEditorImGui::draw(turbine::Context*) noexcept {
+void TileSheetEditorImGui::draw(turbine::Context&) noexcept {
 	const auto paneSize = ImGui::GetContentRegionAvail();
 	const auto tileSheetParentSize = ImVec2(paneSize.x - m_palViewWidth, paneSize.y);
 	const auto fbSize = ox::Vec2(tileSheetParentSize.x - 16, tileSheetParentSize.y - 16);
diff --git a/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheeteditor-imgui.hpp b/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheeteditor-imgui.hpp
index cd076267..59bae5e4 100644
--- a/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheeteditor-imgui.hpp
+++ b/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheeteditor-imgui.hpp
@@ -73,7 +73,7 @@ class TileSheetEditorImGui: public studio::BaseEditor {
 
 		void keyStateChanged(turbine::Key key, bool down) override;
 
-		void draw(turbine::Context*) noexcept override;
+		void draw(turbine::Context&) noexcept override;
 
 		void drawSubsheetSelector(TileSheet::SubSheet*, TileSheet::SubSheetIdx *path);
 
diff --git a/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheeteditormodel.cpp b/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheeteditormodel.cpp
index 44b92756..576d4b8c 100644
--- a/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheeteditormodel.cpp
+++ b/src/nostalgia/modules/core/src/studio/tilesheeteditor/tilesheeteditormodel.cpp
@@ -281,7 +281,7 @@ void TileSheetEditorModel::getFillPixels(bool *pixels, ox::Point const&pt, int o
 }
 
 void TileSheetEditorModel::pushCommand(studio::UndoCommand *cmd) noexcept {
-	m_undoStack.push(cmd);
+	m_undoStack.push(ox::UPtr<studio::UndoCommand>(cmd));
 	m_ongoingDrawCommand = dynamic_cast<DrawCommand*>(cmd);
 	m_updated = true;
 }
diff --git a/src/nostalgia/modules/scene/src/studio/sceneeditor-imgui.cpp b/src/nostalgia/modules/scene/src/studio/sceneeditor-imgui.cpp
index 8fb172c1..ccebd13f 100644
--- a/src/nostalgia/modules/scene/src/studio/sceneeditor-imgui.cpp
+++ b/src/nostalgia/modules/scene/src/studio/sceneeditor-imgui.cpp
@@ -28,7 +28,7 @@ ox::CStringView SceneEditorImGui::itemDisplayName() const noexcept {
 	return m_itemName;
 }
 
-void SceneEditorImGui::draw(turbine::Context*) noexcept {
+void SceneEditorImGui::draw(turbine::Context&) noexcept {
 	auto const paneSize = ImGui::GetContentRegionAvail();
 	m_view.draw(ox::Size{static_cast<int>(paneSize.x), static_cast<int>(paneSize.y)});
 	auto &fb = m_view.framebuffer();
diff --git a/src/nostalgia/modules/scene/src/studio/sceneeditor-imgui.hpp b/src/nostalgia/modules/scene/src/studio/sceneeditor-imgui.hpp
index fe370eb4..f4d173a4 100644
--- a/src/nostalgia/modules/scene/src/studio/sceneeditor-imgui.hpp
+++ b/src/nostalgia/modules/scene/src/studio/sceneeditor-imgui.hpp
@@ -32,7 +32,7 @@ class SceneEditorImGui: public studio::Editor {
 
 		ox::CStringView itemDisplayName() const noexcept final;
 
-		void draw(turbine::Context*) noexcept final;
+		void draw(turbine::Context&) noexcept final;
 
 		void onActivated() noexcept override;
 
diff --git a/src/studio/applib/src/aboutpopup.cpp b/src/studio/applib/src/aboutpopup.cpp
index 2591adcd..d60f71a7 100644
--- a/src/studio/applib/src/aboutpopup.cpp
+++ b/src/studio/applib/src/aboutpopup.cpp
@@ -25,7 +25,7 @@ bool AboutPopup::isOpen() const noexcept {
 	return m_stage == Stage::Open;
 }
 
-void AboutPopup::draw(turbine::Context *ctx) noexcept {
+void AboutPopup::draw(turbine::Context &ctx) noexcept {
 	switch (m_stage) {
 		case Stage::Closed:
 			break;
diff --git a/src/studio/applib/src/aboutpopup.hpp b/src/studio/applib/src/aboutpopup.hpp
index 0f363f14..0435a61a 100644
--- a/src/studio/applib/src/aboutpopup.hpp
+++ b/src/studio/applib/src/aboutpopup.hpp
@@ -35,7 +35,7 @@ class AboutPopup: public studio::Popup {
 		[[nodiscard]]
 		bool isOpen() const noexcept override;
 
-		void draw(turbine::Context *ctx) noexcept override;
+		void draw(turbine::Context &ctx) noexcept override;
 
 };
 
diff --git a/src/studio/applib/src/clawviewer.cpp b/src/studio/applib/src/clawviewer.cpp
index c484bd34..9fce4ca5 100644
--- a/src/studio/applib/src/clawviewer.cpp
+++ b/src/studio/applib/src/clawviewer.cpp
@@ -22,7 +22,7 @@ ox::CStringView ClawEditor::itemDisplayName() const noexcept {
 	return m_itemDisplayName;
 }
 
-void ClawEditor::draw(turbine::Context*) noexcept {
+void ClawEditor::draw(turbine::Context&) noexcept {
 	//const auto paneSize = ImGui::GetContentRegionAvail();
 	ImGui::BeginChild("PaletteEditor");
 	static constexpr auto flags = ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
diff --git a/src/studio/applib/src/clawviewer.hpp b/src/studio/applib/src/clawviewer.hpp
index 1608929d..93a3812b 100644
--- a/src/studio/applib/src/clawviewer.hpp
+++ b/src/studio/applib/src/clawviewer.hpp
@@ -27,7 +27,7 @@ class ClawEditor: public studio::Editor {
 
 		ox::CStringView itemDisplayName() const noexcept final;
 
-		void draw(turbine::Context*) noexcept final;
+		void draw(turbine::Context&) noexcept final;
 
 	private:
 		static void drawRow(const ox::ModelValue &value) noexcept;
diff --git a/src/studio/applib/src/filedialogmanager.cpp b/src/studio/applib/src/filedialogmanager.cpp
index 29c8021f..c061fda4 100644
--- a/src/studio/applib/src/filedialogmanager.cpp
+++ b/src/studio/applib/src/filedialogmanager.cpp
@@ -8,7 +8,7 @@
 
 namespace studio {
 
-studio::TaskState FileDialogManager::update(turbine::Context *ctx) noexcept {
+studio::TaskState FileDialogManager::update(turbine::Context &ctx) noexcept {
 	switch (m_state) {
 		case UpdateProjectPathState::EnableSystemCursor: {
 			// switch to system cursor in this update and open file dialog in the next
@@ -20,7 +20,7 @@ studio::TaskState FileDialogManager::update(turbine::Context *ctx) noexcept {
 			// switch to system cursor
 			auto [path, err] = studio::chooseDirectory();
 			// Mac file dialog doesn't restore focus to main window when closed...
-			turbine::focusWindow(*ctx);
+			turbine::focusWindow(ctx);
 			if (!err) {
 				err = pathChosen.emitCheckError(path);
 				oxAssert(err, "Path chosen response failed");
diff --git a/src/studio/applib/src/filedialogmanager.hpp b/src/studio/applib/src/filedialogmanager.hpp
index fa2eea10..9181cda0 100644
--- a/src/studio/applib/src/filedialogmanager.hpp
+++ b/src/studio/applib/src/filedialogmanager.hpp
@@ -33,7 +33,7 @@ class FileDialogManager : public studio::Task {
 
 		~FileDialogManager() noexcept override = default;
 
-		studio::TaskState update(turbine::Context *ctx) noexcept final;
+		studio::TaskState update(turbine::Context &ctx) noexcept final;
 
 		// signals
 		ox::Signal<ox::Error(const ox::String &)> pathChosen;
diff --git a/src/studio/applib/src/newmenu.cpp b/src/studio/applib/src/newmenu.cpp
index 8db647b2..f5588d23 100644
--- a/src/studio/applib/src/newmenu.cpp
+++ b/src/studio/applib/src/newmenu.cpp
@@ -6,7 +6,6 @@
 
 #include <imgui.h>
 
-#include <studio/context.hpp>
 #include <studio/imguiuitl.hpp>
 
 #include "newmenu.hpp"
@@ -32,7 +31,7 @@ bool NewMenu::isOpen() const noexcept {
 	return m_open;
 }
 
-void NewMenu::draw(turbine::Context *ctx) noexcept {
+void NewMenu::draw(turbine::Context &ctx) noexcept {
 	switch (m_stage) {
 		case Stage::Opening:
 			ImGui::OpenPopup(title().c_str());
@@ -60,7 +59,7 @@ void NewMenu::addItemMaker(ox::UniquePtr<studio::ItemMaker> im) noexcept {
 			});
 }
 
-void NewMenu::drawNewItemType(turbine::Context *ctx) noexcept {
+void NewMenu::drawNewItemType(turbine::Context &ctx) noexcept {
 	drawWindow(ctx, &m_open, [this] {
 		auto items = ox_malloca(m_types.size() * sizeof(const char*), const char*, nullptr);
 		for (auto i = 0u; const auto &im : m_types) {
@@ -72,8 +71,8 @@ void NewMenu::drawNewItemType(turbine::Context *ctx) noexcept {
 	});
 }
 
-void NewMenu::drawNewItemName(turbine::Context *ctx) noexcept {
-	drawWindow(ctx, &m_open, [this, ctx] {
+void NewMenu::drawNewItemName(turbine::Context &ctx) noexcept {
+	drawWindow(ctx, &m_open, [this, &ctx] {
 		const auto typeIdx = static_cast<std::size_t>(m_selectedType);
 		if (typeIdx < m_types.size()) {
 			ImGui::InputText("Name", m_itemName.data(), m_itemName.cap());
@@ -96,7 +95,7 @@ void NewMenu::drawFirstPageButtons() noexcept {
 	}
 }
 
-void NewMenu::drawLastPageButtons(turbine::Context *ctx) noexcept {
+void NewMenu::drawLastPageButtons(turbine::Context &ctx) noexcept {
 	ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 138);
 	ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 	if (ImGui::Button("Back")) {
@@ -113,7 +112,7 @@ void NewMenu::drawLastPageButtons(turbine::Context *ctx) noexcept {
 	}
 }
 
-void NewMenu::finish(turbine::Context *ctx) noexcept {
+void NewMenu::finish(turbine::Context &ctx) noexcept {
 	const auto err = m_types[static_cast<std::size_t>(m_selectedType)]->write(ctx, m_itemName);
 	if (err) {
 		oxLogError(err);
diff --git a/src/studio/applib/src/newmenu.hpp b/src/studio/applib/src/newmenu.hpp
index bfadecd9..f348b82b 100644
--- a/src/studio/applib/src/newmenu.hpp
+++ b/src/studio/applib/src/newmenu.hpp
@@ -43,7 +43,7 @@ class NewMenu: public studio::Popup {
 		[[nodiscard]]
 		bool isOpen() const noexcept override;
 
-		void draw(turbine::Context *ctx) noexcept override;
+		void draw(turbine::Context &ctx) noexcept override;
 
 		template<typename T>
 		void addItemType(ox::String name, ox::String parentDir, ox::String fileExt, T itemTempl, ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept;
@@ -54,15 +54,15 @@ class NewMenu: public studio::Popup {
 		void addItemMaker(ox::UniquePtr<studio::ItemMaker> im) noexcept;
 
 	private:
-		void drawNewItemType(turbine::Context *ctx) noexcept;
+		void drawNewItemType(turbine::Context &ctx) noexcept;
 
-		void drawNewItemName(turbine::Context *ctx) noexcept;
+		void drawNewItemName(turbine::Context &ctx) noexcept;
 
 		void drawFirstPageButtons() noexcept;
 
-		void drawLastPageButtons(turbine::Context *ctx) noexcept;
+		void drawLastPageButtons(turbine::Context &ctx) noexcept;
 
-		void finish(turbine::Context *ctx) noexcept;
+		void finish(turbine::Context &ctx) noexcept;
 
 };
 
diff --git a/src/studio/applib/src/projectexplorer.cpp b/src/studio/applib/src/projectexplorer.cpp
index 77c9c5f6..904a6211 100644
--- a/src/studio/applib/src/projectexplorer.cpp
+++ b/src/studio/applib/src/projectexplorer.cpp
@@ -31,11 +31,10 @@ buildProjectTreeModel(ProjectExplorer *explorer, ox::StringView name, ox::CRStri
 	return out;
 }
 
-ProjectExplorer::ProjectExplorer(turbine::Context *ctx) noexcept {
-	m_ctx = ctx;
+ProjectExplorer::ProjectExplorer(turbine::Context &ctx) noexcept: m_ctx(ctx) {
 }
 
-void ProjectExplorer::draw(turbine::Context *ctx) noexcept {
+void ProjectExplorer::draw(turbine::Context &ctx) noexcept {
 	const auto viewport = ImGui::GetContentRegionAvail();
 	ImGui::BeginChild("ProjectExplorer", ImVec2(300, viewport.y), true);
 	ImGui::SetNextItemOpen(true);
diff --git a/src/studio/applib/src/projectexplorer.hpp b/src/studio/applib/src/projectexplorer.hpp
index 2c252753..1479bdca 100644
--- a/src/studio/applib/src/projectexplorer.hpp
+++ b/src/studio/applib/src/projectexplorer.hpp
@@ -15,11 +15,11 @@ namespace studio {
 class ProjectExplorer: public studio::Widget {
 	private:
 		ox::UniquePtr<ProjectTreeModel> m_treeModel;
-		turbine::Context *m_ctx = nullptr;
+		turbine::Context &m_ctx;
 	public:
-		explicit ProjectExplorer(turbine::Context *ctx) noexcept;
+		explicit ProjectExplorer(turbine::Context &ctx) noexcept;
 
-		void draw(turbine::Context *ctx) noexcept override;
+		void draw(turbine::Context &ctx) noexcept override;
 
 		void setModel(ox::UniquePtr<ProjectTreeModel> model) noexcept;
 
@@ -27,7 +27,7 @@ class ProjectExplorer: public studio::Widget {
 
 		[[nodiscard]]
 		inline ox::FileSystem *romFs() noexcept {
-			return rom(*m_ctx);
+			return rom(m_ctx);
 		}
 
 	// slots
diff --git a/src/studio/applib/src/projecttreemodel.cpp b/src/studio/applib/src/projecttreemodel.cpp
index 73e82825..7e19e2d9 100644
--- a/src/studio/applib/src/projecttreemodel.cpp
+++ b/src/studio/applib/src/projecttreemodel.cpp
@@ -23,7 +23,7 @@ ProjectTreeModel::ProjectTreeModel(ProjectTreeModel &&other) noexcept:
 	m_children(std::move(other.m_children)) {
 }
 
-void ProjectTreeModel::draw(turbine::Context *ctx) const noexcept {
+void ProjectTreeModel::draw(turbine::Context &ctx) const noexcept {
 	constexpr auto dirFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
 	if (!m_children.empty()) {
 		if (ImGui::TreeNodeEx(m_name.c_str(), dirFlags)) {
diff --git a/src/studio/applib/src/projecttreemodel.hpp b/src/studio/applib/src/projecttreemodel.hpp
index fb994e27..4c300cd4 100644
--- a/src/studio/applib/src/projecttreemodel.hpp
+++ b/src/studio/applib/src/projecttreemodel.hpp
@@ -23,7 +23,7 @@ class ProjectTreeModel {
 
 		ProjectTreeModel(ProjectTreeModel &&other) noexcept;
 
-		void draw(turbine::Context *ctx) const noexcept;
+		void draw(turbine::Context &ctx) const noexcept;
 
 		void setChildren(ox::Vector<ox::UniquePtr<ProjectTreeModel>> children) noexcept;
 
diff --git a/src/studio/applib/src/studioapp.cpp b/src/studio/applib/src/studioapp.cpp
index 55a62441..f1aac408 100644
--- a/src/studio/applib/src/studioapp.cpp
+++ b/src/studio/applib/src/studioapp.cpp
@@ -34,7 +34,7 @@ oxModelBegin(StudioConfig)
 oxModelEnd()
 
 StudioUI::StudioUI(turbine::Context *ctx, ox::StringView projectDir) noexcept:
-	m_ctx(ctx),
+	m_ctx(*ctx),
 	m_projectDir(projectDir),
 	m_projectExplorer(ox::make_unique<ProjectExplorer>(m_ctx)),
 	m_aboutPopup(*ctx) {
@@ -42,7 +42,7 @@ StudioUI::StudioUI(turbine::Context *ctx, ox::StringView projectDir) noexcept:
 	ImGui::GetIO().IniFilename = nullptr;
 	loadModules();
 	// open project and files
-	const auto [config, err] = studio::readConfig<StudioConfig>(&keelCtx(*ctx));
+	const auto [config, err] = studio::readConfig<StudioConfig>(keelCtx(*ctx));
 	m_showProjectExplorer = config.showProjectExplorer;
 	if (!err) {
 		oxIgnoreError(openProject(config.projectPath));
@@ -68,7 +68,7 @@ void StudioUI::update() noexcept {
 }
 
 void StudioUI::handleKeyEvent(turbine::Key key, bool down) noexcept {
-	const auto ctrlDown = turbine::buttonDown(*m_ctx, turbine::Key::Mod_Ctrl);
+	const auto ctrlDown = turbine::buttonDown(m_ctx, turbine::Key::Mod_Ctrl);
 	for (auto p : m_popups) {
 		if (p->isOpen()) {
 			if (key == turbine::Key::Escape) {
@@ -89,10 +89,10 @@ void StudioUI::handleKeyEvent(turbine::Key key, bool down) noexcept {
 				m_newMenu.open();
 				break;
 			case turbine::Key::Alpha_O:
-				m_taskRunner.add(ox::make<FileDialogManager>(this, &StudioUI::openProject));
+				m_taskRunner.add(*ox::make<FileDialogManager>(this, &StudioUI::openProject));
 				break;
 			case turbine::Key::Alpha_Q:
-				turbine::requestShutdown(*m_ctx);
+				turbine::requestShutdown(m_ctx);
 				break;
 			case turbine::Key::Alpha_S:
 				save();
@@ -156,13 +156,13 @@ void StudioUI::drawMenu() noexcept {
 				m_newMenu.open();
 			}
 			if (ImGui::MenuItem("Open Project...", "Ctrl+O")) {
-				m_taskRunner.add(ox::make<FileDialogManager>(this, &StudioUI::openProject));
+				m_taskRunner.add(*ox::make<FileDialogManager>(this, &StudioUI::openProject));
 			}
 			if (ImGui::MenuItem("Save", "Ctrl+S", false, m_activeEditor && m_activeEditor->unsavedChanges())) {
 				m_activeEditor->save();
 			}
 			if (ImGui::MenuItem("Quit", "Ctrl+Q")) {
-				turbine::requestShutdown(*m_ctx);
+				turbine::requestShutdown(m_ctx);
 			}
 			ImGui::EndMenu();
 		}
@@ -223,7 +223,7 @@ void StudioUI::drawTabs() noexcept {
 		if (ImGui::BeginTabItem(e->itemDisplayName().c_str(), &open, flags)) {
 			if (m_activeEditor != e.get()) {
 				m_activeEditor = e.get();
-				studio::editConfig<StudioConfig>(&keelCtx(*m_ctx), [&](StudioConfig *config) {
+				studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) {
 					config->activeTabItemName = m_activeEditor->itemName();
 				});
 			}
@@ -232,7 +232,7 @@ void StudioUI::drawTabs() noexcept {
 			}
 			if (m_activeEditorOnLastDraw != e.get()) [[unlikely]] {
 				m_activeEditor->onActivated();
-				turbine::setConstantRefresh(*m_ctx, m_activeEditor->requiresConstantRefresh());
+				turbine::setConstantRefresh(m_ctx, m_activeEditor->requiresConstantRefresh());
 			}
 			e->draw(m_ctx);
 			m_activeEditorOnLastDraw = e.get();
@@ -260,10 +260,10 @@ void StudioUI::loadEditorMaker(studio::EditorMaker const&editorMaker) noexcept {
 }
 
 void StudioUI::loadModule(const studio::Module *mod) noexcept {
-	for (const auto &editorMaker : mod->editors(*m_ctx)) {
+	for (const auto &editorMaker : mod->editors(m_ctx)) {
 		loadEditorMaker(editorMaker);
 	}
-	for (auto &im : mod->itemMakers(*m_ctx)) {
+	for (auto &im : mod->itemMakers(m_ctx)) {
 		m_newMenu.addItemMaker(std::move(im));
 	}
 }
@@ -276,7 +276,7 @@ void StudioUI::loadModules() noexcept {
 
 void StudioUI::toggleProjectExplorer() noexcept {
 	m_showProjectExplorer = !m_showProjectExplorer;
-	studio::editConfig<StudioConfig>(&keelCtx(*m_ctx), [&](StudioConfig *config) {
+	studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) {
 		config->showProjectExplorer = m_showProjectExplorer;
 	});
 }
@@ -303,16 +303,16 @@ void StudioUI::save() noexcept {
 
 ox::Error StudioUI::openProject(ox::CRStringView path) noexcept {
 	oxRequireM(fs, keel::loadRomFs(path));
-	oxReturnError(keel::setRomFs(keelCtx(*m_ctx), std::move(fs)));
-	turbine::setWindowTitle(*m_ctx, ox::sfmt("{} - {}", keelCtx(*m_ctx).appName, path));
-	m_project = ox::make_unique<studio::Project>(keelCtx(*m_ctx), ox::String(path), m_projectDir);
-	auto sctx = applicationData<studio::StudioContext>(*m_ctx);
+	oxReturnError(keel::setRomFs(keelCtx(m_ctx), std::move(fs)));
+	turbine::setWindowTitle(m_ctx, ox::sfmt("{} - {}", keelCtx(m_ctx).appName, path));
+	m_project = ox::make_unique<studio::Project>(keelCtx(m_ctx), ox::String(path), m_projectDir);
+	auto sctx = applicationData<studio::StudioContext>(m_ctx);
 	sctx->project = m_project.get();
 	m_project->fileAdded.connect(m_projectExplorer.get(), &ProjectExplorer::refreshProjectTreeModel);
 	m_project->fileDeleted.connect(m_projectExplorer.get(), &ProjectExplorer::refreshProjectTreeModel);
 	m_openFiles.clear();
 	m_editors.clear();
-	studio::editConfig<StudioConfig>(&keelCtx(*m_ctx), [&](StudioConfig *config) {
+	studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) {
 		config->projectPath = ox::String(path);
 		config->openFiles.clear();
 	});
@@ -362,7 +362,7 @@ ox::Error StudioUI::openFileActiveTab(ox::CRStringView path, bool makeActiveTab)
 		m_activeEditorUpdatePending = editor;
 	}
 	// save to config
-	studio::editConfig<StudioConfig>(&keelCtx(*m_ctx), [&](StudioConfig *config) {
+	studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) {
 		if (!config->openFiles.contains(path)) {
 			config->openFiles.emplace_back(path);
 		}
@@ -376,7 +376,7 @@ ox::Error StudioUI::closeFile(ox::CRStringView path) noexcept {
 	}
 	oxIgnoreError(m_openFiles.erase(std::remove(m_openFiles.begin(), m_openFiles.end(), path)));
 	// save to config
-	studio::editConfig<StudioConfig>(&keelCtx(*m_ctx), [&](StudioConfig *config) {
+	studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) {
 		oxIgnoreError(config->openFiles.erase(std::remove(config->openFiles.begin(), config->openFiles.end(), path)));
 	});
 	return OxError(0);
diff --git a/src/studio/applib/src/studioapp.hpp b/src/studio/applib/src/studioapp.hpp
index 8a652536..b1bcf21a 100644
--- a/src/studio/applib/src/studioapp.hpp
+++ b/src/studio/applib/src/studioapp.hpp
@@ -23,7 +23,7 @@ class StudioUI: public ox::SignalHandler {
 	friend class StudioUIDrawer;
 
 	private:
-		turbine::Context *m_ctx = nullptr;
+		turbine::Context &m_ctx;
 		ox::String m_projectDir;
 		ox::UniquePtr<studio::Project> m_project;
 		studio::TaskRunner m_taskRunner;
diff --git a/src/studio/modlib/include/studio/configio.hpp b/src/studio/modlib/include/studio/configio.hpp
index d15aea0a..938a1cf7 100644
--- a/src/studio/modlib/include/studio/configio.hpp
+++ b/src/studio/modlib/include/studio/configio.hpp
@@ -18,10 +18,10 @@
 namespace studio {
 
 [[nodiscard]]
-ox::String configPath(const keel::Context *ctx) noexcept;
+ox::String configPath(keel::Context const&ctx) noexcept;
 
 template<typename T>
-ox::Result<T> readConfig(keel::Context *ctx, ox::CRStringView name) noexcept {
+ox::Result<T> readConfig(keel::Context &ctx, ox::CRStringView name) noexcept {
 	oxAssert(name != "", "Config type has no TypeName");
 	const auto path = ox::sfmt("/{}.json", name);
 	ox::PassThroughFS fs(configPath(ctx));
@@ -34,13 +34,13 @@ ox::Result<T> readConfig(keel::Context *ctx, ox::CRStringView name) noexcept {
 }
 
 template<typename T>
-ox::Result<T> readConfig(keel::Context *ctx) noexcept {
+ox::Result<T> readConfig(keel::Context &ctx) noexcept {
 	constexpr auto TypeName = ox::requireModelTypeName<T>();
 	return readConfig<T>(ctx, TypeName);
 }
 
 template<typename T>
-ox::Error writeConfig(keel::Context *ctx, ox::CRStringView name, T *data) noexcept {
+ox::Error writeConfig(keel::Context &ctx, ox::CRStringView name, T *data) noexcept {
 	oxAssert(name != "", "Config type has no TypeName");
 	const auto path = ox::sfmt("/{}.json", name);
 	ox::PassThroughFS fs(configPath(ctx));
@@ -58,13 +58,13 @@ ox::Error writeConfig(keel::Context *ctx, ox::CRStringView name, T *data) noexce
 }
 
 template<typename T>
-ox::Error writeConfig(keel::Context *ctx, T *data) noexcept {
+ox::Error writeConfig(keel::Context &ctx, T *data) noexcept {
 	constexpr auto TypeName = ox::requireModelTypeName<T>();
 	return writeConfig(ctx, TypeName, data);
 }
 
 template<typename T, typename Func>
-void openConfig(keel::Context *ctx, ox::CRStringView name, Func f) noexcept {
+void openConfig(keel::Context &ctx, ox::CRStringView name, Func f) noexcept {
 	oxAssert(name != "", "Config type has no TypeName");
 	const auto [c, err] = readConfig<T>(ctx, name);
 	oxLogError(err);
@@ -72,13 +72,13 @@ void openConfig(keel::Context *ctx, ox::CRStringView name, Func f) noexcept {
 }
 
 template<typename T, typename Func>
-void openConfig(keel::Context *ctx, Func f) noexcept {
+void openConfig(keel::Context &ctx, Func f) noexcept {
 	constexpr auto TypeName = ox::requireModelTypeName<T>();
 	openConfig<T>(ctx, TypeName, f);
 }
 
 template<typename T, typename Func>
-void editConfig(keel::Context *ctx, ox::CRStringView name, Func f) noexcept {
+void editConfig(keel::Context &ctx, ox::CRStringView name, Func f) noexcept {
 	oxAssert(name !=  "", "Config type has no TypeName");
 	auto [c, err] = readConfig<T>(ctx, name);
 	oxLogError(err);
@@ -87,7 +87,7 @@ void editConfig(keel::Context *ctx, ox::CRStringView name, Func f) noexcept {
 }
 
 template<typename T, typename Func>
-void editConfig(keel::Context *ctx, Func f) noexcept {
+void editConfig(keel::Context &ctx, Func f) noexcept {
 	constexpr auto TypeName = ox::requireModelTypeName<T>();
 	editConfig<T>(ctx, TypeName, f);
 }
diff --git a/src/studio/modlib/include/studio/filedialog.hpp b/src/studio/modlib/include/studio/filedialog.hpp
index b1e805a4..71fe9b95 100644
--- a/src/studio/modlib/include/studio/filedialog.hpp
+++ b/src/studio/modlib/include/studio/filedialog.hpp
@@ -20,7 +20,7 @@ struct FDFilterItem {
 	FDFilterItem(ox::CRStringView pName, ox::CRStringView pSpec) noexcept;
 };
 
-ox::Result<ox::String> saveFile(const ox::Vector<FDFilterItem> &exts) noexcept;
+ox::Result<ox::String> saveFile(ox::Vector<FDFilterItem> const&exts) noexcept;
 
 ox::Result<ox::String> chooseDirectory() noexcept;
 
diff --git a/src/studio/modlib/include/studio/imguiuitl.hpp b/src/studio/modlib/include/studio/imguiuitl.hpp
index edeed509..65554736 100644
--- a/src/studio/modlib/include/studio/imguiuitl.hpp
+++ b/src/studio/modlib/include/studio/imguiuitl.hpp
@@ -8,6 +8,6 @@
 
 namespace studio::ig {
 
-void centerNextWindow(turbine::Context *ctx) noexcept;
+void centerNextWindow(turbine::Context &ctx) noexcept;
 
 }
\ No newline at end of file
diff --git a/src/studio/modlib/include/studio/itemmaker.hpp b/src/studio/modlib/include/studio/itemmaker.hpp
index 3e0b955a..ed6d2730 100644
--- a/src/studio/modlib/include/studio/itemmaker.hpp
+++ b/src/studio/modlib/include/studio/itemmaker.hpp
@@ -24,7 +24,7 @@ class ItemMaker {
 			fileExt(pFileExt) {
 		}
 		virtual ~ItemMaker() noexcept = default;
-		virtual ox::Error write(turbine::Context *ctx, ox::CRStringView pName) const noexcept = 0;
+		virtual ox::Error write(turbine::Context &ctx, ox::CRStringView pName) const noexcept = 0;
 };
 
 template<typename T>
@@ -61,10 +61,10 @@ class ItemMakerT: public ItemMaker {
 			 item(std::move(pItem)),
 			 fmt(pFmt) {
 		}
-		ox::Error write(turbine::Context *ctx, ox::CRStringView pName) const noexcept override {
+		ox::Error write(turbine::Context &ctx, ox::CRStringView pName) const noexcept override {
 			const auto path = ox::sfmt("/{}/{}.{}", parentDir, pName, fileExt);
-			auto sctx = turbine::applicationData<studio::StudioContext>(*ctx);
-			keel::createUuidMapping(keelCtx(*ctx), path, ox::UUID::generate().unwrap());
+			auto sctx = turbine::applicationData<studio::StudioContext>(ctx);
+			keel::createUuidMapping(keelCtx(ctx), path, ox::UUID::generate().unwrap());
 			return sctx->project->writeObj(path, item, fmt);
 		}
 };
diff --git a/src/studio/modlib/include/studio/popup.hpp b/src/studio/modlib/include/studio/popup.hpp
index 9b44c6fd..9d11e696 100644
--- a/src/studio/modlib/include/studio/popup.hpp
+++ b/src/studio/modlib/include/studio/popup.hpp
@@ -32,7 +32,7 @@ class Popup {
 		[[nodiscard]]
 		virtual bool isOpen() const noexcept = 0;
 
-		virtual void draw(turbine::Context *ctx) noexcept = 0;
+		virtual void draw(turbine::Context &ctx) noexcept = 0;
 
 	protected:
 		constexpr void setSize(ox::Size sz) noexcept {
@@ -47,7 +47,7 @@ class Popup {
 			return m_title;
 		}
 
-		void drawWindow(turbine::Context *ctx, bool *open, const std::function<void()> &drawContents);
+		void drawWindow(turbine::Context &ctx, bool *open, std::function<void()> const&drawContents);
 
 };
 
diff --git a/src/studio/modlib/include/studio/task.hpp b/src/studio/modlib/include/studio/task.hpp
index 1da1575d..a1b00b3d 100644
--- a/src/studio/modlib/include/studio/task.hpp
+++ b/src/studio/modlib/include/studio/task.hpp
@@ -19,15 +19,15 @@ class Task: public ox::SignalHandler {
 	public:
 		ox::Signal<ox::Error()> finished;
 		~Task() noexcept override = default;
-		virtual TaskState update(turbine::Context *ctx) noexcept = 0;
+		virtual TaskState update(turbine::Context &ctx) noexcept = 0;
 };
 
 class TaskRunner {
 	private:
 		ox::Vector<ox::UniquePtr<studio::Task>> m_tasks;
 	public:
-		void update(turbine::Context *ctx) noexcept;
-		void add(Task *task) noexcept;
+		void update(turbine::Context &ctx) noexcept;
+		void add(Task &task) noexcept;
 };
 
 }
diff --git a/src/studio/modlib/include/studio/undostack.hpp b/src/studio/modlib/include/studio/undostack.hpp
index 55234ac0..86f5ae14 100644
--- a/src/studio/modlib/include/studio/undostack.hpp
+++ b/src/studio/modlib/include/studio/undostack.hpp
@@ -23,11 +23,11 @@ class UndoCommand {
 
 class UndoStack {
 	private:
-		ox::Vector<ox::UniquePtr<UndoCommand>> m_stack;
+		ox::Vector<ox::UPtr<UndoCommand>> m_stack;
 		std::size_t m_stackIdx = 0;
 
 	public:
-		void push(UndoCommand *cmd) noexcept;
+		void push(ox::UPtr<UndoCommand> &&cmd) noexcept;
 
 		void redo() noexcept;
 
diff --git a/src/studio/modlib/include/studio/widget.hpp b/src/studio/modlib/include/studio/widget.hpp
index ec571ecb..851d249b 100644
--- a/src/studio/modlib/include/studio/widget.hpp
+++ b/src/studio/modlib/include/studio/widget.hpp
@@ -13,7 +13,7 @@ namespace studio {
 class Widget: public ox::SignalHandler {
 	public:
 		~Widget() noexcept override = default;
-		virtual void draw(turbine::Context*) noexcept = 0;
+		virtual void draw(turbine::Context&) noexcept = 0;
 };
 
 }
diff --git a/src/studio/modlib/src/configio.cpp b/src/studio/modlib/src/configio.cpp
index 589c212b..687defcc 100644
--- a/src/studio/modlib/src/configio.cpp
+++ b/src/studio/modlib/src/configio.cpp
@@ -23,9 +23,9 @@ constexpr auto ConfigDir = [] {
 	}
 }();
 
-ox::String configPath(const keel::Context *ctx) noexcept {
+ox::String configPath(const keel::Context &ctx) noexcept {
 	const auto homeDir = std::getenv(ox::defines::OS == ox::OS::Windows ? "USERPROFILE" : "HOME");
-	return ox::sfmt(ConfigDir, homeDir, ctx->appName);
+	return ox::sfmt(ConfigDir, homeDir, ctx.appName);
 }
 
 }
diff --git a/src/studio/modlib/src/filedialog_nfd.cpp b/src/studio/modlib/src/filedialog_nfd.cpp
index 1727054a..c12971bc 100644
--- a/src/studio/modlib/src/filedialog_nfd.cpp
+++ b/src/studio/modlib/src/filedialog_nfd.cpp
@@ -18,7 +18,7 @@ FDFilterItem::FDFilterItem(ox::CRStringView pName, ox::CRStringView pSpec) noexc
 	ox_strncpy(spec.data(), pSpec.data(), pSpec.len());
 }
 
-static ox::Result<ox::String> toResult(nfdresult_t r, const NFD::UniquePathN &path) noexcept {
+static ox::Result<ox::String> toResult(nfdresult_t r, NFD::UniquePathN const&path) noexcept {
 	switch (r) {
 		case NFD_OKAY: {
 			ox::String out;
@@ -35,8 +35,8 @@ static ox::Result<ox::String> toResult(nfdresult_t r, const NFD::UniquePathN &pa
 	}
 }
 
-ox::Result<ox::String> saveFile(const ox::Vector<FDFilterItem> &filters) noexcept {
-	const NFD::Guard guard;
+ox::Result<ox::String> saveFile(ox::Vector<FDFilterItem> const&filters) noexcept {
+	NFD::Guard const guard;
 	NFD::UniquePathN path;
 	ox::Vector<nfdnfilteritem_t, 5> filterItems(filters.size());
 	for (auto i = 0u; const auto &f : filters) {
@@ -44,7 +44,7 @@ ox::Result<ox::String> saveFile(const ox::Vector<FDFilterItem> &filters) noexcep
 		filterItems[i].spec = f.spec.data();
 		++i;
 	}
-	const auto filterItemsCnt = static_cast<nfdfiltersize_t>(filterItems.size());
+	auto const filterItemsCnt = static_cast<nfdfiltersize_t>(filterItems.size());
 	return toResult(NFD::SaveDialog(path, filterItems.data(), filterItemsCnt), path);
 }
 
diff --git a/src/studio/modlib/src/imguiutil.cpp b/src/studio/modlib/src/imguiutil.cpp
index abe402e2..900743d9 100644
--- a/src/studio/modlib/src/imguiutil.cpp
+++ b/src/studio/modlib/src/imguiutil.cpp
@@ -8,8 +8,8 @@
 
 namespace studio::ig {
 
-void centerNextWindow(turbine::Context *ctx) noexcept {
-	const auto sz = turbine::getScreenSize(*ctx);
+void centerNextWindow(turbine::Context &ctx) noexcept {
+	const auto sz = turbine::getScreenSize(ctx);
 	const auto screenW = static_cast<float>(sz.width);
 	const auto screenH = static_cast<float>(sz.height);
 	const auto mod = ImGui::GetWindowDpiScale() * 2;
diff --git a/src/studio/modlib/src/popup.cpp b/src/studio/modlib/src/popup.cpp
index d3901778..eaf2317c 100644
--- a/src/studio/modlib/src/popup.cpp
+++ b/src/studio/modlib/src/popup.cpp
@@ -7,7 +7,7 @@
 
 namespace studio {
 
-void Popup::drawWindow(turbine::Context *ctx, bool *open, const std::function<void()> &drawContents) {
+void Popup::drawWindow(turbine::Context &ctx, bool *open, std::function<void()> const&drawContents) {
 	studio::ig::centerNextWindow(ctx);
 	ImGui::SetNextWindowSize(static_cast<ImVec2>(m_size));
 	constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
diff --git a/src/studio/modlib/src/task.cpp b/src/studio/modlib/src/task.cpp
index d57e3290..de932a0b 100644
--- a/src/studio/modlib/src/task.cpp
+++ b/src/studio/modlib/src/task.cpp
@@ -8,7 +8,7 @@
 
 namespace studio {
 
-void TaskRunner::update(turbine::Context *ctx) noexcept {
+void TaskRunner::update(turbine::Context &ctx) noexcept {
 	oxIgnoreError(m_tasks.erase(std::remove_if(m_tasks.begin(), m_tasks.end(), [&](ox::UPtr<studio::Task> &t) {
 		const auto done = t->update(ctx) == TaskState::Done;
 		if (done) {
@@ -18,8 +18,8 @@ void TaskRunner::update(turbine::Context *ctx) noexcept {
 	})));
 }
 
-void TaskRunner::add(Task *task) noexcept {
-	m_tasks.emplace_back(task);
+void TaskRunner::add(Task &task) noexcept {
+	m_tasks.emplace_back(&task);
 }
 
 }
diff --git a/src/studio/modlib/src/undostack.cpp b/src/studio/modlib/src/undostack.cpp
index 92676fc3..8294387b 100644
--- a/src/studio/modlib/src/undostack.cpp
+++ b/src/studio/modlib/src/undostack.cpp
@@ -10,18 +10,16 @@ bool UndoCommand::mergeWith(const UndoCommand*) noexcept {
 	return false;
 }
 
-void UndoStack::push(UndoCommand *cmd) noexcept {
+void UndoStack::push(ox::UPtr<UndoCommand> &&cmd) noexcept {
 	for (const auto i = m_stackIdx; i < m_stack.size();) {
 		oxIgnoreError(m_stack.erase(i));
 	}
 	cmd->redo();
-	redoTriggered.emit(cmd);
-	changeTriggered.emit(cmd);
-	if (!m_stack.size() || !(*m_stack.back().value)->mergeWith(cmd)) {
-		m_stack.emplace_back(cmd);
+	redoTriggered.emit(cmd.get());
+	changeTriggered.emit(cmd.get());
+	if (m_stack.empty() || !(*m_stack.back().value)->mergeWith(cmd.get())) {
+		m_stack.emplace_back(std::move(cmd));
 		++m_stackIdx;
-	} else {
-		delete cmd;
 	}
 }