diff --git a/circular_maze.cpp b/circular_maze.cpp
index 14304155656b3f0713f25c37d7f2e4cad0793752..a08b886b4e9784c8bb2deac0e5cbe61da0db7512 100644
--- a/circular_maze.cpp
+++ b/circular_maze.cpp
@@ -84,14 +84,14 @@ class circular_maze
 	range2f bounds;
 
 	float corridor_radius;
-	float wall_wdith;
+	float wall_width;
 	float initial_radius;
 
 	float2 center;
 
-	using float_NxN = std::vector<std::vector<float>>;
-	float_NxN walls;
-	float_NxN paths;
+	using float_NxM = std::vector<std::vector<float>>;
+	float_NxM walls;
+	float_NxM paths;
 
 
 	std::optional<float> closest_wall(int level, float angle)
@@ -137,6 +137,7 @@ class circular_maze
 	public:
 	float current_angle = 0;
 	float player_level = -1;
+	auto get_corridor_radius() const {return corridor_radius;}
 
 	circular_maze(float2 screen_size) :
 		layers(7),
@@ -145,7 +146,7 @@ class circular_maze
 		fov_range{-fov/2,+fov/2},
 		bounds{fit(screen_size,{cord_length(fov),1.f})},
 		corridor_radius( size(bounds).y() / (layers+2) ),
-		wall_wdith(corridor_radius/6),
+		wall_width(corridor_radius/6),
 		initial_radius(corridor_radius * 2),
 		center{bounds.lower()+(bounds.upper() - bounds.lower()) * float2{0.5f,1.f}}
 	{
@@ -185,7 +186,7 @@ class circular_maze
 
 	const float2& screen_size() { return _screen_size; }
 
-	std::optional<float> hit_test(float angle, float level, const float_NxN& elements)
+	std::optional<float> hit_test(float angle, float level, const float_NxM& elements)
 	{
 		if(level < 0 || level >= layers)
 			return std::nullopt;
@@ -206,24 +207,31 @@ class circular_maze
 		return hit_test(angle, player_level, walls);
 	}
 
-	std::optional<float> path_hit_test_up(float angle)
+	std::optional<float> path_hit_test(float angle, float level, float direction)
 	{
-		return hit_test(angle, player_level + 1, paths);
+		return hit_test(angle, level + (direction+1)/2, paths);
 	}
 
-	std::optional<float> path_hit_test_up(float angle, float level)
+	void circular_move(float velocity)
 	{
-		return hit_test(angle, level + 1, paths);
-	}
-
-	std::optional<float> path_hit_test_down(float angle)
-	{
-		return hit_test(angle, player_level, paths);
-	}
-
-	std::optional<float> path_hit_test_down(float angle, float level)
-	{
-		return hit_test(angle, level, paths);
+		const auto radius = player_level * corridor_radius + initial_radius;
+		const auto corridor_angle = corridor_radius/tau/radius;
+		const auto max_angular_velocity = corridor_angle*0.8;
+		float angular_velocity = velocity/tau/radius;
+		if(abs(angular_velocity) > max_angular_velocity)
+			angular_velocity = std::copysign(max_angular_velocity, angular_velocity);
+
+		auto new_angle = wrap(current_angle + angular_velocity, 1.f);
+		auto hit_wall = wall_hit_test(new_angle);
+		if(!hit_wall)
+		{
+			current_angle = new_angle;
+		}
+		else
+		{
+			const auto offset = std::copysign(corridor_angle*0.51f, mod_difference(current_angle + *hit_wall, 3.f/4, 1.f));
+			current_angle = wrap(3.f/4 - *hit_wall - offset, 1.f);
+		}
 	}
 
 	void draw(vg::frame& frame)
@@ -233,7 +241,7 @@ class circular_maze
 			.fill(0x1d4151_rgb)
 		;
 
-		auto fov_range_up = fov_range - 1.f/4;
+		const auto fov_range_up = fov_range - 1.f/4;
 
 
 		{auto sketch = frame.begin_sketch();
@@ -243,12 +251,12 @@ class circular_maze
 				sketch.arc(center, fov_range_up * tau, radius - corridor_radius/2);
 				radius += corridor_radius;
 			}
-			sketch.line_width(wall_wdith).outline(0xfbfbf9_rgb);
+			sketch.line_width(wall_width).outline(0xfbfbf9_rgb);
 		}
 
 		{auto sketch = frame.begin_sketch();
 		float radius = initial_radius - corridor_radius/2;
-		for(size_t level = 0; level < paths.size(); ++level)
+		for(size_t level = 0; level < paths.size(); ++level, radius += corridor_radius)
 		{
 			float path_arc_angle = (corridor_radius * 0.8)/tau/radius;
 			auto path_arc_range = range{-path_arc_angle, path_arc_angle}/2;
@@ -260,41 +268,58 @@ class circular_maze
 				if(!(fov_range_up + 1.f).intersects(path_arc_range + path_angle))
 					continue;
 
-				// TODO: approximate arc with a polygin so that we don't need to convert to radians,
+				// TODO: approximate arc with a polygon so that we don't need to convert to radians,
 				// here and everywhere
 				sketch.arc(center, (path_arc_range + path_angle) * tau, radius);
 			}
-			radius += corridor_radius;
-		} sketch.line_width(wall_wdith + 3).outline(0x1d4151_rgb); }
+		} sketch.line_width(wall_width + 3).outline(0x1d4151_rgb); }
 
