diff --git a/src/core/include/pw/core/debug.hpp b/src/core/include/pw/core/debug.hpp
index 601770b..d20ec0f 100644
--- a/src/core/include/pw/core/debug.hpp
+++ b/src/core/include/pw/core/debug.hpp
@@ -75,6 +75,7 @@ public:
 
         stream& operator << (const void *value);			///! pointer
 
+
     protected:
 
         debug* _log;
diff --git a/src/core/include/pw/core/matrix.hpp b/src/core/include/pw/core/matrix.hpp
index 2a489ed..03e9685 100644
--- a/src/core/include/pw/core/matrix.hpp
+++ b/src/core/include/pw/core/matrix.hpp
@@ -70,9 +70,6 @@ struct matrix_ : matrixbase_<T, matrix_<R, C, T>>
 		return *this;
 	}
 
-//	//! get cell count
-//	inline std::size_t coefficients() const { return this->size(); }
-
 	inline size_t offset(size_t r,size_t c) const {
 		return (RowMajor) ? r * C + c : c * R + r;
 	}
@@ -85,7 +82,7 @@ struct matrix_ : matrixbase_<T, matrix_<R, C, T>>
 		return data[offset(r,c)];
 	}
 
-	inline const T* ptr() const { return &data[0]; }
+    inline const T *ptr() const { return &data[0]; }
 
 	//! set identity
 	inline matrix_& set_identity()
@@ -201,6 +198,14 @@ struct matrix_ : matrixbase_<T, matrix_<R, C, T>>
         for (size_t i = 0; i < rows; i++) c[i] = (*this)(i,col_);
         return c;
     }
+
+    static constexpr auto identity() {
+        matrix_ res;
+        for (std::size_t r = 0;r < rows; r++)
+            for (std::size_t c = 0; c < cols; c++)
+                res(r,c) = (c == r) ? T(1) : T(0);
+        return res;
+    }
 };
 
 template <> inline
