diff --git a/demo/data/tileset_base.yml b/demo/data/tileset_base.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a7453cb2cf6a7dd04b2139ba2aa89a516d69e768
--- /dev/null
+++ b/demo/data/tileset_base.yml
@@ -0,0 +1,9 @@
+---
+floors:
+  ground:
+    visible: true
+walls:
+  none:
+    visible: false
+  solid:
+    visible: true
\ No newline at end of file
diff --git a/demo/demo/grid.cpp b/demo/demo/grid.cpp
index 0a26d652c36ed20c6caa0f98b0212f6c9a2f4263..2349a8ee0417b00d5fdc0059951bf43fd8a636d7 100644
--- a/demo/demo/grid.cpp
+++ b/demo/demo/grid.cpp
@@ -17,47 +17,100 @@
 //
 
 #include "grid.hpp"
+
+#include "fggl/assets/loader.hpp"
 #include "fggl/entity/gridworld/zone.hpp"
 
-namespace demo {
+using namespace fggl::gfx::colours;
 
-	GridScene::GridScene(fggl::App &app) : Game(app), m_tiles(), m_grid(nullptr) {
-	}
+namespace demo {
 
-	void GridScene::activate() {
-		Game::activate();
-		fggl::debug::log(fggl::debug::Level::info, "GridScene::activate()");
+	using namespace fggl::entity::grid;
 
-		// create the grid world
-		fggl::entity::grid::FloorTile empty{fggl::entity::grid::FloorTile::IMPOSSIBLE, fggl::gfx::colours::BLACK};
-		fggl::entity::grid::FloorTile ground{1, fggl::gfx::colours::GREEN};
-		m_tiles.m_floors.push_back(empty);
-		m_tiles.m_floors.push_back(ground);
+	static void build_tileset(TileSet& tiles) {
+		fggl::entity::grid::FloorTile empty{fggl::entity::grid::FloorTile::IMPOSSIBLE, BLACK};
+		fggl::entity::grid::FloorTile ground{1, GREEN};
+		tiles.m_floors.push_back(empty);
+		tiles.m_floors.push_back(ground);
 
 		fggl::entity::grid::WallTile noWall{};
-		m_tiles.m_walls.push_back(noWall);
+		tiles.m_walls.push_back(noWall);
 
 		fggl::entity::grid::WallTile solidWall{
 			.render = true,
-			.colour = fggl::gfx::colours::DARK_SLATE_GRAY
+			.colour = DARK_SLATE_GRAY
 		};
-		m_tiles.m_walls.push_back(solidWall);
+		tiles.m_walls.push_back(solidWall);
+	}
 
-		m_grid = std::make_unique<fggl::entity::grid::Area2D<255,255>>(m_tiles);
-		m_grid->clear();
+	static void build_room(DemoGrid* area, fggl::math::vec2i center, fggl::math::vec2i size) {
 
-		// create a small area to use
-		for (int i=3; i<20; ++i) {
-			m_grid->setWallAt(i, 3, true, 1);
-			m_grid->setWallAt(i, 20, true, 1);
-			m_grid->setWallAt(20, i, false, 1);
-			m_grid->setWallAt(3, i, false, 1);
+		for (int yOffset = -size.y; yOffset <= size.y; ++yOffset) {
+			auto yPos = yOffset + center.y;
+			area->setWallAt(center.x - size.x, yPos, false, 1);
+			area->setWallAt(center.x + size.x + 1, yPos, false, 1);
+		}
+
+		for (int xOffset = -size.x; xOffset <= size.x; ++xOffset) {
+			auto xPos = center.x + xOffset;
+
+			area->setWallAt(xPos, center.y - size.y, true, 1);
+			area->setWallAt(xPos, center.y + size.y + 1, true, 1);
+
+			for (int yOffset = -size.y; yOffset <= size.y; ++yOffset) {
+				auto yPos = yOffset + center.y;
+				area->setFloorAt(xPos, yPos, 1);
+			}
+		}
+	}
 
-			for (int j=3; j<20; ++j) {
-				m_grid->setFloorAt(i, j, 1);
+	void build_doorway(DemoGrid* area, fggl::math::vec2i position, bool north, int size = 1) {
+		for ( auto offset = 0; offset < size; offset++) {
+			if ( north ) {
+				area->setWallAt(position.x + offset, position.y, north, 0);
+			} else {
+				area->setWallAt(position.x, position.y + offset, north, 0);
 			}
 		}
+	}
 
+	static void build_test_env(DemoGrid* area) {
+		area->clear();
+		build_room(area, {5, 5}, {4,4});
+		build_room(area, {11, 5}, {1,1});
+		build_room(area, {17, 5}, {4,4});
+		build_doorway(area, {10, 5}, false, 1);
+		build_doorway(area, {13, 5}, false, 1);
+
+		build_room(area, {25, 5}, {3,3});
+
+		// player
+		auto& manager = area->entities();
+		{
+			auto player = manager.create();
+			auto& cellPos = manager.add<CellPos>(player);
+			cellPos.pos = {5,5};
+		}
+	}
+
+	GridScene::GridScene(fggl::App &app) : Game(app), m_tiles(), m_grid(nullptr) {
+	}
+
+	void GridScene::activate() {
+		Game::activate();
+		fggl::debug::log(fggl::debug::Level::info, "GridScene::activate()");
+
+
+		// fake loading the tileset
+		if ( m_tiles.m_floors.empty() ) {
+			build_tileset(m_tiles);
+			//auto* assetLoader = m_owner.service<fggl::assets::Loader>();
+			//assetLoader->load("tileset_base.yml", ASSET_TILESET);
+		}
+
+		// create the grid world
+		m_grid = std::make_unique<DemoGrid>(m_tiles);
+		build_test_env(m_grid.get());
 	}
 
 	void GridScene::deactivate() {
@@ -99,12 +152,31 @@ namespace demo {
 		}
 	}
 
-	float progress = 0.0f;
+
+	static void render_objects(fggl::gfx::Paint& paint, DemoGrid& grid) {
+		auto& manager = grid.entities();
+
+		auto entities = manager.find<CellPos>();
+		for (const auto& entity : entities ) {
+			//auto& sprite = manager.get<Sprite>(entity);
+			auto& cellPos = manager.get<CellPos>(entity);
+
+			// convert grid pos to world pos
+			fggl::math::vec2f drawPos = cellPos.pos;
+			drawPos *= DRAW_SIZE;
+
+			auto shape = fggl::gfx::make_shape(drawPos, DRAW_HALF, 3);
+			paint.fill(shape);
+		}
+	}
+
+	//float progress = 0.0f;
 	void GridScene::render(fggl::gfx::Graphics &gfx) {
 		Game::render(gfx);
 
 		fggl::gfx::Paint paint;
 		render_grid(paint, *m_grid);
+		render_objects(paint, *m_grid);
 
 		/*
 		// draw test shapes to check grid alignment
diff --git a/demo/include/grid.hpp b/demo/include/grid.hpp
index 6c089b587d61e5a206ec53f3f085bdb81fe065ea..46954317a75b1790b3a7422eeee2e715a5c551a5 100644
--- a/demo/include/grid.hpp
+++ b/demo/include/grid.hpp
@@ -27,6 +27,15 @@
 namespace demo {
 
 	constexpr int GRID_SIZE = 255;
+	using DemoGrid = fggl::entity::grid::Area2D<GRID_SIZE, GRID_SIZE>;
+
+	struct Sprite {
+
+	};
+
+	struct CellPos {
+		fggl::math::vec2i pos;
+	};
 
 	class GridScene : public fggl::scenes::Game {
 		public:
@@ -38,7 +47,7 @@ namespace demo {
 			void render(fggl::gfx::Graphics& gfx) override;
 		private:
 			fggl::entity::grid::TileSet m_tiles;
-			std::unique_ptr<fggl::entity::grid::Area2D<GRID_SIZE,GRID_SIZE>> m_grid;
+			std::unique_ptr<DemoGrid> m_grid;
 
 	};
 
diff --git a/include/fggl/entity/gridworld/zone.hpp b/include/fggl/entity/gridworld/zone.hpp
index 039ada76c225b62d9511f46cbacbec728bd1f102..376c7db11640dde4a1f638b936b71184cd4b3ed7 100644
--- a/include/fggl/entity/gridworld/zone.hpp
+++ b/include/fggl/entity/gridworld/zone.hpp
@@ -23,10 +23,13 @@
 #include <vector>
 
 #include "fggl/math/types.hpp"
+#include "fggl/assets/types.hpp"
+#include "fggl/entity/entity.hpp"
 
 namespace fggl::entity::grid {
 
 	using GridPos = math::vec2i;
+	constexpr auto ASSET_TILESET = assets::AssetType::make("tileset");
 
 	template<typename T, uint32_t width, uint32_t height>
 	struct Grid {
@@ -147,11 +150,16 @@ namespace fggl::entity::grid {
 				}
 			}
 
+			EntityManager& entities() {
+				return m_entities;
+			}
+
 			void neighbours(math::vec2i pos, std::vector<math::vec2i> &neighbours) const;
 		private:
 			TileSet& m_tiles;
 			Grid<uint32_t, width, height> m_floors;
 			Grid<WallState, width + 1, height + 1> m_walls;
+			EntityManager m_entities;
 	};
 
 } // namespace fggl::entity::gridworld