diff --git a/demo/main.cpp b/demo/main.cpp
index f17d9fe2fffa7cfd8d9c1afb6b21312349590275..9bc3aaee0d188f0b4c9375e2aac4928edcc4e270 100644
--- a/demo/main.cpp
+++ b/demo/main.cpp
@@ -13,6 +13,7 @@
 #include "fggl/gfx/ogl/renderer.hpp"
 #include "fggl/gfx/ogl/compat.hpp"
 #include "fggl/gfx/compat.hpp"
+#include "fggl/gui/containers.hpp"
 
 #include <fggl/data/heightmap.h>
 #include <fggl/data/procedural.hpp>
@@ -124,6 +125,8 @@ public:
     }
 
     void setup() {
+		m_canvas.size( fggl::math::vec2(0,0), fggl::math::vec2(100, 100));
+
         auto types = m_world->types();
 
         // create camera using strings
@@ -250,14 +253,21 @@ public:
         }
     }
 
-    void render(fggl::gfx::Paint& paint) override {
-        //debugInspector();
-        //fggl::gfx::renderMeshes(glModule, *m_world, m_sceneTime->delta());
-    }
+    void render(fggl::gfx::Graphics& gfx) override {
+		// render the 3D scene
+		if ( m_world != nullptr ) {
+			gfx.drawScene( *m_world );
+		}
 
-	fggl::ecs3::World* world() override {
-		return m_world.get();
-	}
+		const fggl::math::vec2 panelSize { 250.0F, 250.0F };
+		const auto canvasY = gfx.canvasBounds().bottom - panelSize.y;
+		m_canvas.size( {0.0F, canvasY}, panelSize);
+
+		// now the 2D scene
+		fggl::gfx::Paint paint;
+		m_canvas.render(paint);
+		gfx.draw2D(paint);
+    }
 
     // entity inspector
     void debugInspector() {
@@ -283,6 +293,7 @@ private:
     std::unique_ptr<fggl::ecs3::World> m_world;
     std::unique_ptr<fggl::util::Timer> m_sceneTime;
     InputManager m_inputs;
+	fggl::gui::Panel m_canvas;
 };
 
 void gamepadDebug(bool* visible) {
diff --git a/fggl/app.cpp b/fggl/app.cpp
index 5ca623b73d3db732cd8d9d3a6938916b83193989..134999398f2d15ea0c230c4a6ebefc43d670fe3e 100644
--- a/fggl/app.cpp
+++ b/fggl/app.cpp
@@ -41,17 +41,9 @@ namespace fggl {
                 m_window->frameStart();
 
                 // get draw instructions
-                fggl::gfx::Paint paint;
-                state.render(paint);
+				auto& graphics = m_window->graphics();
+                state.render(graphics);
 
-                // execute draw instructions
-                auto& graphics = m_window->graphics();
-                graphics.draw2D( paint );
-
-				ecs3::World* world = state.world();
-				if ( world != nullptr ) {
-					graphics.drawScene(*world);
-				}
 
                 m_window->frameEnd();
                 m_modules->onFrameEnd();
diff --git a/fggl/gfx/ogl4/canvas.cpp b/fggl/gfx/ogl4/canvas.cpp
index 729dbfedfa3fd31be0af0a528db0476d077b5c79..c106c02e1d7e34b78b562ba185c9c3c1df2c9347 100644
--- a/fggl/gfx/ogl4/canvas.cpp
+++ b/fggl/gfx/ogl4/canvas.cpp
@@ -29,6 +29,7 @@
 #include "fggl/util/service.h"
 
 #include "fggl/gui/fonts.hpp"
+#include "fggl/gfx/windowing.hpp"
 
 #define FGGL_OPENGL_CORRECTNESS
 
@@ -90,7 +91,9 @@ namespace fggl::gfx::ogl4 {
 		}
 	}
 
-	CanvasRenderer::CanvasRenderer() : m_fontTex(ogl::TextureType::Tex2D) {
+	CanvasRenderer::CanvasRenderer() :
+		m_bounds({0.0F, 1920.F, 1080.0F, 0.0F}),
+		m_fontTex(ogl::TextureType::Tex2D) {
 		m_vao.bind();
 
 		#ifdef FGGL_GL_I_BOUND
@@ -133,10 +136,12 @@ namespace fggl::gfx::ogl4 {
 		m_indexList.replace(mesh.indexList.size(), mesh.indexList.data());
 
 		// draw
+		glDisable( GL_DEPTH_TEST );
+		glDisable( GL_CULL_FACE );
 
 		// FIXME: this should be abstracted into the shader class
 		glUseProgram( shader );
-		auto projMat = glm::ortho(0.0f, 1920.0f, 1080.0f, 0.f);
+		auto projMat = glm::ortho(m_bounds.left, m_bounds.right, m_bounds.bottom, m_bounds.top);
 		glUniformMatrix4fv(glGetUniformLocation( shader, "projection"), 1, GL_FALSE,
 						   glm::value_ptr(projMat));
 
@@ -150,6 +155,7 @@ namespace fggl::gfx::ogl4 {
 			return;
 		}
 
+
 		// get the expected font
 		auto fontFactory = util::ServiceLocator::instance().get<gui::FontLibrary>();
 		std::shared_ptr<gui::FontFace> face = fontFactory->getFont("LiberationSans-Regular.ttf");
@@ -167,8 +173,12 @@ namespace fggl::gfx::ogl4 {
 		// bind the vbo we'll use for writing
 		m_vao.bind();
 
-		glEnable(GL_BLEND);
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		// setup the openGL state we expect for rendering
+		glDisable( GL_DEPTH_TEST );
+		glDisable( GL_CULL_FACE );
+
+		glEnable( GL_BLEND );
+		glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
 
 		// for each text string, attempt to render it
 		for ( const auto& textCmd : paint.textCmds() ) {
@@ -219,6 +229,7 @@ namespace fggl::gfx::ogl4 {
 		}
 
 		glDisable(GL_BLEND);
+		glEnable(GL_DEPTH_TEST);
 	}
 
 	/*
diff --git a/fggl/gui/containers.cpp b/fggl/gui/containers.cpp
index ed36f1ad1c7b7cb03ac34fcc4485358af53282f2..60056ec60d76bf95cf2837aab47e6ed27d419e99 100644
--- a/fggl/gui/containers.cpp
+++ b/fggl/gui/containers.cpp
@@ -1,4 +1,5 @@
 #include <fggl/gui/containers.hpp>
+#include <spdlog/spdlog.h>
 
 namespace fggl::gui {
 
@@ -52,4 +53,16 @@ namespace fggl::gui {
 			setSize(biggestCross, lineSum);
 	}*/
 
+	void Panel::render(gfx::Paint &paint) {
+		spdlog::info("Imma render mah panel! {}, {}", bottomRight().x, bottomRight().y );
+
+		// background painting time
+		gfx::Path2D background(topLeft());
+		background.colour(math::vec3(1.0F, 1.0F, 0.0F));
+		draw_box(background, topLeft(), bottomRight());
+		paint.fill(background);
+
+		// call parent's render method for child objects
+		Container::render(paint);
+	}
 };
diff --git a/fggl/gui/widget.cpp b/fggl/gui/widget.cpp
index 837a42c63683ad88fea86e5eddb72619844dd90c..9aa8fe8de9969988aeaf819abefd9336c76795d3 100644
--- a/fggl/gui/widget.cpp
+++ b/fggl/gui/widget.cpp
@@ -26,7 +26,7 @@ namespace fggl::gui {
 		path.pathTo( { innerTop.x, innerTop.y } );
 	}
 
-	void makeBox( gfx::Path2D& path, glm::vec2 topLeft, glm::vec2 bottomRight ) {
+	void draw_box( gfx::Path2D& path, glm::vec2 topLeft, glm::vec2 bottomRight ) {
 		path.moveTo( { topLeft.x, topLeft.y } );
 		path.pathTo( { bottomRight.x, topLeft.y } );
 		path.pathTo( { bottomRight.x, bottomRight.y } );
@@ -39,7 +39,7 @@ namespace fggl::gui {
 
 		// background
 		path.colour( {0.5f, 0.5f, 0.5f} );
-		makeBox( path, topLeft, bottomRight );
+		draw_box( path, topLeft, bottomRight );
 
 		// fill
 		math::vec2 innerTop { topLeft.x + 5, topLeft.y + 5 };
@@ -52,14 +52,13 @@ namespace fggl::gui {
 
 		// draw the bar
 		path.colour( {0.8f, 0.0f, 0.0f} );
-		makeBox( path, innerTop, innerBottom );
+		draw_box( path, innerTop, innerBottom );
 
 		// part of the bar that's not filled in
 		math::vec2 emptyTop { innerBottom.x, innerTop.y };
 		math::vec2 emptyBottom { trueBottom, innerBottom.y };
 		path.colour( {0.4f, 0.0f, 0.0f} );
-		makeBox( path, emptyTop, emptyBottom );
-
+		draw_box( path, emptyTop, emptyBottom );
 	}
 
 	void draw_slider( gfx::Path2D& path, glm::vec2 topLeft, glm::vec2 size, float value ) {
@@ -78,7 +77,7 @@ namespace fggl::gui {
 		math::vec2 selectorTop { innerTop.x + selectorValue - ( selectorWidth/2), topLeft.y };
 		math::vec2 selectorBottom { selectorTop.x + selectorWidth, bottomRight.y };
 		path.colour( {1.0f, 1.0f, 1.0f} );
-		makeBox( path, selectorTop, selectorBottom );
+		draw_box( path, selectorTop, selectorBottom );
 	}
 
 	void draw_button( gfx::Path2D& path, glm::vec2 pos, glm::vec2 size, bool active, bool pressed) {
@@ -141,6 +140,6 @@ namespace fggl::gui {
 
 		// inner box
 		path.colour( baseColour );
-		makeBox( path, innerTop, innerBottom );
+		draw_box( path, innerTop, innerBottom );
 	}
 }
\ No newline at end of file
diff --git a/fggl/scenes/menu.cpp b/fggl/scenes/menu.cpp
index c1629e2932e0f0fdf84c867aa228aa53830c23fa..712056f42e05963d0c738d1c758f48aa5b16c16a 100644
--- a/fggl/scenes/menu.cpp
+++ b/fggl/scenes/menu.cpp
@@ -54,8 +54,11 @@ namespace fggl::scenes {
         }
     }
 
-    void BasicMenu::render(gfx::Paint& paint) {
+    void BasicMenu::render(gfx::Graphics& gfx) {
+		// render the 2D scene (we don't have a 3D scene to worry about in menus)
+		gfx::Paint paint;
 		m_canvas.render( paint );
+		gfx.draw2D(paint);
     }
 
     void BasicMenu::activate() {
diff --git a/include/fggl/app.hpp b/include/fggl/app.hpp
index a73989c137bc70e0a103cc204650ffe881731e8e..a83dece63bbebdb70e63806b02b22c547dd0b834 100644
--- a/include/fggl/app.hpp
+++ b/include/fggl/app.hpp
@@ -76,16 +76,12 @@ namespace fggl {
 			 * It is not safe to assume the render target will always be the same, as the scene may be
 			 * rendered in mutliple passes (eg, for VR requirements).
 			 */
-			virtual void render(gfx::Paint &paint) = 0;
+			virtual void render(gfx::Graphics &paint) = 0;
 
 			virtual void activate() {}
 
 			virtual void deactivate() {}
 
-			inline virtual ecs3::World* world() {
-				return nullptr;
-			}
-
 		protected:
 			App &m_owner;
 	};
diff --git a/include/fggl/gfx/ogl/renderer.hpp b/include/fggl/gfx/ogl/renderer.hpp
index a07cbaba16a59fe0e07f11103fed8af9f1cba288..97f621f0d3a05371ac92a471b3dce84acbaf0eec 100644
--- a/include/fggl/gfx/ogl/renderer.hpp
+++ b/include/fggl/gfx/ogl/renderer.hpp
@@ -59,6 +59,10 @@ namespace fggl::gfx {
 			void draw2D(const Paint &paint) override;
 			void drawScene(ecs3::World& world) override;
 
+			inline Bounds canvasBounds() override {
+				return m_canvasRenderer->bounds();
+			}
+
 		private:
 			std::unique_ptr<ogl4::StaticModelRenderer> m_modelRenderer;
 			std::unique_ptr<ogl4::CanvasRenderer> m_canvasRenderer;
diff --git a/include/fggl/gfx/ogl4/canvas.hpp b/include/fggl/gfx/ogl4/canvas.hpp
index 6c90bff32cf512d8a33983bdbfe3a495c1527ac1..849d1af7e3fb9fab772bdbc7e7eac6edc850d1cd 100644
--- a/include/fggl/gfx/ogl4/canvas.hpp
+++ b/include/fggl/gfx/ogl4/canvas.hpp
@@ -7,6 +7,7 @@
 
 #include "fggl/gfx/paint.hpp"
 #include "fggl/gfx/ogl/types.hpp"
+#include "fggl/gfx/windowing.hpp"
 
 #include "fggl/gui/fonts.hpp"
 
@@ -17,11 +18,15 @@ namespace fggl::gfx::ogl4 {
 			CanvasRenderer();
 			void render(GLuint shader, const gfx::Paint& paint);
 
+			inline gfx::Bounds bounds() const {
+				return m_bounds;
+			}
+
 		private:
+			gfx::Bounds m_bounds;
 			ogl::VertexArray m_vao;
 			ogl::ArrayBuffer m_vertexList;
 			ogl::ElementBuffer m_indexList;
-
 			gui::FontLibrary m_fonts;
 			ogl::Texture m_fontTex;
 
diff --git a/include/fggl/gfx/windowing.hpp b/include/fggl/gfx/windowing.hpp
index 45866bc46edb4e8b867d9fbfe35e59cc1b6a7524..4a22fb5362d77469addd2929c23f6414718ac311 100644
--- a/include/fggl/gfx/windowing.hpp
+++ b/include/fggl/gfx/windowing.hpp
@@ -8,13 +8,22 @@
 
 namespace fggl::gfx {
 
+	struct Bounds {
+		float top;
+		float right;
+		float bottom;
+		float left;
+	};
+
 	class Graphics {
 		public:
 			virtual ~Graphics() = default;
 			virtual void clear() = 0;
 			virtual void resize(int width, int height) = 0;
 
+			virtual Bounds canvasBounds() = 0;
 			virtual void draw2D(const Paint &paint) = 0;
+
 			virtual void drawScene(ecs3::World&) = 0;
 	};
 
diff --git a/include/fggl/gui/containers.hpp b/include/fggl/gui/containers.hpp
index d27d59d8a8678ad2e64de0c1f028535b7efc1375..676a60b20467deb3a021cc980f01edc318a71adc 100644
--- a/include/fggl/gui/containers.hpp
+++ b/include/fggl/gui/containers.hpp
@@ -28,6 +28,15 @@ namespace fggl::gui {
 			std::vector<std::unique_ptr<Widget>> m_children;
 	};
 
+	class Panel : public Container {
+		public:
+			Panel() = default;
+			~Panel() = default;
+
+			void render(gfx::Paint& paint) override;
+
+	};
+
 	enum class LayoutAxis {
 		LINE_AXIS,
 		PAGE_AXIS
diff --git a/include/fggl/gui/widget.hpp b/include/fggl/gui/widget.hpp
index e74e496f11eda4b429f146e36af84b8d74b44cf3..f740bf1db71c38770819e7aba2831ab4cb3ac812 100644
--- a/include/fggl/gui/widget.hpp
+++ b/include/fggl/gui/widget.hpp
@@ -36,15 +36,20 @@ namespace fggl::gui {
 
 			virtual ~Widget() = default;
 
-			inline math::vec2 topLeft() {
+			inline math::vec2 topLeft() const {
 				return m_bounds.topLeft;
 			};
 
-			inline math::vec2 bottomRight() {
+			inline math::vec2 bottomRight() const {
 				return m_bounds.topLeft + m_bounds.size;
 			}
 
-			inline math::vec2 size() {
+			inline void size(math::vec2 pos, math::vec2 size) {
+				m_bounds.topLeft = pos;
+				m_bounds.size = size;
+			}
+
+			inline math::vec2 size() const {
 				return m_bounds.size;
 			}
 
diff --git a/include/fggl/scenes/menu.hpp b/include/fggl/scenes/menu.hpp
index b7ce39d7bea349ad187af294cc6378eab9b7959f..3e1b977b4ef8cf542c3e8fa2d8c25b75811af42d 100644
--- a/include/fggl/scenes/menu.hpp
+++ b/include/fggl/scenes/menu.hpp
@@ -19,7 +19,7 @@ namespace fggl::scenes {
 			explicit BasicMenu(App &owner);
 
 			void update() override;
-			void render(gfx::Paint &paint) override;
+			void render(gfx::Graphics &paint) override;
 
 			void activate() override;
 			void deactivate() override;