diff --git a/src/nostalgia/core/studio/CMakeLists.txt b/src/nostalgia/core/studio/CMakeLists.txt
index 9490feee..c0a36a7f 100644
--- a/src/nostalgia/core/studio/CMakeLists.txt
+++ b/src/nostalgia/core/studio/CMakeLists.txt
@@ -7,6 +7,7 @@ add_library(
 		#paletteeditor.cpp
 		tilesheeteditor-imgui.cpp
 		tilesheeteditor.cpp
+		tilesheeteditormodel.cpp
 		tilesheetpixelgrid.cpp
 		tilesheetpixels.cpp
 )
diff --git a/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp b/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp
index 28e659b2..8c2f06f7 100644
--- a/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp
+++ b/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp
@@ -96,7 +96,7 @@ void TileSheetEditorImGui::drawTileSheet(const geo::Vec2 &fbSize) noexcept {
 	}
 }
 
-void TileSheetEditorImGui::drawPalettePicker() noexcept {
+void TileSheetEditorImGui::drawPalettePicker() const noexcept {
 	// header
 	ImGui::BeginTable("PaletteTable", 2);
 	ImGui::TableSetupColumn("No.", 0, 0.35);
diff --git a/src/nostalgia/core/studio/tilesheeteditor-imgui.hpp b/src/nostalgia/core/studio/tilesheeteditor-imgui.hpp
index 4d7b372b..c2120e14 100644
--- a/src/nostalgia/core/studio/tilesheeteditor-imgui.hpp
+++ b/src/nostalgia/core/studio/tilesheeteditor-imgui.hpp
@@ -64,7 +64,7 @@ class TileSheetEditorImGui: public studio::Editor {
 
 		void drawTileSheet(const geo::Vec2 &fbSize) noexcept;
 
-		void drawPalettePicker() noexcept;
+		void drawPalettePicker() const noexcept;
 
 	// slots
 	public:
diff --git a/src/nostalgia/core/studio/tilesheeteditor.cpp b/src/nostalgia/core/studio/tilesheeteditor.cpp
index 99aed085..8dc7d1f0 100644
--- a/src/nostalgia/core/studio/tilesheeteditor.cpp
+++ b/src/nostalgia/core/studio/tilesheeteditor.cpp
@@ -4,22 +4,19 @@
 
 #include <iostream>
 
-#include <nostalgia/geo/point.hpp>
 #include <nostalgia/core/consts.hpp>
 #include <nostalgia/core/media.hpp>
 #include <nostalgia/core/ptidxconv.hpp>
+#include <nostalgia/geo/point.hpp>
 
 #include "tilesheeteditor.hpp"
 
 namespace nostalgia::core {
 
-TileSheetEditor::TileSheetEditor(Context *ctx, const ox::String &path) {
+TileSheetEditor::TileSheetEditor(Context *ctx, const ox::String &path): m_model(ctx, path) {
 	// build shaders
 	oxThrowError(m_pixelsDrawer.buildShader());
 	oxThrowError(m_pixelGridDrawer.buildShader());
-	oxRequireT(img, readObj<NostalgiaGraphic>(ctx, path.c_str()));
-	m_img = std::move(*img);
-	oxThrowError(readObj<NostalgiaPalette>(ctx, m_img.defaultPalette).moveTo(&m_pal));
 }
 
 void TileSheetEditor::cut() {
@@ -37,13 +34,12 @@ void TileSheetEditor::draw() noexcept {
 	glClear(GL_COLOR_BUFFER_BIT);
 	m_pixelsDrawer.draw(m_updated, m_scrollOffset);
 	m_pixelGridDrawer.draw(m_updated, m_scrollOffset);
-	m_updated = false;
 }
 
-void TileSheetEditor::scrollV(const geo::Vec2 paneSz, float wheel, bool zoomMod) noexcept {
+void TileSheetEditor::scrollV(const geo::Vec2 &paneSz, float wheel, bool zoomMod) noexcept {
 	const auto pixelSize = m_pixelsDrawer.pixelSize(paneSz);
-	const ImVec2 sheetSize(pixelSize.x * static_cast<float>(m_img.columns) * TileWidth,
-								  pixelSize.y * static_cast<float>(m_img.rows) * TileHeight);
+	const ImVec2 sheetSize(pixelSize.x * static_cast<float>(img().columns) * TileWidth,
+	                       pixelSize.y * static_cast<float>(img().rows) * TileHeight);
 	if (zoomMod) {
 		m_pixelSizeMod = ox::clamp(m_pixelSizeMod + wheel * 0.02f, 0.55f, 2.f);
 		m_pixelsDrawer.setPixelSizeMod(m_pixelSizeMod);
@@ -57,10 +53,10 @@ void TileSheetEditor::scrollV(const geo::Vec2 paneSz, float wheel, bool zoomMod)
 	m_scrollOffset.y = ox::clamp(m_scrollOffset.y, 0.f, sheetSize.y / 2);
 }
 
-void TileSheetEditor::scrollH(const geo::Vec2 paneSz, float wheelh) noexcept {
+void TileSheetEditor::scrollH(const geo::Vec2 &paneSz, float wheelh) noexcept {
 	const auto pixelSize = m_pixelsDrawer.pixelSize(paneSz);
-	const ImVec2 sheetSize(pixelSize.x * static_cast<float>(m_img.columns) * TileWidth,
-								  pixelSize.y * static_cast<float>(m_img.rows) * TileHeight);
+	const ImVec2 sheetSize(pixelSize.x * static_cast<float>(img().columns) * TileWidth,
+						   pixelSize.y * static_cast<float>(img().rows) * TileHeight);
 	m_scrollOffset.x += wheelh * 0.1f;
 	m_scrollOffset.x = ox::clamp(m_scrollOffset.x, -(sheetSize.x / 2), 0.f);
 }
@@ -76,21 +72,13 @@ void TileSheetEditor::clickPixel(const geo::Vec2 &paneSize, const geo::Vec2 &cli
 	y /= pixDrawSz.y;
 	const auto pt = geo::Point(static_cast<int>(x * 2), static_cast<int>(y * 2));
 	const uint8_t palIdx = 0;
-	m_img.setPixel(pt, palIdx);
+	m_model.img().setPixel(pt, palIdx);
 	m_updated = true;
 }
 
 void TileSheetEditor::resize(const geo::Vec2 &sz) noexcept {
-	m_pixelsDrawer.initBufferSet(sz, m_img, *m_pal);
-	m_pixelGridDrawer.initBufferSet(sz, m_img);
-}
-
-const NostalgiaGraphic &TileSheetEditor::img() const {
-	return m_img;
-}
-
-const NostalgiaPalette &TileSheetEditor::pal() const {
-	return *m_pal;
+	m_pixelsDrawer.initBufferSet(sz, img(), pal());
+	m_pixelGridDrawer.initBufferSet(sz, img());
 }
 
 bool TileSheetEditor::updated() const noexcept {
@@ -104,36 +92,4 @@ void TileSheetEditor::ackUpdate() noexcept {
 void TileSheetEditor::saveItem() {
 }
 
-void TileSheetEditor::getFillPixels(bool *pixels, geo::Point pt, int oldColor) const {
-	const auto tileIdx = [this](const geo::Point &pt) noexcept {
-		return ptToIdx(pt, m_img.columns) / PixelsPerTile;
-	};
-	// get points
-	const auto leftPt = pt + geo::Point(-1, 0);
-	const auto rightPt = pt + geo::Point(1, 0);
-	const auto topPt = pt + geo::Point(0, -1);
-	const auto bottomPt = pt + geo::Point(0, 1);
-	// calculate indices
-	const auto idx = ptToIdx(pt, m_img.columns);
-	const auto leftIdx = ptToIdx(leftPt, m_img.columns);
-	const auto rightIdx = ptToIdx(rightPt, m_img.columns);
-	const auto topIdx = ptToIdx(topPt, m_img.columns);
-	const auto bottomIdx = ptToIdx(bottomPt, m_img.columns);
-	const auto tile = tileIdx(pt);
-	// mark pixels to update
-	pixels[idx % PixelsPerTile] = true;
-	if (!pixels[leftIdx % PixelsPerTile] && tile == tileIdx(leftPt) && m_img.pixels[leftIdx] == oldColor) {
-		getFillPixels(pixels, leftPt, oldColor);
-	}
-	if (!pixels[rightIdx % PixelsPerTile] && tile == tileIdx(rightPt) && m_img.pixels[rightIdx] == oldColor) {
-		getFillPixels(pixels, rightPt, oldColor);
-	}
-	if (!pixels[topIdx % PixelsPerTile] && tile == tileIdx(topPt) && m_img.pixels[topIdx] == oldColor) {
-		getFillPixels(pixels, topPt, oldColor);
-	}
-	if (!pixels[bottomIdx % PixelsPerTile] && tile == tileIdx(bottomPt) && m_img.pixels[bottomIdx] == oldColor) {
-		getFillPixels(pixels, bottomPt, oldColor);
-	}
-}
-
 }
diff --git a/src/nostalgia/core/studio/tilesheeteditor.hpp b/src/nostalgia/core/studio/tilesheeteditor.hpp
index 53b76892..3a167dcc 100644
--- a/src/nostalgia/core/studio/tilesheeteditor.hpp
+++ b/src/nostalgia/core/studio/tilesheeteditor.hpp
@@ -6,103 +6,25 @@
 
 #include <ox/model/def.hpp>
 
+#include <nostalgia/core/gfx.hpp>
 #include <nostalgia/geo/bounds.hpp>
 #include <nostalgia/geo/vec.hpp>
-#include <nostalgia/core/gfx.hpp>
 #include <nostalgia/glutils/glutils.hpp>
 #include <nostalgia/studio/studio.hpp>
 
+#include "tilesheeteditormodel.hpp"
 #include "tilesheetpixelgrid.hpp"
 #include "tilesheetpixels.hpp"
 
 namespace nostalgia::core {
 
-// Command IDs to use with QUndoCommand::id()
-enum class CommandId {
-	UpdatePixel = 1,
-	ModPixel = 2,
-	UpdateDimension = 3,
-	InsertTile = 4,
-	ClipboardPaste = 5,
-};
-
-enum class TileSheetTool: int {
-	Select,
-	Draw,
-	Fill,
-};
-
-[[nodiscard]]
-constexpr auto toString(TileSheetTool t) noexcept {
-	switch (t) {
-		case TileSheetTool::Select:
-			return "Select";
-		case TileSheetTool::Draw:
-			return "Draw";
-		case TileSheetTool::Fill:
-			return "Fill";
-	}
-	return "";
-}
-
-struct PixelChunk {
-	static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.PixelChunk";
-	static constexpr auto TypeVersion = 1;
-	geo::Point pt;
-	int size = 0;
-};
-
-oxModelBegin(PixelChunk)
-	oxModelField(pt)
-	oxModelField(size)
-oxModelEnd()
-
-struct TileSheetClipboard {
-	static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard";
-	static constexpr auto TypeVersion = 1;
-
-	oxModelFriend(TileSheetClipboard);
-
-	protected:
-		ox::Vector<int> m_pixels;
-		geo::Point m_p1;
-		geo::Point m_p2;
-
-	public:
-		void addPixel(int color);
-
-		[[nodiscard]]
-		bool empty() const;
-
-		void pastePixels(const geo::Point &pt, ox::Vector<int> *tgt, int tgtColumns) const;
-
-		void setPoints(const geo::Point &p1, const geo::Point &p2);
-
-		[[nodiscard]]
-		geo::Point point1() const;
-
-		[[nodiscard]]
-		geo::Point point2() const;
-
-};
-
-template<typename T>
-constexpr ox::Error model(T *io, TileSheetClipboard *b) noexcept {
-	io->template setTypeInfo<TileSheetClipboard>();
-	oxReturnError(io->field("pixels", &b->m_pixels));
-	oxReturnError(io->field("p1", &b->m_p1));
-	oxReturnError(io->field("p2", &b->m_p2));
-	return OxError(0);
-}
-
 class TileSheetEditor {
 
 	private:
+		TileSheetEditorModel m_model;
 		TileSheetGrid m_pixelGridDrawer;
 		TileSheetPixels m_pixelsDrawer;
 		bool m_updated = false;
-		NostalgiaGraphic m_img;
-		AssetRef<NostalgiaPalette> m_pal;
 		float m_pixelSizeMod = 1;
 		geo::Vec2 m_scrollOffset;
 
@@ -121,16 +43,19 @@ class TileSheetEditor {
 
 		void clickPixel(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept;
 
-		void scrollV(const geo::Vec2 paneSz, float wheel, bool zoomMod) noexcept;
+		void scrollV(const geo::Vec2 &paneSz, float wheel, bool zoomMod) noexcept;
 
-		void scrollH(const geo::Vec2 paneSz, float wheel) noexcept;
+		void scrollH(const geo::Vec2 &paneSz, float wheel) noexcept;
 
 		void resize(const geo::Vec2 &sz) noexcept;
 
-		const NostalgiaGraphic &img() const;
+		[[nodiscard]]
+		constexpr const NostalgiaGraphic &img() const noexcept;
 
-		const NostalgiaPalette &pal() const;
+		[[nodiscard]]
+		constexpr const NostalgiaPalette &pal() const noexcept;
 
+		[[nodiscard]]
 		bool updated() const noexcept;
 
 		void ackUpdate() noexcept;
@@ -138,8 +63,6 @@ class TileSheetEditor {
 	protected:
 		void saveItem();
 
-		void getFillPixels(bool *pixels, geo::Point pt, int oldColor) const;
-
 	private:
 		void setPalette();
 
@@ -161,4 +84,12 @@ class TileSheetEditor {
 
 };
 
+constexpr const NostalgiaGraphic &TileSheetEditor::img() const noexcept {
+	return m_model.img();
+}
+
+constexpr const NostalgiaPalette &TileSheetEditor::pal() const noexcept {
+	return m_model.pal();
+}
+
 }
diff --git a/src/nostalgia/core/studio/tilesheeteditormodel.cpp b/src/nostalgia/core/studio/tilesheeteditormodel.cpp
new file mode 100644
index 00000000..09f3aa91
--- /dev/null
+++ b/src/nostalgia/core/studio/tilesheeteditormodel.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
+ */
+
+#include <nostalgia/core/media.hpp>
+
+#include "tilesheeteditormodel.hpp"
+
+namespace nostalgia::core {
+
+TileSheetEditorModel::TileSheetEditorModel(Context *ctx, const ox::String &path) {
+	// build shaders
+	oxRequireT(img, readObj<NostalgiaGraphic>(ctx, path.c_str()));
+	m_img = std::move(*img);
+	oxThrowError(readObj<NostalgiaPalette>(ctx, m_img.defaultPalette).moveTo(&m_pal));
+}
+
+void TileSheetEditorModel::getFillPixels(bool *pixels, geo::Point pt, int oldColor) const noexcept {
+	const auto tileIdx = [this](const geo::Point &pt) noexcept {
+		return ptToIdx(pt, img().columns) / PixelsPerTile;
+	};
+	// get points
+	const auto leftPt = pt + geo::Point(-1, 0);
+	const auto rightPt = pt + geo::Point(1, 0);
+	const auto topPt = pt + geo::Point(0, -1);
+	const auto bottomPt = pt + geo::Point(0, 1);
+	// calculate indices
+	const auto idx = ptToIdx(pt, m_img.columns);
+	const auto leftIdx = ptToIdx(leftPt, m_img.columns);
+	const auto rightIdx = ptToIdx(rightPt, m_img.columns);
+	const auto topIdx = ptToIdx(topPt, m_img.columns);
+	const auto bottomIdx = ptToIdx(bottomPt, m_img.columns);
+	const auto tile = tileIdx(pt);
+	// mark pixels to update
+	pixels[idx % PixelsPerTile] = true;
+	if (!pixels[leftIdx % PixelsPerTile] && tile == tileIdx(leftPt) && m_img.pixels[leftIdx] == oldColor) {
+		getFillPixels(pixels, leftPt, oldColor);
+	}
+	if (!pixels[rightIdx % PixelsPerTile] && tile == tileIdx(rightPt) && m_img.pixels[rightIdx] == oldColor) {
+		getFillPixels(pixels, rightPt, oldColor);
+	}
+	if (!pixels[topIdx % PixelsPerTile] && tile == tileIdx(topPt) && m_img.pixels[topIdx] == oldColor) {
+		getFillPixels(pixels, topPt, oldColor);
+	}
+	if (!pixels[bottomIdx % PixelsPerTile] && tile == tileIdx(bottomPt) && m_img.pixels[bottomIdx] == oldColor) {
+		getFillPixels(pixels, bottomPt, oldColor);
+	}
+}
+
+}
\ No newline at end of file
diff --git a/src/nostalgia/core/studio/tilesheeteditormodel.hpp b/src/nostalgia/core/studio/tilesheeteditormodel.hpp
new file mode 100644
index 00000000..141c169c
--- /dev/null
+++ b/src/nostalgia/core/studio/tilesheeteditormodel.hpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
+ */
+
+#pragma once
+
+#include <ox/std/string.hpp>
+
+#include <nostalgia/geo/bounds.hpp>
+#include <nostalgia/geo/vec.hpp>
+#include <nostalgia/core/gfx.hpp>
+#include <nostalgia/glutils/glutils.hpp>
+#include <nostalgia/studio/studio.hpp>
+
+namespace nostalgia::core {
+
+// Command IDs to use with QUndoCommand::id()
+enum class CommandId {
+	UpdatePixel = 1,
+	ModPixel = 2,
+	UpdateDimension = 3,
+	InsertTile = 4,
+	ClipboardPaste = 5,
+};
+
+enum class TileSheetTool: int {
+	Select,
+	Draw,
+	Fill,
+};
+
+[[nodiscard]]
+constexpr auto toString(TileSheetTool t) noexcept {
+	switch (t) {
+		case TileSheetTool::Select:
+			return "Select";
+		case TileSheetTool::Draw:
+			return "Draw";
+		case TileSheetTool::Fill:
+			return "Fill";
+	}
+	return "";
+}
+
+struct PixelChunk {
+	static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.PixelChunk";
+	static constexpr auto TypeVersion = 1;
+	geo::Point pt;
+	int size = 0;
+};
+
+oxModelBegin(PixelChunk)
+	oxModelField(pt)
+	oxModelField(size)
+oxModelEnd()
+
+struct TileSheetClipboard {
+		static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard";
+		static constexpr auto TypeVersion = 1;
+
+		oxModelFriend(TileSheetClipboard);
+
+	protected:
+		ox::Vector<int> m_pixels;
+		geo::Point m_p1;
+		geo::Point m_p2;
+
+	public:
+		void addPixel(int color);
+
+		[[nodiscard]]
+		bool empty() const;
+
+		void pastePixels(const geo::Point &pt, ox::Vector<int> *tgt, int tgtColumns) const;
+
+		void setPoints(const geo::Point &p1, const geo::Point &p2);
+
+		[[nodiscard]]
+		geo::Point point1() const;
+
+		[[nodiscard]]
+		geo::Point point2() const;
+
+};
+
+template<typename T>
+constexpr ox::Error model(T *io, TileSheetClipboard *b) noexcept {
+	io->template setTypeInfo<TileSheetClipboard>();
+	oxReturnError(io->field("pixels", &b->m_pixels));
+	oxReturnError(io->field("p1", &b->m_p1));
+	oxReturnError(io->field("p2", &b->m_p2));
+	return OxError(0);
+}
+
+class TileSheetEditorModel {
+
+	private:
+		NostalgiaGraphic m_img;
+		AssetRef<NostalgiaPalette> m_pal;
+
+	public:
+		TileSheetEditorModel(Context *ctx, const ox::String &path);
+
+		~TileSheetEditorModel() = default;
+
+		void cut();
+
+		void copy();
+
+		void paste();
+
+		[[nodiscard]]
+		constexpr const NostalgiaGraphic &img() const noexcept;
+
+		[[nodiscard]]
+		constexpr NostalgiaGraphic &img() noexcept;
+
+		[[nodiscard]]
+		constexpr const NostalgiaPalette &pal() const noexcept;
+
+	protected:
+		void saveItem();
+
+		void getFillPixels(bool *pixels, geo::Point pt, int oldColor) const noexcept;
+
+	private:
+		void setPalette();
+
+		void saveState();
+
+		void restoreState();
+
+		[[nodiscard]]
+		ox::String paletteName(const ox::String &palettePath) const;
+
+		[[nodiscard]]
+		ox::String palettePath(const ox::String &palettePath) const;
+
+		// slots
+	public:
+		ox::Error colorSelected() noexcept;
+
+		ox::Error setColorTable() noexcept;
+
+};
+
+constexpr const NostalgiaGraphic &TileSheetEditorModel::img() const noexcept {
+	return m_img;
+}
+
+constexpr NostalgiaGraphic &TileSheetEditorModel::img() noexcept {
+	return m_img;
+}
+
+constexpr const NostalgiaPalette &TileSheetEditorModel::pal() const noexcept {
+	return *m_pal;
+}
+
+}
\ No newline at end of file
diff --git a/src/nostalgia/core/studio/tilesheetpixelgrid.cpp b/src/nostalgia/core/studio/tilesheetpixelgrid.cpp
index abedf1d8..d629b58f 100644
--- a/src/nostalgia/core/studio/tilesheetpixelgrid.cpp
+++ b/src/nostalgia/core/studio/tilesheetpixelgrid.cpp
@@ -25,9 +25,9 @@ void TileSheetGrid::draw(bool update, const geo::Vec2 &scroll) noexcept {
 	if (update) {
 		glutils::sendVbo(m_bufferSet);
 	}
-	const auto uniformScroll = static_cast<GLint>(glGetUniformLocation(m_shader, "gScroll"));
+	const auto uniformScroll = glGetUniformLocation(m_shader, "gScroll");
 	glUniform2f(uniformScroll, scroll.x, scroll.y);
-	glDrawArrays(GL_POINTS, 0, m_bufferSet.vertices.size() / VertexVboRowLength);
+	glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(m_bufferSet.vertices.size() / VertexVboRowLength));
 }
 
 void TileSheetGrid::initBufferSet(const geo::Vec2 &paneSize, const NostalgiaGraphic &img) noexcept {
diff --git a/src/nostalgia/core/studio/tilesheetpixels.cpp b/src/nostalgia/core/studio/tilesheetpixels.cpp
index 0b3a61a6..e2ad28e0 100644
--- a/src/nostalgia/core/studio/tilesheetpixels.cpp
+++ b/src/nostalgia/core/studio/tilesheetpixels.cpp
@@ -24,7 +24,7 @@ void TileSheetPixels::draw(bool update, const geo::Vec2 &scroll) noexcept {
 	if (update) {
 		glutils::sendVbo(m_bufferSet);
 	}
-	const auto uniformScroll = static_cast<GLint>(glGetUniformLocation(m_shader, "vScroll"));
+	const auto uniformScroll = glGetUniformLocation(m_shader, "vScroll");
 	glUniform2f(uniformScroll, scroll.x, scroll.y);
 	glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_bufferSet.elements.size()), GL_UNSIGNED_INT, nullptr);
 }
@@ -56,7 +56,7 @@ geo::Vec2 TileSheetPixels::pixelSize(const geo::Vec2 &paneSize) const noexcept {
 	return {xmod * m_pixelSizeMod, ymod * m_pixelSizeMod};
 }
 
-void TileSheetPixels::setPixelBufferObject(const geo::Vec2 &paneSize, unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) noexcept {
+void TileSheetPixels::setPixelBufferObject(const geo::Vec2 &paneSize, unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) const noexcept {
 	const auto [xmod, ymod] = pixelSize(paneSize);
 	x *= xmod;
 	y *= -ymod;
diff --git a/src/nostalgia/core/studio/tilesheetpixels.hpp b/src/nostalgia/core/studio/tilesheetpixels.hpp
index 7a2c5053..a8750913 100644
--- a/src/nostalgia/core/studio/tilesheetpixels.hpp
+++ b/src/nostalgia/core/studio/tilesheetpixels.hpp
@@ -54,7 +54,7 @@ class TileSheetPixels {
 		geo::Vec2 pixelSize(const geo::Vec2 &paneSize) const noexcept;
 
 	private:
-		void setPixelBufferObject(const geo::Vec2 &paneS, unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) noexcept;
+		void setPixelBufferObject(const geo::Vec2 &paneS, unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) const noexcept;
 
 		void setBufferObjects(const geo::Vec2 &paneS, const NostalgiaGraphic &img, const NostalgiaPalette &pal, glutils::BufferSet *bg) noexcept;