diff --git a/src/core/include/pw/core/math.hpp b/src/core/include/pw/core/math.hpp
index b8fc16e..16afc9d 100644
--- a/src/core/include/pw/core/math.hpp
+++ b/src/core/include/pw/core/math.hpp
@@ -29,32 +29,30 @@
 namespace pw {
 
 const static double __PW_PI = 3.1415926535897932384626433832795028841971693993751058209;
-const static double __RAD2DEG = 180.0 / __PW_PI;
-const static double __DEG2RAD = __PW_PI / 180.0;
-
 
 template <typename T>
 inline const T pi() { return static_cast<T>(__PW_PI); }
 
+template <typename T>
+inline const T one_over_pi() { return static_cast<T>(1 / __PW_PI); }
+
 template <typename T>
 inline T rad_to_deg(const T& angle_in_radian) {
-	return angle_in_radian * __RAD2DEG;
+	return angle_in_radian * static_cast<T>(180) * one_over_pi<T>();
 }
 
 template <typename T>
 inline T deg_to_rad(const T& angle_in_degree) {
-	return angle_in_degree * __DEG2RAD;
+	return angle_in_degree * pi<T>() / static_cast<T>(180);
 }
 
 template <typename T>
-static inline
-T repeat(const T& t, const T& length) {
+inline T repeat(const T& t, const T& length) {
 	return std::clamp(t - std::floor(t / length) * length, T(0), length);
 }
 
 template <typename T>
-static inline
-T ping_pong(const T& t,const T& length) {
+inline T ping_pong(const T& t,const T& length) {
 	auto tn = repeat(t, length * T(2));
 	return length - std::abs(tn - length);
 }
diff --git a/src/visual/include/pw/visual/shader.hpp b/src/visual/include/pw/visual/shader.hpp
index 207834a..517d9a0 100644
--- a/src/visual/include/pw/visual/shader.hpp
+++ b/src/visual/include/pw/visual/shader.hpp
@@ -7,6 +7,7 @@
 #include <pw/core/debug.hpp>
 
 #include <map>
+#include <variant>
 
 namespace pw {
 
@@ -26,8 +27,6 @@ public:
     void set_source(const std::string& c,code_type t) { _source[t] = c; }
 	std::string source(code_type t) { return _source[t]; }
 
-//	void set_attributes(const std::vector<std::string> > &attributes);
-
 	bool ready() const;
 
 	shader& set(int location,float v);
@@ -51,6 +50,12 @@ public:
 
     void use();
 
+	using uniform_t = std::variant<bool,int,float,double,vector2f,vector3f,vector4f,matrix4x4f>;
+
+	using uniform_set = std::map<std::string,uniform_t>;
+
+	void set_uniforms(uniform_set s);
+
 protected:
 
 	std::map<code_type,std::string> _source;
diff --git a/src/visual/src/pipeline.cpp b/src/visual/src/pipeline.cpp
index 3d6956c..7dbd2e6 100644
--- a/src/visual/src/pipeline.cpp
+++ b/src/visual/src/pipeline.cpp
@@ -97,7 +97,6 @@ struct triangle_renderer
 
     void draw()
     {
-		double t0 = timer::now();
 
         shader_p.use();
 
@@ -112,27 +111,30 @@ struct triangle_renderer
 		axisangle rot(vector3::forward(),v_angle);
         model_mat = rot.to_matrix();
 
-
 		matrix4x4f view_mat = transform_tools<float>::look_at(vector3({0,0,0}),
 															  vector3::forward(),
 															  vector3::up());
 
-		matrix4x4f proj_mat = transform_tools<float>::perspective_projection(deg_to_rad(45.f),
+		matrix4x4f proj_mat = transform_tools<float>::perspective_projection(deg_to_rad(60.0f),
 																			 1.3f,
 																			 0.2f,1000.f);
 
-//		debug::d() << serialize::matrix(proj_mat);
-
-
         // highly inefficient - should be cached -
 		shader_p.set("input_color",col);
 		shader_p.set("model",model_mat);
 		shader_p.set("view",view_mat);
 		shader_p.set("projection",proj_mat);
 
+		// new version with ...
+
+		shader::uniform_set us;
+		us["input_color"] = col;
+
+		shader_p.set_uniforms(us);
+
 		amesh_renderer.draw();
 
-		debug::d() << 100 * (timer::now() - t0) << "ms";
+//		debug::d() << 100 * (timer::now() - t0) << "ms";
 
     }
 };
diff --git a/src/visual/src/shader.cpp b/src/visual/src/shader.cpp
index a2f9ac0..2453f23 100644
--- a/src/visual/src/shader.cpp
+++ b/src/visual/src/shader.cpp
@@ -197,7 +197,18 @@ bool shader::build()
 
 void shader::use()
 {
-    _impl->use();
+	_impl->use();
+}
+
+void shader::set_uniforms(shader::uniform_set s)
+{
+	for (auto& u : s) {
+		std::visit(
+					[u](auto&& arg){
+						std::cout << u.first << " " << typeid(arg).name() << std::endl;
+					},
+			u.second);
+	}
 }
 
 int shader::uniform_location(const std::string &name) const