-		{auto sketch = frame.begin_sketch();
-		for(size_t level = 0; level < walls.size(); ++level)
+		float radius = initial_radius - corridor_radius/2;
+		for(size_t level = 0; level < walls.size(); ++level, radius += corridor_radius)
 		{
+			const float wall_arc_angle = wall_width/tau/radius;
+			const auto wall_arc_range = range{-wall_arc_angle, wall_arc_angle}/2;
 			for(size_t angle = 0; angle < walls[level].size(); ++angle)
 			{
 				const auto wall_angle = wrap(
 					walls[level][angle] + current_angle,
 				1.f);
-				if(!(fov_range_up + 1.f).contains(wall_angle))
+				const auto intersection = (fov_range_up + 1.f).intersection(wall_arc_range + wall_angle);
+				if(!intersection.valid())
 					continue;
-				sketch.line(
-					center + rotate(
-						float2::i(initial_radius + corridor_radius*(float(level)-0.5f)),
-						wall_angle
-					),
-					center + rotate(
-						float2::i(initial_radius + corridor_radius*(float(level)+0.5f)),
-						wall_angle
+
+				const auto visible_wall_angle = intersection.upper() - intersection.lower();
+				const auto visible_wall_width = wall_width * visible_wall_angle/wall_arc_angle;
+				const auto wall_anchor = intersection.lower() == (fov_range_up + 1.f).lower() ? .5f : -.5f;
+
+				// TODO: welp, looks like even here, polygon would be better, to render different widths with one draw call
+				frame.begin_sketch()
+					.line(
+						center + rotate(
+							float2::i(initial_radius + corridor_radius*(float(level)-0.5f)),
+							wall_angle + wall_anchor * (wall_arc_angle - visible_wall_angle)
+						),
+						center + rotate(
+							float2::i(initial_radius + corridor_radius*(float(level)+0.5f)),
+							wall_angle + wall_anchor * (wall_arc_angle - visible_wall_angle)
+						)
 					)
-				);
+					.line_width(visible_wall_width).outline(0xfbfbf9_rgb);
 			}
-		} sketch.line_width(wall_wdith).outline(0xfbfbf9_rgb); }
+		}
 
