diff --git a/control.cc b/control.cc
index 17c7b44..1943fd4 100644
--- a/control.cc
+++ b/control.cc
@@ -5,6 +5,18 @@
 using namespace cops;
 
 
+/*= Command execution ========================================================*/
+
+void cops::Execute(
+	__rd__ T_Operations const& operations ,
+	__rw__ T_Context& context )
+{
+	for ( auto const& op : operations ) {
+		op->execute( context );
+	}
+}
+
+
 /*= X_OpFailure ==============================================================*/
 
 X_OpFailure::X_OpFailure(
@@ -49,7 +61,7 @@ OPLoadConstant::OPLoadConstant(
 { }
 
 void OPLoadConstant::execute(
-		__rw__ T_Context& ctx )
+		__rw__ T_Context& ctx ) const
 {
 	ctx.opStack.push_back( constant );
 }
@@ -63,7 +75,7 @@ OPLoadVariable::OPLoadVariable(
 { }
 
 void OPLoadVariable::execute(
-		__rw__ T_Context& ctx )
+		__rw__ T_Context& ctx ) const
 {
 	const auto vPos( ctx.varPos.find( variable ) );
 	if ( vPos == ctx.varPos.end( ) ) {
@@ -81,7 +93,7 @@ OPLoadInput::OPLoadInput(
 { }
 
 void OPLoadInput::execute(
-		__rw__ T_Context& ctx )
+		__rw__ T_Context& ctx ) const
 {
 	ctx.opStack.push_back( ctx.sync->valueOf( input , *( ctx.time ) ) );
 }
@@ -95,7 +107,7 @@ OPStoreVariable::OPStoreVariable(
 { }
 
 void OPStoreVariable::execute(
-		__rw__ T_Context& ctx )
+		__rw__ T_Context& ctx ) const
 {
 	if ( ctx.opStack.empty( ) ) {
 		throw error( "stack is empty" );
@@ -118,7 +130,7 @@ void OPStoreVariable::execute(
 /*= Arithmetic operators =====================================================*/
 
 void OPAdd::execute(
-		__rw__ T_Context& ctx )
+		__rw__ T_Context& ctx ) const
 {
 	if ( ctx.opStack.size( ) < 2 ) {
 		throw error( "missing operands in stack" );
@@ -129,7 +141,7 @@ void OPAdd::execute(
 }
 
 void OPMul::execute(
-		__rw__ T_Context& ctx )
+		__rw__ T_Context& ctx ) const
 {
 	if ( ctx.opStack.size( ) < 2 ) {
 		throw error( "missing operands in stack" );
@@ -140,7 +152,7 @@ void OPMul::execute(
 }
 
 void OPNeg::execute(
-		__rw__ T_Context& ctx )
+		__rw__ T_Context& ctx ) const
 {
 	if ( ctx.opStack.empty( ) ) {
 		throw error( "missing operand in stack" );
@@ -149,7 +161,7 @@ void OPNeg::execute(
 }
 
 void OPInv::execute(
-		__rw__ T_Context& ctx )
+		__rw__ T_Context& ctx ) const
 {
 	if ( ctx.opStack.empty( ) || ctx.opStack.back( ) == 0 ) {
 		throw error( "missing operand in stack" );
@@ -165,7 +177,7 @@ OPDup::OPDup( __rd__ const uint32_t stackIndex )
 { }
 
 void OPDup::execute(
-		__rw__ T_Context& ctx )
+		__rw__ T_Context& ctx ) const
 {
 	if ( ctx.opStack.size( ) <= stackIndex ) {
 		std::string err( "stack does not have " );
@@ -183,7 +195,7 @@ OPXchg::OPXchg( __rd__ const uint32_t stackIndex )
 { }
 
 void OPXchg::execute(
-		__rw__ T_Context& ctx )
+		__rw__ T_Context& ctx ) const
 {
 	if ( ctx.opStack.size( ) <= stackIndex ) {
 		std::string err( "stack does not have " );
@@ -199,6 +211,10 @@ void OPXchg::execute(
 
 /*= OPSetUniform =============================================================*/
 
+// GENERAL FIXME
+// program identifier should be an entry in a table
+// or, you know, a program name
+
 OPSetUniform::OPSetUniform(
 		__rd__ const uint32_t program ,
 		__rd__ const uint32_t uniform ,
@@ -209,7 +225,7 @@ OPSetUniform::OPSetUniform(
 { }
 
 void OPSetUniform::execute(
-		__rw__ T_Context& ctx )
+		__rw__ T_Context& ctx ) const
 {
 	if ( count == 0 || ctx.opStack.size( ) < count ) {
 		std::string err( "stack does not have " );
@@ -244,3 +260,101 @@ void OPSetUniform::execute(
 		func( program , uniform , 1 , values );
 	}
 }
+
+
+/*= OPUsePipeline ============================================================*/
+
+// GENERAL FIXME
+// pipeline identifier should be an entry in a table
+// or, you know, a program name
+
+OPUsePipeline::OPUsePipeline(
+		__rd__ const uint32_t index )
+	: T_Op( OP_USE_PIPELINE ) , pipeline( index )
+{ }
+
+void OPUsePipeline::execute(
+		__rw__ T_Context& ) const
+{
+	glBindProgramPipeline( pipeline );
+}
+
+
+/*= OPUseTexture =============================================================*/
+
+// GENERAL FIXME
+// texture & sampler identifiers should be entries in a table
+
+OPUseTexture::OPUseTexture(
+		__rd__ const uint32_t binding ,
+		__rd__ const uint32_t texture ,
+		__rd__ const uint32_t sampler )
+	: T_Op( OP_USE_TEXTURE ) , binding( binding ) ,
+		texture( texture ) , sampler( sampler )
+{ }
+
+void OPUseTexture::execute(
+		__rw__ T_Context& ) const
+{
+	glBindTextureUnit( binding , texture );
+	glBindSampler( binding , sampler );
+}
+
+
+/*= OPUseFramebuffer =========================================================*/
+
+// GENERAL FIXME
+// framebuffer identifier should be an entry in a table
+
+OPUseFramebuffer::OPUseFramebuffer(
+		__rd__ const uint32_t framebuffer )
+	: T_Op( OP_USE_FRAMEBUFFER ) , framebuffer( framebuffer )
+{ }
+
+void OPUseFramebuffer::execute(
+		__rw__ T_Context& ) const
+{
+	glBindFramebuffer( GL_FRAMEBUFFER , framebuffer );
+}
+
+
+/*= OPSetViewport ============================================================*/
+
+void OPSetViewport::execute(
+		__rw__ T_Context& ctx ) const
+{
+	if ( ctx.opStack.size( ) < 4 ) {
+		throw error( "stack does not have 4 items" );
+	}
+	glViewport(
+		*( ctx.opStack.end( ) - 1 ) ,
+		*( ctx.opStack.end( ) - 2 ) ,
+		*( ctx.opStack.end( ) - 3 ) ,
+		*( ctx.opStack.end( ) - 4 ) );
+	ctx.opStack.resize( ctx.opStack.size( ) - 4 );
+}
+
+
+/*= Draw commands ============================================================*/
+
+void OPClear::execute(
+		__rw__ T_Context& ctx ) const
+{
+	if ( ctx.opStack.size( ) < 4 ) {
+		throw error( "stack does not have 4 items" );
+	}
+	glClearColor(
+		*( ctx.opStack.end( ) - 1 ) ,
+		*( ctx.opStack.end( ) - 2 ) ,
+		*( ctx.opStack.end( ) - 3 ) ,
+		*( ctx.opStack.end( ) - 4 ) );
+	ctx.opStack.resize( ctx.opStack.size( ) - 4 );
+	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+}
+
+void OPFullscreen::execute(
+		__rw__ T_Context& ) const
+{
+	glBindVertexArray( 0 );
+	glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 );
+}
diff --git a/control.hh b/control.hh
index e63b3c8..376720e 100644
--- a/control.hh
+++ b/control.hh
@@ -64,6 +64,10 @@ namespace cops {
 		OP_USE_PIPELINE ,
 		OP_USE_TEXTURE ,
 		OP_USE_FRAMEBUFFER ,
+		OP_SET_VIEWPORT ,
+		//
+		OP_CLEAR ,
+		OP_FULLSCREEN
 	};
 
 	struct T_Op
@@ -76,7 +80,7 @@ namespace cops {
 			{ return op_; }
 
 		virtual void execute(
-			__rw__ T_Context& ctx ) = 0;
+			__rw__ T_Context& ctx ) const = 0;
 
 		std::string source;
 		uint32_t line;
@@ -88,7 +92,8 @@ namespace cops {
 	    private:
 		E_Op op_;
 	};
-	using T_Operations = std::vector< cops::T_Op >;
+	using P_Op = std::unique_ptr< T_Op >;
+	using T_Operations = std::vector< P_Op >;
 
 	/*====================================================================*/
 
@@ -97,7 +102,7 @@ namespace cops {
 		explicit OPLoadConstant(
 			__rd__ const float constant );
 		void execute(
-			__rw__ T_Context& ctx ) override;
+			__rw__ T_Context& ctx ) const override;
 		float constant;
 	};
 
@@ -106,7 +111,7 @@ namespace cops {
 		explicit OPLoadVariable(
 			__rd__ std::string const& variable );
 		void execute(
-			__rw__ T_Context& ctx ) override;
+			__rw__ T_Context& ctx ) const override;
 		std::string variable;
 	};
 
@@ -115,7 +120,7 @@ namespace cops {
 		explicit OPLoadInput(
 			__rd__ std::string const& input );
 		void execute(
-			__rw__ T_Context& ctx ) override;
+			__rw__ T_Context& ctx ) const override;
 		std::string input;
 	};
 
@@ -124,7 +129,7 @@ namespace cops {
 		explicit OPStoreVariable(
 			__rd__ std::string const& variable );
 		void execute(
-			__rw__ T_Context& ctx ) override;
+			__rw__ T_Context& ctx ) const override;
 		std::string variable;
 	};
 
@@ -134,28 +139,28 @@ namespace cops {
 	{
 		OPAdd( ) : T_Op( OP_ADD ) {}
 		void execute(
-			__rw__ T_Context& ctx ) override;
+			__rw__ T_Context& ctx ) const override;
 	};
 
 	struct OPMul : public T_Op
 	{
 		OPMul( ) : T_Op( OP_MUL ) {}
 		void execute(
-			__rw__ T_Context& ctx ) override;
+			__rw__ T_Context& ctx ) const override;
 	};
 
 	struct OPNeg : public T_Op
 	{
 		OPNeg( ) : T_Op( OP_NEG ) {}
 		void execute(
-			__rw__ T_Context& ctx ) override;
+			__rw__ T_Context& ctx ) const override;
 	};
 
 	struct OPInv : public T_Op
 	{
 		OPInv( ) : T_Op( OP_INV ) {}
 		void execute(
-			__rw__ T_Context& ctx ) override;
+			__rw__ T_Context& ctx ) const override;
 	};
 
 	/*--------------------------------------------------------------------*/
@@ -164,7 +169,7 @@ namespace cops {
 	{
 		explicit OPDup( uint32_t stackIndex = 0 );
 		void execute(
-			__rw__ T_Context& ctx ) override;
+			__rw__ T_Context& ctx ) const override;
 		uint32_t stackIndex;
 	};
 
@@ -172,7 +177,7 @@ namespace cops {
 	{
 		explicit OPXchg( uint32_t stackIndex = 1 );
 		void execute(
-			__rw__ T_Context& ctx ) override;
+			__rw__ T_Context& ctx ) const override;
 		uint32_t stackIndex;
 	};
 
@@ -186,7 +191,7 @@ namespace cops {
 			__rd__ const uint32_t count ,
 			__rd__ const bool integer );
 		void execute(
-			__rw__ T_Context& ctx ) override;
+			__rw__ T_Context& ctx ) const override;
 
 		uint32_t program;
 		uint32_t uniform;
@@ -194,17 +199,63 @@ namespace cops {
 		bool integer;
 	};
 
-
 	struct OPUsePipeline : public T_Op
 	{
 		explicit OPUsePipeline(
 			__rd__ const uint32_t index );
 		void execute(
-			__rw__ T_Context& ctx ) override;
+			__rw__ T_Context& ctx ) const override;
 
 		uint32_t pipeline;
 	};
 
+	struct OPUseTexture : public T_Op
+	{
+		OPUseTexture(
+			__rd__ const uint32_t binding ,
+			__rd__ const uint32_t texture ,
+			__rd__ const uint32_t sampler = 0 );
+		void execute(
+			__rw__ T_Context& ctx ) const override;
+
+		uint32_t binding;
+		uint32_t texture;
+		uint32_t sampler;
+	};
+
+	struct OPUseFramebuffer : public T_Op
+	{
+		explicit OPUseFramebuffer(
+			__rd__ const uint32_t framebuffer );
+		void execute(
+			__rw__ T_Context& ctx ) const override;
+
+		uint32_t framebuffer;
+	};
+
+	struct OPSetViewport : public T_Op
+	{
+		OPSetViewport( ) : T_Op( OP_SET_VIEWPORT ) { }
+		void execute(
+			__rw__ T_Context& ctx ) const override;
+	};
+
+	/*--------------------------------------------------------------------*/
+
+	struct OPClear : public T_Op
+	{
+		OPClear( ) : T_Op( OP_CLEAR ) { }
+		void execute(
+			__rw__ T_Context& ctx ) const override;
+	};
+
+	struct OPFullscreen : public T_Op
+	{
+		OPFullscreen( ) : T_Op( OP_FULLSCREEN ) { }
+		void execute(
+			__rw__ T_Context& ctx ) const override;
+	};
+
 	/*====================================================================*/
 
 	void Execute(