diff --git a/common/sketchbook.hpp b/common/sketchbook.hpp
index 20f381f78351b2567959114c3b5a1b3b66cfc871..4adb4a409fb67873249f5f025fa526e66bdbca55 100644
--- a/common/sketchbook.hpp
+++ b/common/sketchbook.hpp
@@ -58,15 +58,26 @@ auto trand_float2()
 { return float2(trand_float(), trand_float()); };
 
 template <typename Number, typename Ratio = float>
+constexpr
 Number lerp(Number from, Number to, Ratio ratio)
 {
 	return from + (to - from) * ratio;
 }
 
+template <size_t FPS>
+class framerate
+{
+	public:
+	constexpr static auto frames_per_second = FPS;
+	// thanks howard hinnant, everything other than this amazing duration type caused a lot of stutter
+	using tick = std::chrono::duration<std::uintmax_t, std::ratio<1, FPS>>;
+	constexpr static auto frametime = tick(1);
+};
+
 class Program
 {
 	public:
-	using clock = std::chrono::high_resolution_clock;
+	using clock = std::chrono::steady_clock;
 	using duration = std::chrono::duration<float>;
 
 	private:
@@ -132,8 +143,8 @@ int main(int argc, char const* argv[]) try
 
 	if(!vsync && !program.frametime)
 	{
-		program.frametime = 16ms;
 		std::cout << "vsync didn't work"  << '\n';
+		program.frametime = framerate<60>::frametime;
 	}
 	float2 win_size = float2(win.size());
 
@@ -213,6 +224,10 @@ void process_events(Program& program)
 		{
 			program.mouse_move(float2(e.data.position), float2(e.data.motion));
 		},
+		[&program](const quit_request&)
+		{
+			program.end();
+		},
 		[](auto) { }
 	}, *event);
 }
diff --git a/drag_and_wrap.cpp b/drag_and_wrap.cpp
index a9904b31019eae5ec6743d91f4a974f7ed38a549..e7ab349e6465cffb0489106eea6cf9e53d91623b 100644
--- a/drag_and_wrap.cpp
+++ b/drag_and_wrap.cpp
@@ -63,6 +63,7 @@ circle* crc = nullptr;
 
 void start(Program& program)
 {
+	program.frametime = framerate<60>::frametime;
 
 	if(program.argc > 2)
 	{
@@ -70,7 +71,6 @@ void start(Program& program)
 		using seed_t = decltype(tiny_rand());
 		tiny_rand.seed({ ston<seed_t>(program.argv[1]), ston<seed_t>(program.argv[2]) });
 	}
-	program.frametime = 16'666'666ns;
 
 	std::cout << "seed: " << std::hex << std::showbase << tiny_rand << '\n';
 
diff --git a/starry_night_sky.cpp b/starry_night_sky.cpp
index cc524f5433dd1b3aa88bdbe4fb9ae62fc4815382..aef11f72ee3dc8ac6f4463abbb5a7282218c2eca 100644
--- a/starry_night_sky.cpp
+++ b/starry_night_sky.cpp
@@ -17,7 +17,7 @@ rgb skyColorFrom (rgb24(0_u8, 0_u8, 51_u8)),
 bool request_draw = false;
 void start(Program& program)
 {
-	program.frametime = 16ms;
+	program.frametime = framerate<60>::frametime;
 
 	if(program.argc > 2)
 	{