diff --git a/src/core/include/pw/core/matrixbase.hpp b/src/core/include/pw/core/matrixbase.hpp
index 39d245b..b2b46cb 100644
--- a/src/core/include/pw/core/matrixbase.hpp
+++ b/src/core/include/pw/core/matrixbase.hpp
@@ -39,7 +39,7 @@ namespace pw {
 template <typename T, typename Derived>
 struct matrixbase_ {
 
-	typedef T value_type;
+    using value_type = T;
 
 	Derived& derived() { return static_cast<Derived&>(*this); }
     const Derived& derived() const { return static_cast<const Derived&>(*this); }
diff --git a/src/scene/include/pw/scene/components/relationship.hpp b/src/scene/include/pw/scene/components/relationship.hpp
index 7b23dcc..b00da04 100644
--- a/src/scene/include/pw/scene/components/relationship.hpp
+++ b/src/scene/include/pw/scene/components/relationship.hpp
@@ -33,12 +33,20 @@ namespace pw {
 /**
  * @brief entity relations are hidden and managed by the entity itself
  */
-struct relationship {
-    relationship() = default;
-    relationship(const relationship&) = default;
+struct parent {
+    parent() = default;
+    parent(const parent&) = default;
 
-    std::vector<entt::entity> children;
-    entt::entity parent { entt::null };
+    entt::entity entity { entt::null };
+
+    operator bool() const { return entity != entt::null; }
+};
+
+struct children {
+    children() = default;
+    children(const children&) = default;
+
+    std::vector<entt::entity> entities;
 };
 
 
diff --git a/src/scene/include/pw/scene/components/transform.hpp b/src/scene/include/pw/scene/components/transform.hpp
index 64c5b3e..4ec5a02 100644
--- a/src/scene/include/pw/scene/components/transform.hpp
+++ b/src/scene/include/pw/scene/components/transform.hpp
@@ -9,58 +9,52 @@ namespace pw {
 
 struct transform {
 
+    transform() = default;
+    transform(const transform&) = default;
+
 	inline const matrix4x4& local() const { return _local; }
     void set_local(const matrix4x4 &local)
     {
         _local = local;
-        update_global_from_local();
-        // TODO need to rebuild the transforms: both -> global down and global up
     }
 
 	inline const matrix4x4& global() const { return _global; }
+
     void set_global(const matrix4x4 &global)
     {
+        matrix4x4 diff = _global.inverse() * global;
+        _local = _local * diff;
+
         _global = global;
-        _global_inverse = global.inverse();
-
-        update_local_from_global();
     }
 
-	inline const matrix4x4& global_inverse() const { return _global_inverse; }
-
 	inline transform& translate(const real_t &x, const real_t &y, const real_t &z) {
         _local(0,3) += x;_local(1,3) += y;_local(2,3) += z;
-		update_global_from_local();
 		return *this;
 	}
 
 	inline transform& set_translation(const real_t &x, const real_t &y, const real_t &z) {
 		_local(0,3) = x;_local(1,3) = y;_local(2,3) = z;
-		update_global_from_local();
 		return *this;
 	}
 
 	inline transform& rotate(const quaternion& q) {
         _local = _local * q.to_matrix();
-		update_global_from_local();
 		return *this;
 	}
 
 	inline transform& set_rotation(const quaternion& q) {
 		_local = q.to_matrix();
-		update_global_from_local();
 		return *this;
 	}
 
 	inline transform& scale(const real_t &sx, const real_t &sy, const real_t &sz) {
 		_local(0,0) *= sx; _local(1,1) *= sy; _local(2,2) *= sz;
-		update_global_from_local();
 		return *this;
 	}
 
 	inline transform& set_scale(const real_t &sx, const real_t &sy, const real_t &sz) {
 		_local(0,0) = sx; _local(1,1) = sy; _local(2,2) = sz;
-		update_global_from_local();
 		return *this;
 	}
 
@@ -68,14 +62,8 @@ struct transform {
 		return scale(uniform_scale,uniform_scale,uniform_scale);
 	}
 
-	matrix4x4 _local;
-	matrix4x4 _global;
-
-	matrix4x4 _global_inverse;
-
-	void update_global_from_local();
-
-	void update_local_from_global();
+    matrix4x4 _local = matrix4x4::identity();
+    matrix4x4 _global = matrix4x4::identity();
 };
 
 }
diff --git a/src/scene/include/pw/scene/scene.hpp b/src/scene/include/pw/scene/scene.hpp
index 722d8dd..50fa22c 100644
--- a/src/scene/include/pw/scene/scene.hpp
+++ b/src/scene/include/pw/scene/scene.hpp
@@ -28,6 +28,7 @@
 #include <pw/core/globals.hpp>
 #include <entt/entt.hpp>
 
+
 namespace pw {
 
 class entity;
diff --git a/src/scene/src/entity.cpp b/src/scene/src/entity.cpp
index a665978..5a914ae 100644
--- a/src/scene/src/entity.cpp
+++ b/src/scene/src/entity.cpp
@@ -43,12 +43,12 @@ bool entity::add_child(entity &child)
     // TODO: check circular dependencies
 
     // declare child relationship
-    auto& r = get_or_create_component<relationship>();
-    r.children.push_back(child._entity);
+    auto& c = this->get_or_create_component<children>();
+    c.entities.push_back(child._entity);
 
     // declare parent
-    auto& p_r = child.get_or_create_component<relationship>();
-    p_r.parent = _entity;
+    auto& p_r = child.get_or_create_component<parent>();
+    p_r.entity = _entity;
 
     return true;
 }
@@ -62,19 +62,19 @@ bool entity::remove_child(entity& child)
     }
 
     // both need to have a relationship component
-    if (has_component<relationship>() &&
-            child.has_component<relationship>())
+    if (child.has_component<parent>() &&
+            this->has_component<children>())
     {
         // we need to check if the child is related to the parent
-        auto r_p = child.get_component<relationship>();
-        if (r_p.parent == _entity)
+        auto r_p = child.get_component<parent>();
+        if (r_p.entity == _entity)
         {
             // now go ahead delete parent
-            r_p.parent = entt::null;
+            r_p.entity = entt::null;
 
             // now remove all children
-            auto& r = this->get_component<relationship>();
-            r.children.erase(std::remove(r.children.begin(),r.children.end(),child._entity));
+            auto& c = this->get_component<children>();
+            c.entities.erase(std::remove(c.entities.begin(),c.entities.end(),child._entity));
 
             // flag success
             return true;
@@ -83,10 +83,11 @@ bool entity::remove_child(entity& child)
     return false;
 }
 
+
 size_t entity::child_count() const
 {
-    return has_component<relationship>() ?
-                get_component<relationship>().children.size() :
+    return this->has_component<children>() ?
+                get_component<children>().entities.size() :
                 0;
 }
 
diff --git a/src/scene/src/scene.cpp b/src/scene/src/scene.cpp
index 8f5a1ee..498b4ee 100644
--- a/src/scene/src/scene.cpp
+++ b/src/scene/src/scene.cpp
@@ -2,6 +2,7 @@
 #include "pw/scene/entity.hpp"
 
 #include "pw/core/debug.hpp"
+#include "pw/core/serialize.hpp"
 
 namespace pw {
 
@@ -23,35 +24,67 @@ size_t scene::count_alive_enties() const
 void scene::update_transforms()
 {
 
-#if 0
+#if 1
 
-    auto view = _registry->view<transform,relationship>();
+    // search for nodes with parent and transform (only find leaf nodes)
+    auto view = _registry->view<transform,parent>(entt::exclude<children>);
 
     for (auto entity : view)
     {
-        auto [t,r] = view.get<transform,relationship>(entity);
+        debug::d() << "info for entity " << (int)entity;
 
-    }
+        //auto [t,r] = view.get<transform,parent>(entity);
 
-        #endif
+                // collect node path
+        std::vector<transform> path;
+        while (_registry->has<parent>(entity)) {
 
+            if (_registry->has<transform>(entity)) {
+                path.push_back(_registry->get<transform>(entity));
+            }
 
-
-    auto view = _registry->view<relationship>();
-
-    for (auto e : view) {
-
-        const auto& r = view.get<relationship>(e);
-
-        if (r.children.size() && r.parent == entt::null) {
-            debug::d() << "root";
+            entity = _registry->get<parent>(entity).entity;
         }
 
-//        debug::d() << __PRETTY_FUNCTION__ << " " << view.get<relationship>(e).children.size();
 
-//        if
+        debug::d() << "\tpath length " << path.size();
+
+        std::reverse(path.begin(),path.end());
+
+        auto m = pw::matrix4x4::identity();
+
+        for (auto& transform : path) {
+            transform._global = transform._local * m;
+            m = transform._global;
+
+            debug::d() << pw::serialize::matrix(m);
+        }
+
+
+
+//        r = _registry->view<relationship>
+
     }
 
+
+#else
+
+//    auto view = _registry->view<relationship>();
+
+//    for (auto e : view) {
+
+//        const auto& r = view.get<relationship>(e);
+
+//        if (r.children.size() && r.parent == entt::null) {
+//            debug::d() << "root '" << (int)e << "'";
+//        }
+
+////        debug::d() << __PRETTY_FUNCTION__ << " " << view.get<relationship>(e).children.size();
+
+////        if
+//    }
+#endif
+
 //    auto vr = _registry->view<relationship>();
 
 //    for (auto [rel] : vr) {
diff --git a/src/scene/tests/pwscene_test_scene.cpp b/src/scene/tests/pwscene_test_scene.cpp
index fa55ab6..7b3e426 100644
--- a/src/scene/tests/pwscene_test_scene.cpp
+++ b/src/scene/tests/pwscene_test_scene.cpp
@@ -43,6 +43,12 @@ void test_stack()
     e2.add_component<pw::transform>();
     e3.add_component<pw::transform>();
 
+    auto e22 = entity{s};
+    e22.add_component<pw::transform>().set_scale(.5,.5,.5);
+    e2.add_child(e22);
+
+    e2.get_component<pw::transform>().set_translation(10,20,40);
+
     std::cout << e.child_count() << std::endl;
 
     s.update_transforms();
diff --git a/src/visual/src/texture.cpp b/src/visual/src/texture.cpp
index 8c2982a..a184c44 100644
--- a/src/visual/src/texture.cpp
+++ b/src/visual/src/texture.cpp
@@ -26,6 +26,10 @@ struct texture::impl {
 		case data_layout::shape_3d:
 			return GL_TEXTURE_3D;
 		}
+
+        debug::e() << __PRETTY_FUNCTION__ << " unknown texture layout";
+
+        return 0;
 	}
 
 	void create()