diff --git a/source/main.cpp b/source/main.cpp
index d77d9ca116d83a8ae28bde15538ff9015eef7aed..f4b769accf60f0f5ec02f91318e16f79dbe8e037 100755
--- a/source/main.cpp
+++ b/source/main.cpp
@@ -17,38 +17,128 @@
 
 #include "MicroBit.h"
 
-MicroBit ubit;
+
+/*
+ * NOTE: this global variable is our MicroBit instance.
+ *
+ * I'd much rather declare this in main() only (I don't like globals) and
+ * interact with it from my classes via a reference or a pointer to it, however
+ * this does not appear to work, for some unknown reason...
+ */
+MicroBit UBIT;
 
 
-class EventThingy {
+/**
+ * @brief Main class responsible for the game loop and logic
+ */
+class Game {
 public:
-    EventThingy() {
-        ubit.messageBus.listen(
-            MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, this, &EventThingy::event_handler_a
-        );
-
-        ubit.messageBus.listen(
-            MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, this, &EventThingy::event_handler_b
-        );
-    }
+    /**
+     * @brief Default Constructor
+     */
+    Game();
 
-    void event_handler_a(MicroBitEvent) {
-        ubit.display.image.setPixelValue(2, 2, 1);
-    }
+    /**
+     * @brief Starts a new run of the game
+     * @note method blocks until game over.
+     */
+    void run();
 
-    void event_handler_b(MicroBitEvent) {
-        ubit.display.image.setPixelValue(2, 2, 0);
-    }
+    /* begin event handler methods */
+
+    /**
+     * Handles Button A Press event
+     */
+    void press_button_a(MicroBitEvent);
+
+    /**
+     * Handles Button B Press event
+     */
+    void press_button_b(MicroBitEvent);
+
+    /* end event handler methods */
+
+private:
+    /**
+     * @brief Draws whatever's in the screen buffer to display
+     */
+    void draw();
+
+    // internal screen-buffer, which we draw to first before pasting to display
+    MicroBitImage screen_buffer;
 };
 
+Game::Game()
+    : screen_buffer(5, 5) // our screen buffer mirrors the display dimensions
+{}
+
+void Game::run() {
+    UBIT.display.scroll("NEW GAME!");
+    // init screen display mode, to be sure it is in a known-state
+    // TODO: consider changing to greyscale to allow "mutli-coloured" blocks
+    UBIT.display.setDisplayMode(DISPLAY_MODE_BLACK_AND_WHITE);
+    // register event-handlers
+    UBIT.messageBus.listen(
+        MICROBIT_ID_BUTTON_A,
+        MICROBIT_BUTTON_EVT_CLICK,
+        this,
+        &Game::press_button_a
+    );
+    UBIT.messageBus.listen(
+        MICROBIT_ID_BUTTON_B,
+        MICROBIT_BUTTON_EVT_CLICK,
+        this,
+        &Game::press_button_b
+    );
+    while (true) { // TODO: change to use game-over condition
+        // sleep to conserve CPU cycles and allow other fibers a chance to run
+        UBIT.sleep(10); // 10ms sleep, or 100Hz tick rate
+        this->draw(); // render screen buffer
+    }
+    // TODO: add the rest of the game logic
+    UBIT.display.scroll("GAME OVER!");
+    // TODO: display final score
+    // TODO: de-register event-handlers
+    UBIT.messageBus.ignore(
+        MICROBIT_ID_BUTTON_A,
+        MICROBIT_BUTTON_EVT_CLICK,
+        this,
+        &Game::press_button_a
+    );
+    UBIT.messageBus.ignore(
+        MICROBIT_ID_BUTTON_B,
+        MICROBIT_BUTTON_EVT_CLICK,
+        this,
+        &Game::press_button_b
+    );
+}
+
+void Game::draw() {
+    // XXX: debug drawing, fill the screen buffer with black
+    this->screen_buffer.clear();
+    // render our screen buffer
+    UBIT.display.image.paste(this->screen_buffer);
+}
+
+void Game::press_button_a(MicroBitEvent e) {
+    // XXX: debug
+    this->screen_buffer.setPixelValue(0, 2, 255);
+}
+
+void Game::press_button_b(MicroBitEvent e) {
+    // XXX: debug
+    this->screen_buffer.setPixelValue(4, 2, 255);
+}
+
 int main() {
     // Initialise the micro:bit runtime.
-    ubit.init();
+    UBIT.init();
 
-    EventThingy eventer;
+    UBIT.display.scroll("BLOCKS!");
 
-    while (true) {
-        ubit.sleep(10); // 10ms sleep, or 100Hz tick rate
+    while (true) { // indefinitely start new games
+        Game game;
+        game.run();
     }
 
     // TODO: potentially remove this call, if clarified that it is not required.