diff --git a/Makefile b/Makefile
index 8c3aae1..52312da 100644
--- a/Makefile
+++ b/Makefile
@@ -18,6 +18,7 @@ DEMO = \
 	 rendertarget.cc \
 	 programs.cc \
 	 camera.cc \
+	 demo.cc \
 	 \
 	 raymarcher.cc \
 	 \
diff --git a/demo.cc b/demo.cc
new file mode 100644
index 0000000..8f901ba
--- /dev/null
+++ b/demo.cc
@@ -0,0 +1,58 @@
+#include "externals.hh"
+#include "demo.hh"
+
+
+T_Demo::T_Demo( __rw__ T_FilesWatcher& watcher ,
+		__rd__ const uint32_t width ,
+		__rd__ const uint32_t height )
+	: watcher( watcher ) , width( width ) , height( height )
+{ }
+
+
+bool T_Demo::initialise( )
+{
+	raymarcher = std::make_unique< T_Raymarcher >(
+			watcher , width , height );
+	dof = std::make_unique< T_DoFPass >( watcher ,
+			raymarcher->output( ) , raymarcher->depth( ) );
+	bloom = std::make_unique< T_BloomPass >( watcher ,
+			raymarcher->output( ) );
+	combine = std::make_unique< T_CombinePass >( watcher ,
+			dof->output( ) , bloom->output( ) );
+	return true;
+}
+
+void T_Demo::makeUI( )
+{
+	raymarcher->makeUI( );
+	dof->makeUI( );
+	bloom->makeUI( );
+	combine->makeUI( );
+}
+
+void T_Demo::render( )
+{
+	raymarcher->render( );
+	dof->render( );
+	bloom->render( );
+	combine->render( );
+}
+
+void T_Demo::handleDND(
+		__rd__	ImVec2 const& move ,
+		__rd__	const bool hasCtrl ,
+		__rd__	const bool hasShift ,
+		__rd__	const bool lmb		// Left mouse button
+	)
+{
+	raymarcher->camera( ).handleDND( move , hasCtrl , hasShift , lmb );
+}
+
+void T_Demo::handleWheel(
+		__rd__	const float wheel ,
+		__rd__	const bool hasCtrl ,
+		__rd__	const bool hasShift
+	)
+{
+	raymarcher->camera( ).handleWheel( wheel , hasCtrl , hasShift );
+}
diff --git a/demo.hh b/demo.hh
new file mode 100644
index 0000000..f5a362d
--- /dev/null
+++ b/demo.hh
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "raymarcher.hh"
+#include "dof.hh"
+#include "bloom.hh"
+#include "combine.hh"
+#include "profiling.hh"
+
+
+struct T_Demo
+{
+	T_Demo( ) = delete;
+	NO_COPY( T_Demo );
+	NO_MOVE( T_Demo );
+
+	// ---------------------------------------------------------------------
+
+	T_Demo( __rw__ T_FilesWatcher& watcher ,
+			__rd__ const uint32_t width ,
+			__rd__ const uint32_t height );
+
+	bool initialise( );
+	void makeUI( );
+	void render( );
+
+	void handleDND(
+			__rd__	ImVec2 const& move ,
+			__rd__	const bool hasCtrl ,
+			__rd__	const bool hasShift ,
+			__rd__	const bool lmb		// Left mouse button
+		);
+	void handleWheel(
+			__rd__	const float wheel ,
+			__rd__	const bool hasCtrl ,
+			__rd__	const bool hasShift
+		);
+
+	// ---------------------------------------------------------------------
+
+	T_FilesWatcher& watcher;
+	const uint32_t width;
+	const uint32_t height;
+
+//	T_TextureManagement textures;
+
+	std::unique_ptr< T_Raymarcher > raymarcher;
+	std::unique_ptr< T_DoFPass > dof;
+	std::unique_ptr< T_BloomPass > bloom;
+	std::unique_ptr< T_CombinePass > combine;
+};
diff --git a/externals.hh b/externals.hh
index 678f39b..ff917fa 100644
--- a/externals.hh
+++ b/externals.hh
@@ -31,3 +31,17 @@
 #define __rd__
 #define __wr__
 #define __rw__
+
+// Macros that enable/disable copying/moving
+#define NO_COPY( CLS ) \
+	CLS( CLS const& ) = delete; \
+	CLS& operator =( CLS const& ) = delete
+#define NO_MOVE( CLS ) \
+	CLS( CLS&& ) = delete; \
+	CLS& operator =( CLS&& ) = delete
+#define COPY( CLS ) \
+	CLS( CLS const& ); \
+	CLS& operator =( CLS const& )
+#define MOVE( CLS ) \
+	CLS( CLS&& ); \
+	CLS& operator =( CLS&& )
diff --git a/main.cc b/main.cc
index b8efce0..75dbeee 100644
--- a/main.cc
+++ b/main.cc
@@ -1,10 +1,7 @@
 #include "externals.hh"
 
 #include "imgui_impl_sdl.h"
