diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp
index c3205580d..9a1ac6494 100644
--- a/Machines/Oric/Oric.cpp
+++ b/Machines/Oric/Oric.cpp
@@ -45,6 +45,11 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
 	return 1;
 }
 
+void Machine::synchronise()
+{
+	update_video();
+}
+
 void Machine::update_video()
 {
 	_videoOutput->run_for_cycles(_cycles_since_video_update);
@@ -53,21 +58,10 @@ void Machine::update_video()
 
 void Machine::setup_output(float aspect_ratio)
 {
-	// TODO: this is a copy and paste from the Electron; correct.
-
-	_crt.reset(new Outputs::CRT::CRT(256, 8, Outputs::CRT::DisplayType::PAL50, 1));
-	_crt->set_rgb_sampling_function(
-		"vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)"
-		"{"
-			"uint texValue = texture(sampler, coordinate).r;"
-			"texValue >>= 4 - (int(icoordinate.x * 8) & 4);"
-			"return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));"
-		"}");
-
 	_videoOutput.reset(new VideoOutput(_ram));
-	_videoOutput->set_crt(_crt);
 }
 
 void Machine::close_output()
 {
+	_videoOutput.reset();
 }
diff --git a/Machines/Oric/Oric.hpp b/Machines/Oric/Oric.hpp
index ccf2ffca1..2fbededf9 100644
--- a/Machines/Oric/Oric.hpp
+++ b/Machines/Oric/Oric.hpp
@@ -38,12 +38,12 @@ class Machine:
 
 		// to satisfy CPU6502::Processor
 		unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
-		void synchronise() { update_video(); }
+		void synchronise();
 
 		// to satisfy CRTMachine::Machine
 		virtual void setup_output(float aspect_ratio);
 		virtual void close_output();
-		virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return _crt; }
+		virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return _videoOutput->get_crt(); }
 		virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return nullptr; }
 		virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
 
@@ -54,7 +54,6 @@ class Machine:
 		inline void update_video();
 
 		// Outputs
-		std::shared_ptr<Outputs::CRT::CRT> _crt;
 		std::unique_ptr<VideoOutput> _videoOutput;
 };
 
diff --git a/Machines/Oric/Video.cpp b/Machines/Oric/Video.cpp
index 3c106a9f0..7ddd97686 100644
--- a/Machines/Oric/Video.cpp
+++ b/Machines/Oric/Video.cpp
@@ -10,14 +10,61 @@
 
 using namespace Oric;
 
-VideoOutput::VideoOutput(uint8_t *memory) : _ram(memory)
+VideoOutput::VideoOutput(uint8_t *memory) :
+	_ram(memory),
+	_frame_counter(0), _counter(0),
+	_state(Sync), _cycles_in_state(0)
 {
+	_crt.reset(new Outputs::CRT::CRT(384, 6, Outputs::CRT::DisplayType::PAL50, 1));
+
+	// TODO: this is a copy and paste from the Electron; factor out.
+	_crt->set_rgb_sampling_function(
+		"vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)"
+		"{"
+			"uint texValue = texture(sampler, coordinate).r;"
+			"texValue >>= 4 - (int(icoordinate.x * 8) & 4);"
+			"return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));"
+		"}");
 }
 
-void VideoOutput::set_crt(std::shared_ptr<Outputs::CRT::CRT> crt)
+std::shared_ptr<Outputs::CRT::CRT> VideoOutput::get_crt()
 {
+	return _crt;
 }
 
 void VideoOutput::run_for_cycles(int number_of_cycles)
 {
+	// Vertical: 0–39: pixels; otherwise blank; 48–53 sync
+	// Horizontal: 0–223: pixels; otherwise blank; 256–259 sync
+
+	while(number_of_cycles--)
+	{
+		_counter = (_counter + 1)%(312 * 64);	// TODO: NTSC
+
+		State new_state = Blank;
+		if((_counter & 63) >= 48 && (_counter & 63) <= 53) new_state = Sync;
+		else if(_counter >= 256*312 && _counter <= 259*312) new_state = Sync;
+		else if(_counter < 224 && ((_counter&63) < 40)) new_state = Pixels;
+
+		if(_state != new_state)
+		{
+			switch(_state)
+			{
+				case Sync:		_crt->output_sync(_cycles_in_state * 6);		break;
+				case Blank:		_crt->output_blank(_cycles_in_state * 6);		break;
+				case Pixels:	_crt->output_data(_cycles_in_state * 6, 2);		break;
+			}
+			_state = new_state;
+			_cycles_in_state = 0;
+			if(_state == Pixels) _pixel_target = _crt->allocate_write_area(120);
+		}
+		else _cycles_in_state++;
+
+		if(new_state == Pixels) {
+			_pixel_target[0] = 0x70;
+			_pixel_target[1] = 0x14;
+			_pixel_target[2] = 0x23;
+			_pixel_target += 3;
+		}
+	}
 }
diff --git a/Machines/Oric/Video.hpp b/Machines/Oric/Video.hpp
index cf5a49564..a16ed54bc 100644
--- a/Machines/Oric/Video.hpp
+++ b/Machines/Oric/Video.hpp
@@ -16,11 +16,25 @@ namespace Oric {
 class VideoOutput {
 	public:
 		VideoOutput(uint8_t *memory);
-		void set_crt(std::shared_ptr<Outputs::CRT::CRT> crt);
+		std::shared_ptr<Outputs::CRT::CRT> get_crt();
 		void run_for_cycles(int number_of_cycles);
 
 	private:
 		uint8_t *_ram;
+		std::shared_ptr<Outputs::CRT::CRT> _crt;
+
+		// Counters
+		int _counter, _frame_counter;
+
+		// Output state
+		enum State {
+			Blank, Sync, Pixels
+		} _state;
+		unsigned int _cycles_in_state;
+		uint8_t *_pixel_target;
+
+		// Registers
+		uint8_t _ink, _style, _paper;
 };
 
 }