diff --git a/demo/demo/GameScene.cpp b/demo/demo/GameScene.cpp
index 1bb95b57c96dcfe6eb903038ba5bb334ce32e08a..0ce3b09be5e333100302f67340b7f199cd516c07 100644
--- a/demo/demo/GameScene.cpp
+++ b/demo/demo/GameScene.cpp
@@ -28,6 +28,10 @@
 camera_type cam_mode = cam_free;
 
 static void placeObject(fggl::entity::EntityManager& world, fggl::entity::EntityID floor, fggl::entity::EntityFactory* factory, fggl::util::GUID prototype, glm::vec3 targetPos) {
+	#ifndef NDEBUG
+		fggl::debug::trace("Creating object from prototype: {}", fggl::util::guidToString(prototype));
+	#endif
+
 	auto obj = factory->create(prototype, world);
 	auto& result = world.get<fggl::math::Transform>(obj);
 
@@ -104,13 +108,13 @@ static fggl::entity::EntityID setupTerrain(fggl::entity::EntityManager& world) {
 				terrainData.setValue(x, z, (float)noise);
 			}
 		}
+		world.add<fggl::data::HeightMap>(terrain, terrainData);
 
-	//	world.set<fggl::data::HeightMap>(terrain, &terrainData);
 	}
 	return terrain;
 }
 