-#include "raymarcher.hh"
-#include "dof.hh"
-#include "bloom.hh"
-#include "combine.hh"
+#include "demo.hh"
 #include "profiling.hh"
 
 
@@ -30,10 +27,9 @@ struct T_Main
 	T_FilesWatcher watcher;
 	std::unique_ptr< T_ShaderProgram > spCopy;
 
-	std::unique_ptr< T_Raymarcher > raymarcher;
-	std::unique_ptr< T_DoFPass > dofPass;
-	std::unique_ptr< T_BloomPass > bloomPass;
-	std::unique_ptr< T_CombinePass > combinePass;
+	std::unique_ptr< T_Demo > demo;
+
+	void initDemo( );
 
 	void startIteration( );
 	void handleCapture( );
@@ -66,20 +62,22 @@ T_Main::T_Main( )
 	ImGui_ImplSdl_Init( window );
 
 	initProgram( );
-	raymarcher = std::make_unique< T_Raymarcher >( watcher , 1280 , 720 );
-	dofPass = std::make_unique< T_DoFPass >( watcher ,
-			raymarcher->output( ) , raymarcher->depth( ) );
-	bloomPass = std::make_unique< T_BloomPass >( watcher ,
-			raymarcher->output( ) );
-	combinePass = std::make_unique< T_CombinePass >( watcher ,
-			dofPass->output( ) , bloomPass->output( ) );
 }
 
 void T_Main::mainLoop( )
 {
 	auto& p( T_Profiler::Profiler );
-	p.clear( );
 	while ( !done ) {
+		if ( demo ) {
+			auto const& dspSize( ImGui::GetIO( ).DisplaySize );
+			if ( demo->width != dspSize.x || demo->height != dspSize.y ) {
+				demo.reset( );
+			}
+		}
+		if ( !demo ) {
+			initDemo( );
+		}
+
 		p.startFrame( );
 		T_Profiler::Profiler.start( "Full frame" );
 		startIteration( );
@@ -97,6 +95,7 @@ void T_Main::mainLoop( )
 
 T_Main::~T_Main( )
 {
+	demo.reset( );
 	ImGui_ImplSdl_Shutdown( );
 	SDL_GL_DeleteContext( gl );
 	SDL_DestroyWindow( window );
@@ -105,6 +104,23 @@ T_Main::~T_Main( )
 
 /*----------------------------------------------------------------------------*/
 
+void T_Main::initDemo( )
+{
+	assert( !demo );
+	auto const& dspSize( ImGui::GetIO( ).DisplaySize );
+	if ( dspSize.x < 0 || dspSize.y < 0 ) {
+		return;
+	}
+
+	printf( "init w/ dspsize %dx%d\n" , int( dspSize.x ) , int( dspSize.y ) );
+	demo = std::make_unique< T_Demo >( watcher , dspSize.x , dspSize.y );
+	if ( demo->initialise( ) ) {
+		T_Profiler::Profiler.clear( );
+	} else {
+		demo.reset( );
+	}
+}
+
 void T_Main::startIteration( )
 {
 	SDL_Event event;
@@ -147,7 +163,9 @@ void T_Main::handleCapture( )
 		ImGui::SetMouseCursor( ImGuiMouseCursor_Arrow );
 	} else if ( capture ) {
 		ImGui::SetMouseCursor( ImGuiMouseCursor_Move );
-		raymarcher->camera( ).handleDND( mouseMove , ctrl , shift , lmb );
+		if ( demo ) {
+			demo->handleDND( mouseMove , ctrl , shift , lmb );
+		}
 	} else if ( appCanGrab && mb ) {
 		capture = true;
 		mouseInitial = ImGui::GetMousePos( );
@@ -156,8 +174,8 @@ void T_Main::handleCapture( )
 		ImGui::SetMouseCursor( ImGuiMouseCursor_Move );
 	}
 
-	if ( ( appCanGrab || capture ) && io.MouseWheel ) {
-		raymarcher->camera( ).handleWheel( io.MouseWheel , ctrl , shift );
+	if ( ( appCanGrab || capture ) && io.MouseWheel && demo ) {
+		demo->handleWheel( io.MouseWheel , ctrl , shift );
 	}
 }
 
@@ -168,13 +186,10 @@ void T_Main::makeUI( )
 			ImGuiSetCond_Once );
 	ImGui::SetNextWindowPos( ImVec2( ) , ImGuiSetCond_Once );
 	ImGui::Begin( "Yay! Demo!" );
-
 	ImGui::Checkbox( "Profiler" , &T_Profiler::Profiler.uiEnabled( ) );
-	raymarcher->makeUI( );
-	dofPass->makeUI( );
-	bloomPass->makeUI( );
-	combinePass->makeUI( );
-
+	if ( demo ) {
+		demo->makeUI( );
+	}
 	ImGui::End( );
 
 	T_Profiler::Profiler.makeUI( );
@@ -182,13 +197,11 @@ void T_Main::makeUI( )
 
 void T_Main::render( )
 {
-	T_Profiler::Profiler.start( "Render" );
-	raymarcher->render( );
-	dofPass->render( );
-	bloomPass->render( );
-	combinePass->render( );
-	glFinish( ); T_Profiler::Profiler.end( "Render" );
-
+	if ( demo ) {
+		T_Profiler::Profiler.start( "Render" );
+		demo->render( );
+		glFinish( ); T_Profiler::Profiler.end( "Render" );
+	}
 	glUseProgram( 0 );
 	ImGui::Render( );
 }
diff --git a/texture.cc b/texture.cc
index 9571ec7..7d0e7c4 100644
--- a/texture.cc
+++ b/texture.cc
@@ -75,7 +75,7 @@ T_Texture::T_Texture(
 		assert( w && h );
 	}
 
-	GL_CHECK( );
+	GL_ASSERT( );
 }
 
 T_Texture::~T_Texture( )
@@ -131,7 +131,7 @@ T_Texture& T_Texture::wrap(
 T_TextureSampler::T_TextureSampler( )
 {
 	glGenSamplers( 1 , &id_ );
-	GL_CHECK( );
+	GL_ASSERT( );
 }
 
 T_TextureSampler::T_TextureSampler(
@@ -204,7 +204,7 @@ T_TextureSampler& T_TextureSampler::wrap(
 	}
 	glSamplerParameteri( id_ , GL_TEXTURE_WRAP_S , gm );
 	glSamplerParameteri( id_ , GL_TEXTURE_WRAP_T , gm );
-	GL_CHECK( );
+	GL_ASSERT( );
 	return *this;
 }
 
@@ -214,7 +214,7 @@ T_TextureSampler& T_TextureSampler::lod(
 {
 	glSamplerParameterf( id_ , GL_TEXTURE_MIN_LOD , min );
 	glSamplerParameterf( id_ , GL_TEXTURE_MAX_LOD , max );
-	GL_CHECK( );
+	GL_ASSERT( );
 	return *this;
 }
 
@@ -250,7 +250,7 @@ void T_TextureSampler::setSamplingMode( ) const
 
 	glSamplerParameteri( id_ , GL_TEXTURE_MIN_FILTER , min );
 	glSamplerParameteri( id_ , GL_TEXTURE_MAG_FILTER , max );
-	GL_CHECK( );
+	GL_ASSERT( );
 }
 
 
diff --git a/texture.hh b/texture.hh
index bc74fab..9dff77f 100644
--- a/texture.hh
+++ b/texture.hh
@@ -129,6 +129,7 @@ struct T_TextureManagement
 {
 	static constexpr uint32_t MaxUnits = 8;
 
+	T_TextureManagement( ) = default;
 	T_TextureManagement( T_TextureManagement const& ) = delete;
 	T_TextureManagement( T_TextureManagement&& ) = delete;
 
diff --git a/utilities.hh b/utilities.hh
index 182d5c7..eeda6f0 100644
--- a/utilities.hh
+++ b/utilities.hh
@@ -15,16 +15,19 @@ inline void reenableButtons( )
 
 /*----------------------------------------------------------------------------*/
 
-#define GL_CHECK( ) \
+#define GL_CHECK( FAIL ) \
 	do { \
 		auto err_( glGetError( ) ); \
-		if ( err_ != GL_NO_ERROR ) { \
-			fprintf( stderr , "GL error %x in %s:%d\n" , \
-					err_ , __FILE__ , __LINE__ ); \
-			abort( ); \
-		} \
+		if ( err_ != GL_NO_ERROR ) FAIL; \
 	} while ( 0 )
 
+#define GL_ASSERT( ) \
+	GL_CHECK({ \
+		fprintf( stderr , "GL error %x in %s:%d\n" , \
+				err_ , __FILE__ , __LINE__ ); \
+		abort( ); \
+	})
+
 /*----------------------------------------------------------------------------*/
 
 // Add some value to an angle, keeping it in [-180;180]