+		const auto player_diameter =
+			corridor_radius - wall_width -3;
+		const auto player_center =
+			center - float2::j(player_level * corridor_radius + initial_radius);
 		frame.begin_sketch().ellipse(rect{
-			float2::one(corridor_radius - wall_wdith -3),
-			center - float2::j(player_level * corridor_radius + initial_radius),
+			float2::one(player_diameter),
+			player_center,
 			half
-		}).fill(0x00feed_rgb);
+		}).fill(paint::radial_gradient(
+			player_center,
+			{player_diameter/2 * .3f, player_diameter/2},
+			{rgba_vector(0x00feed'ff_rgba), rgba_vector(0x00000000_rgba)}));
 	};
 
 	void diagram(vg::frame& frame)
@@ -375,39 +400,43 @@ struct radial_movement
 	float level = 0;
 };
 std::queue<radial_movement> radial_movements;
+void make_radial_movement(float direction)
+{
+	auto level = !empty(radial_movements) ? radial_movements.back().level : maze.player_level;
+	auto angle = !empty(radial_movements)
+	? wrap(3/4.f - radial_movements.back().path, 1.f)
+	: maze.current_angle;
+	auto path = maze.path_hit_test(angle, level, direction);
+	if(path)
+		radial_movements.push({*path, level + direction});
+}
 
 bool diagram = false;
+std::optional<float2> drag = std::nullopt;
+std::optional<float2> jerk = std::nullopt;
+float circular_velocity = 0.f;
 
 void start(Program& program)
 {
-	program.size = int2(maze.screen_size());
+	program.fullscreen = true;
+
+	program.draw_once = [](auto frame)
+	{
+		maze = circular_maze(frame.size);
+	};
 
 	program.key_down = [](scancode code, keycode)
 	{
 		switch(code)
 		{
 			case scancode::j:
-			{
-				auto level = !empty(radial_movements) ? radial_movements.back().level : maze.player_level;
-				auto angle = !empty(radial_movements)
-					? wrap(3/4.f - radial_movements.back().path, 1.f)
-					: maze.current_angle;
-				auto path = maze.path_hit_test_down(angle, level);
-				if(path)
-					radial_movements.push({*path, level - 1});
-			}
+			case scancode::down:
+				make_radial_movement(-1);
 			break;
 
 			case scancode::k:
-			{
-				auto level = !empty(radial_movements) ? radial_movements.back().level : maze.player_level;
-				auto angle = !empty(radial_movements)
-					? wrap(3/4.f - radial_movements.back().path, 1.f)
-					: maze.current_angle;
-				auto path = maze.path_hit_test_up(angle, level);
-				if(path)
-					radial_movements.push({*path, level + 1});
-			}
+			case scancode::up:
+				make_radial_movement(+1);
 			break;
 
 			case scancode::d:
@@ -418,17 +447,33 @@ void start(Program& program)
 		}
 	};
 
-	// program.mouse_down = [](float2 position, auto)
-	// {
-	// };
-    //
-	// program.mouse_up = [](auto, auto)
-	// {
-	// };
-    //
-	// program.mouse_move = [](auto, float2 motion)
-	// {
-	// };
+	program.mouse_down = [](float2, auto)
+	{
+		drag = float2::zero();
+		circular_velocity = 0;
+	};
+
+	program.mouse_up = [](auto, auto)
+	{
+		drag = std::nullopt;
+		jerk = std::nullopt;
+	};
+
+	program.mouse_move = [](auto, float2 motion)
+	{
+		if(drag)
+		{
+			*drag += motion;
+
+			if(!jerk)
+			{
+				// TODO: use mouse_motion::window_normalized_motion
+				auto possible_jerk = trunc(motion / (maze.get_corridor_radius()/3));
+				if(possible_jerk != float2::zero())
+					jerk = signum(possible_jerk);
+			}
+		}
+	};
 
 	program.draw_loop = [](auto frame, auto delta)
 	{
@@ -469,18 +514,35 @@ void start(Program& program)
 				);
 			}
 
-			if(pressed(scancode::h))
+			if(pressed(scancode::h) || pressed(scancode::left))
 			{
-				auto new_angle = wrap(maze.current_angle + 0.001f, 1.f);
-				if(!maze.wall_hit_test(new_angle))
-					maze.current_angle = new_angle;
+				maze.circular_move(1);
+				circular_velocity = 1;
 			}
 
-			if(pressed(scancode::l))
+			if(pressed(scancode::l) || pressed(scancode::right))
+			{
+				maze.circular_move(-1);
+				circular_velocity = -1;
+			}
+
+			if(drag)
+			{
+				circular_velocity = drag->x();
+				maze.circular_move(drag->x()/5);
+
+				if(jerk && (*jerk * float2::j() != float2::zero()))
+				{
+					make_radial_movement(-jerk->y());
+					jerk = float2::zero(); // prevents further jerks on this drag TODO: should probably add some kind of a timer on this, to eventually reset back to nullopt
+				}
+
+				drag = float2::zero();
+			}
+			else
 			{
-				auto new_angle = wrap(maze.current_angle - 0.001f, 1.f);
-				if(!maze.wall_hit_test(new_angle))
-					maze.current_angle = new_angle;
+				circular_velocity *= 0.8f;
+				maze.circular_move(circular_velocity);
 			}
 		}