-static fggl::entity::EntityID setupEnvironment(fggl::entity::EntityManager& world) {
+static fggl::entity::EntityID setup_environment(fggl::entity::EntityManager& world) {
 	setupCamera(world);
 	return setupTerrain(world);
 }
@@ -120,14 +124,10 @@ static auto BUNKER_PROTOTYPE = "bunker"_fid;
 static void setupBunkerPrototype(fggl::entity::EntityFactory* factory) {
 	{
 		auto bunkerSpec = fggl::entity::EntitySpec{};
-		bunkerSpec.components[fggl::util::make_guid("transform")] = {};
-
-		fggl::entity::ComponentSpec procMesh{};
-		procMesh.set<std::string>("shader", "phong");
+		bunkerSpec.addComp(fggl::math::Transform::guid, {});
 
 		// mesh
 		int nSections = 2;
-
 		fggl::data::Mesh mesh;
 		for (int j=-(nSections/2); j<=nSections/2; j++) {
 			const auto shapeOffset = glm::vec3( 0.0f, 0.5f, (float)j * 1.0f );
@@ -146,9 +146,31 @@ static void setupBunkerPrototype(fggl::entity::EntityFactory* factory) {
 		}
 		mesh.removeDups();
 
-		procMesh.set<std::vector<fggl::data::Vertex>>("vertexData", mesh.vertexList());
-		procMesh.set<std::vector<unsigned int>>("indexData", mesh.indexList());
-		bunkerSpec.components[fggl::util::make_guid("procedural_mesh")] = procMesh;
+		// generate mesh component data
+		// FIXME: find a better way to do this, avoid re-uploading the whole mesh.
+		fggl::entity::ComponentSpec procMesh{};
+		procMesh.set<std::string>("pipeline", "redbook/debug");
+
+		YAML::Node vertexData;
+		for (auto& vertex : mesh.vertexList()) {
+			YAML::Node vertexNode;
+			vertexNode["position"] = vertex.posititon;
+			vertexNode["normal"] = vertex.normal;
+			vertexNode["colour"] = vertex.colour;
+			vertexNode["texPos"] = vertex.texPos;
+			vertexData.push_back(vertexNode);
+		}
+
+		YAML::Node indexData;
+		for (auto& index : mesh.indexList()) {
+			indexData.push_back(index);
+		}
+
+		YAML::Node meshData;
+		meshData["vertex"] = vertexData;
+		meshData["index"] = indexData;
+		procMesh.set("mesh", meshData);
+		bunkerSpec.addComp(fggl::data::StaticMesh::guid, procMesh);
 
 		factory->define(BUNKER_PROTOTYPE, bunkerSpec);
 	}
@@ -159,7 +181,7 @@ void GameScene::setup() {
 
 	auto* entityFactory = m_owner.service<fggl::entity::EntityFactory>();
 
-	auto terrain = setupEnvironment(world());
+	auto terrain = setup_environment(world());
 	setupBunkerPrototype(entityFactory);
 
 	// create building prototype
diff --git a/fggl/debug/CMakeLists.txt b/fggl/debug/CMakeLists.txt
index d2d4e1ce2dce81e01e0539aa91045b3782dec460..bd85e56f53c1773349991947a93d93d04820cc6e 100644
--- a/fggl/debug/CMakeLists.txt
+++ b/fggl/debug/CMakeLists.txt
@@ -2,6 +2,7 @@ target_sources(fggl
         PRIVATE
         debug.cpp
         debug_draw.cpp
+        logging.cpp
         )
 
 # spdlog for cleaner logging
diff --git a/fggl/debug/logging.cpp b/fggl/debug/logging.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3c726c54c7256cb862e8cf7aa9cea9bcfdbed230
--- /dev/null
+++ b/fggl/debug/logging.cpp
@@ -0,0 +1,43 @@
+/*
+ * This file is part of FGGL.
+ *
+ * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with FGGL.
+ * If not, see <https://www.gnu.org/licenses/>.
+ */
+
+//
+// Created by webpigeon on 11/09/22.
+//
+
+
+#ifdef __GNUG__
+	#include <cstdlib>
+	#include <memory>
+	#include <cxxabi.h>
+
+	namespace fggl::debug {
+		std::string demangle(const char *name) {
+			int status = -4;
+
+			std::unique_ptr<char, decltype(&std::free)> res{
+				abi::__cxa_demangle(name, nullptr, nullptr, &status),
+				std::free
+			};
+
+			return (status == 0) ? res.get() : name;
+		}
+	}
+#else
+	namespace fggl::debug {
+		std::string demangle(const char* name) {
+			return name;
+		}
+	}
+#endif
diff --git a/fggl/gfx/ogl4/models.cpp b/fggl/gfx/ogl4/models.cpp
index ed6e430698d371b9dbe5373962365b19d5b0cb9a..1095ac8ff2cb11923a4512998a14ce1debd0e2a8 100644
--- a/fggl/gfx/ogl4/models.cpp
+++ b/fggl/gfx/ogl4/models.cpp
@@ -108,7 +108,7 @@ namespace fggl::gfx::ogl4 {
 			modelComp.restartIndex = heightMapMesh.restartVertex;
 
 			// no active model, we need to resolve/load one.
-			//spdlog::info("looks like heightmap, {} needs a static mesh", renderable);
+			debug::info("looks like {} needs a static mesh", (uint64_t)renderable);
 		}
 	}
 
@@ -152,7 +152,7 @@ namespace fggl::gfx::ogl4 {
 				// ensure that the model pipeline actually exists...
 				const auto &model = world.get<StaticModel>(entity);
 				if (model.pipeline == nullptr) {
-					spdlog::warn("shader was null, aborting render");
+					debug::warning("shader was null, aborting render");
 					continue;
 				}
 
@@ -211,14 +211,17 @@ namespace fggl::gfx::ogl4 {
 				}
 
 				// material detection with fallback
-				const auto &material = world.get<PhongMaterial>(entity);
-
-				if (shader->hasUniform("materials[0].ambient")) {
-					shader->setUniformF(shader->uniform("materials[0].emission"), material.emission);
-					shader->setUniformF(shader->uniform("materials[0].ambient"), material.ambient);
-					shader->setUniformF(shader->uniform("materials[0].diffuse"), material.diffuse);
-					shader->setUniformF(shader->uniform("materials[0].specular"), material.specular);
-					shader->setUniformF(shader->uniform("materials[0].shininess"), material.shininess);
+				auto* material = world.tryGet<PhongMaterial>(entity);
+				if ( material == nullptr ) {
+					material = &DEFAULT_MATERIAL;
+				}
+
+				if ( shader->hasUniform("materials[0].ambient") ) {
+					shader->setUniformF(shader->uniform("materials[0].emission"), material->emission);
+					shader->setUniformF(shader->uniform("materials[0].ambient"), material->ambient);
+					shader->setUniformF(shader->uniform("materials[0].diffuse"), material->diffuse);
+					shader->setUniformF(shader->uniform("materials[0].specular"), material->specular);
+					shader->setUniformF(shader->uniform("materials[0].shininess"), material->shininess);
 				}
 
 				if (shader->hasUniform("lightPos")) {
diff --git a/include/fggl/app.hpp b/include/fggl/app.hpp
index 98eab804e7aa6b84f2ecb45d882684ab1673339c..a6c6a90dd3be9991952eb4c9e6779575a0bc1ada 100644
--- a/include/fggl/app.hpp
+++ b/include/fggl/app.hpp
@@ -123,7 +123,7 @@ namespace fggl {
 				try {
 					return m_subsystems->template get<T>();
 				} catch (std::out_of_range &e) {
-					debug::log(debug::Level::error, "Service not found: {}", T::service);
+					debug::log(debug::Level::error, "Service not found: {}", T::service.get());
 					return nullptr;
 				}
 			}
diff --git a/include/fggl/debug/impl/logging_fmt.hpp b/include/fggl/debug/impl/logging_fmt.hpp
index 1c0fddbd36b5f252a7a0c2113c31b8ea34eb190c..71374b479a4cd8ef022a6e38f5725c6a4927efdd 100644
--- a/include/fggl/debug/impl/logging_fmt.hpp
+++ b/include/fggl/debug/impl/logging_fmt.hpp
@@ -20,6 +20,8 @@
 #define FGGL_DEBUG_IMPL_LOGGING_FMT_HPP
 
 #include <fmt/format.h>
+#include <fmt/color.h>
+
 #include <iostream>
 #include <string>
 #include <string_view>
@@ -78,13 +80,13 @@ namespace fggl::debug {
 	template<typename ...T>
 	inline void error(FmtType fmt, T &&...args) {
 		auto fmtStr = fmt::format(fmt::runtime(fmt), args...);
-		fmt::print(CERR_FMT, level_to_string(Level::error), fmtStr);
+		fmt::print(fg(fmt::color::red), CERR_FMT, level_to_string(Level::error), fmtStr);
 	}
 
 	template<typename ...T>
 	inline void warning(FmtType fmt, T &&...args) {
 		auto fmtStr = fmt::format(fmt::runtime(fmt), args...);
-		fmt::print(CERR_FMT, level_to_string(Level::warning), fmtStr);
+		fmt::print(fg(fmt::color::orange), CERR_FMT, level_to_string(Level::warning), fmtStr);
 	}
 
 	template<typename ...T>
@@ -101,8 +103,10 @@ namespace fggl::debug {
 
 	template<typename ...T>
 	inline void trace(FmtType fmt, T &&...args) {
-		auto fmtStr = fmt::format(fmt::runtime(fmt), args...);
-		fmt::print(CERR_FMT, level_to_string(Level::trace), fmtStr);
+		#ifdef FGGL_LOG_TRACE
+			auto fmtStr = fmt::format(fmt::runtime(fmt), args...);
+			fmt::print(CERR_FMT, level_to_string(Level::trace), fmtStr);
+		#endif
 	}
 
 }
diff --git a/include/fggl/debug/logging.hpp b/include/fggl/debug/logging.hpp
index ef4955fc2ed8e70f7eac0b48cbcdb2ee5de0435c..f3ab6bfd565e8bc3fe246f780b111c808c7d0e47 100644
--- a/include/fggl/debug/logging.hpp
+++ b/include/fggl/debug/logging.hpp
@@ -21,8 +21,12 @@
 
 #include <string_view>
 
+
+
 namespace fggl::debug {
 
+	std::string demangle(const char* name);
+
 	using FmtType = const std::string_view;
 	enum class Level;
 
diff --git a/include/fggl/entity/entity.hpp b/include/fggl/entity/entity.hpp
index b4a3d17940b8654622232148f06634952eab5abf..0843299fc79be9dcbf7ba16c72bedebf7b9a6f60 100644
--- a/include/fggl/entity/entity.hpp
+++ b/include/fggl/entity/entity.hpp
@@ -48,7 +48,8 @@ namespace fggl::entity {
 			Component &get(EntityID entity) {
 				#ifndef NDEBUG
 				if (!has<Component>(entity)) {
-					debug::error("Entity {} has no component of type {}", (uint64_t) entity, typeid(Component).name());
+					debug::error("Entity {} has no component of type {}", (uint64_t) entity, debug::demangle(typeid(Component).name()));
+					assert(false && "Entity was missing component - use tryGet or fix definition");
 				}
 				#endif
 				return m_registry.get<Component>(entity);
diff --git a/include/fggl/entity/loader/loader.hpp b/include/fggl/entity/loader/loader.hpp
index cdcc10f50ac8af633af64055c30ec74dcdceb61e..d7d0703d17b95541cbec332b7454f7ffaa4aa307 100644
--- a/include/fggl/entity/loader/loader.hpp
+++ b/include/fggl/entity/loader/loader.hpp
@@ -45,13 +45,16 @@ namespace fggl::entity {
 			constexpr static const modules::ModuleService service = modules::make_service("fggl::entity:Factory");
 
 			EntityID create(const EntityType &spec, EntityManager &manager, const CustomiseFunc &customise = nullptr) {
+				debug::warning("creating {}", spec);
+				assert( m_prototypes.contains(spec) && "asked to create undefined prototype!" );
+
 				try {
 					std::vector<CustomiseFunc> finishers;
 
 					// set up the components for the entity
 					auto entity = setupComponents(spec, manager, finishers);
 					if (entity == entity::INVALID) {
-						debug::error("Error attempting to create entity with type {}", std::to_string(spec.get()));
+						debug::error("EntityFactory: failed to build from prototype {}", std::to_string(spec.get()));
 						return entity::INVALID;
 					}
 
@@ -67,15 +70,18 @@ namespace fggl::entity {
 
 					return entity;
 				} catch (std::out_of_range &ex) {
-					#ifndef NDEBUG
-					debug::log(debug::Level::error,
-							   "EntityFactory: Unknown entity type '{}'",
-							   fggl::util::guidToString(spec));
-					#endif
+					debug::error("EntityFactory: Unknown entity type '{}'", spec);
 					return fggl::entity::INVALID;
 				}
 			}
 
+			void log_known_types() const {
+				debug::debug("dumping known types:");
+				for(auto& [k,v] : m_factories) {
+					debug::debug("\ttype: {}", k);
+				}
+			}
+
 			void define(EntityType type, const EntitySpec &spec) {
 				m_prototypes[type] = spec;
 			}
@@ -97,12 +103,16 @@ namespace fggl::entity {
 			entity::EntityID setupComponents(EntityType entityType,
 											 EntityManager &manager,
 											 std::vector<CustomiseFunc> &finishers) {
+				assert(entityType != NO_PARENT && "setup components called with NO_PARENT?!");
+
 				auto entity = manager.create();
 				std::vector<ComponentID> loadedComps;
 
 				auto currentType = entityType;
 				while (currentType != NO_PARENT) {
 					auto &entitySpec = m_prototypes.at(currentType);
+					debug::debug("constructing {} for {} ({} comps)", currentType, entityType, entitySpec.components.size());
+					assert( entitySpec.ordering.size() == entitySpec.components.size() && "ordering incorrect size, bad things happend!" );
 
 					for (auto &component : entitySpec.ordering) {
 						// skip comps loaded by children
@@ -121,11 +131,8 @@ namespace fggl::entity {
 								finishers.push_back(info.finalise);
 							}
 						} catch (std::out_of_range &ex) {
-							#ifndef NDEBUG
-							debug::log(debug::Level::error,
-									   "EntityFactory: Unknown component factory type '{}'",
-									   fggl::util::guidToString(component));
-							#endif
+							debug::error( "EntityFactory: Unknown component factory type '{}'", component );
+							log_known_types();
 							manager.destroy(entity);
 							return entity::INVALID;
 						}
diff --git a/include/fggl/entity/loader/spec.hpp b/include/fggl/entity/loader/spec.hpp
index e78ccfeac3785ab187b96af5d8f45f3f3df9997c..749fa4cc2585ea3ad5e676613dc14f455912098c 100644
--- a/include/fggl/entity/loader/spec.hpp
+++ b/include/fggl/entity/loader/spec.hpp
@@ -53,6 +53,11 @@ namespace fggl::entity {
 		EntityType parent = NO_PARENT;
 		std::vector<ComponentID> ordering;
 		std::map<ComponentID, ComponentSpec> components;
+
+		inline void addComp(ComponentID cmp, const ComponentSpec& spec) {
+			components[cmp] = spec;
+			ordering.push_back(cmp);
+		}
 	};
 
 } // namespace fggl::entity
diff --git a/include/fggl/gfx/ogl4/models.hpp b/include/fggl/gfx/ogl4/models.hpp
index ec12ed03746c526df8a903fa640756c069c888b7..9f3175a26c02b829990ca7ce9aa426394d3a5ace 100644
--- a/include/fggl/gfx/ogl4/models.hpp
+++ b/include/fggl/gfx/ogl4/models.hpp
@@ -49,7 +49,7 @@ namespace fggl::gfx::ogl4 {
 		public:
 			inline StaticModelRenderer(gfx::ShaderCache *cache)
 				: m_shaders(cache), m_phong(nullptr), m_vao(), m_vertexList(), m_indexList() {
-				m_phong = std::make_shared<ogl::Shader>(cache->get("phong"));
+				m_phong = std::make_shared<ogl::Shader>(cache->get("redbook/debug"));
 			}
 
 			~StaticModelRenderer() = default;
diff --git a/include/fggl/modules/manager.hpp b/include/fggl/modules/manager.hpp
index 791d2f003dcd813197e4e2b83261827b0b8883a8..deb5f14a418d766437781137b42471a1227e8948 100644
--- a/include/fggl/modules/manager.hpp
+++ b/include/fggl/modules/manager.hpp
@@ -185,7 +185,7 @@ namespace fggl::modules {
 							debug::log(debug::Level::warning,
 									   "{} depends on {}, but nothing provides it",
 									   moduleItr.first,
-									   service);
+									   service.get());
 							// nothing can provide the service requested, setup is invalid.
 							return false;
 						}
@@ -222,7 +222,7 @@ namespace fggl::modules {
 								debug::log(debug::Level::warning,
 										   "{} could not create service {}",
 										   nextToInit,
-										   service);
+										   service.get());
 							}
 						}
 					} else {
diff --git a/include/fggl/util/guid.hpp b/include/fggl/util/guid.hpp
index 99902435ef2390f2a44cb5032c3777ab9149fc1a..2b6556058c44e592518bd5d45a96fa317c9ce20a 100644
--- a/include/fggl/util/guid.hpp
+++ b/include/fggl/util/guid.hpp
@@ -24,6 +24,7 @@
 #include <cassert>
 
 #include "fggl/util/safety.hpp"
+#include "fggl/debug/logging.hpp"
 
 namespace fggl::util {
 
@@ -73,7 +74,7 @@ namespace fggl::util {
 	#endif
 
 	constexpr GUID make_guid(const char *str) {
-		return GUID::make(hash_fnv1a_64(str));
+		return GUID(hash_fnv1a_64(str));
 	}
 
 	inline GUID make_guid_rt(const std::string &str) {
@@ -86,6 +87,24 @@ namespace fggl::util {
 
 } // namespace fggl::util
 
+// formatter
+template<> struct fmt::formatter<fggl::util::GUID> {
+	constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
+		auto it = ctx.begin(), end = ctx.end();
+		return it;
+	}
+
+	template <typename FormatContext>
+	auto format(const fggl::util::GUID& guid, FormatContext& ctx) const -> decltype(ctx.out()) {
+		#ifndef NDEBUG
+		return fmt::format_to(ctx.out(), "GUID[{}]", guidToString(guid));
+		#else
+		return fmt::format_to(ctx.out(), "GUID[{}]", guid.get());
+		#endif
+	}
+};
+
+
 fggl::util::GUID operator "" _fid(const char *str);
 fggl::util::GUID operator "" _fid(const char *str, std::size_t);
 
diff --git a/include/fggl/util/safety.hpp b/include/fggl/util/safety.hpp
index cd5719aff6ddbd426483d35fbc84118e264314f0..55cfa036a2f4b577fe07cf38da45bad01eac5fa8 100644
--- a/include/fggl/util/safety.hpp
+++ b/include/fggl/util/safety.hpp
@@ -47,8 +47,6 @@ namespace fggl::util {
 				return m_value;
 			}
 
-			constexpr explicit operator std::string_view() const { return m_value; }
-
 			/**
 			 * Check for equality of two handles.
 			 *