diff --git a/Makefile b/Makefile
index b2992bcd27b4b8d4665b1604502a5317cf460693..213bfcda2957ccce7b0a6512fded9141edc9ff06 100644
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,7 @@ $(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
 	$(ECHO) compiling $<
 	clang -c $(CFLAGS) $< -o $@
 
-all: $(BUILD_DIR)/splat $(BUILD_DIR)/shapes
+all: $(BUILD_DIR)/splat $(BUILD_DIR)/shapes $(BUILD_DIR)/sprite
 
 $(BUILD_DIR)/splat: $(OBJECTS) $(BUILD_DIR)/splat.o Makefile
 	$(ECHO) linking $<
@@ -45,6 +45,12 @@ $(BUILD_DIR)/shapes: $(OBJECTS) $(BUILD_DIR)/shapes.o Makefile
 	# $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(BUILD_DIR)/splat.o
 	$(ECHO) success
 
+$(BUILD_DIR)/sprite: $(OBJECTS) $(BUILD_DIR)/sprite.o Makefile
+	$(ECHO) linking $<
+	$(CC) -L./osx/lib/ -lSDL2 -lSDL2_ttf -lSDL2_image -lfreetype -lpng -lwebp -ltiff -ljpeg -lbz2 -lz -framework OpenGL -o $@ $(OBJECTS) build/sprite.o
+	# $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(BUILD_DIR)/splat.o
+	$(ECHO) success
+
 #######################################
 # clean up
 #######################################
diff --git a/examples/shapes.cpp b/examples/shapes.cpp
index f1054d5d333848e8a0627a9d954cf634ff66395a..0d6ce8bf88efc2621ba702343ab365d61af46f51 100644
--- a/examples/shapes.cpp
+++ b/examples/shapes.cpp
@@ -3,8 +3,6 @@
 #include <vector>
 #include <cstring>
 
-#include <SDL2/SDL.h>
-
 #include <context.hpp>
 #include <app.hpp>
 
@@ -23,7 +21,7 @@ private:
 
     uwe::Font font15_;
 public:
-    MyApp(int width, int height);
+    MyApp(int width, int height, std::string title);
     ~MyApp();
 
     void begin() override;
@@ -35,10 +33,10 @@ public:
     uwe::Image render_text(std::string msg);
 };
 
-MyApp::MyApp(int width, int height): 
+MyApp::MyApp(int width, int height, std::string title): 
     width_{width},
     height_{height} {
-        init(width, height);
+        init(width, height, title);
 }
 
 MyApp::~MyApp() {
@@ -138,22 +136,10 @@ uwe::Image MyApp::render_text(std::string msg) {
     return image;
 }
 
-// int WINAPI WinMain(
-//     HINSTANCE   hInstance,
-//     HINSTANCE   hPrevInstance,
-//     PWSTR       lpCmdLine,
-//     int         nCmdShow) {
-//     SDL_SetMainReady();
-//     std::cout << "here" << std::endl;
-
-//     return 0;
-// }
-
-//int main( int argc, char** argv ) {
 int main(int argc, char *argv[]) {
     //SDL_SetMainReady();
     
-    uwe::App* app = new MyApp{width, height};
+    uwe::App* app = new MyApp{width, height, "Shapes Example"};
     std::cout << "here 2" << std::endl;
 
     //app->dump_renderer_info();
diff --git a/examples/splat.cpp b/examples/splat.cpp
index 8add178b3e54f2937746a16afdd6ecff37d8be39..d6a9ce1a9b5e1e41c6731976596af56b8b91b5f9 100644
--- a/examples/splat.cpp
+++ b/examples/splat.cpp
@@ -14,7 +14,7 @@ private:
     int width_;
     int height_;
 public:
-    MyApp(int width, int height);
+    MyApp(int width, int height, std::string);
     ~MyApp();
 
     void begin() override;
@@ -24,10 +24,10 @@ public:
     void key_pressed(uwe::Scancode scancode, bool repeat) override;
 };
 
-MyApp::MyApp(int width, int height): 
+MyApp::MyApp(int width, int height, std::string title): 
     width_{width},
     height_{height} {
-        init(width, height);
+        init(width, height, title);
 }
 
 MyApp::~MyApp() {
@@ -57,7 +57,7 @@ void MyApp::draw() {
 
         const unsigned int offset = ( get_framebuffer_width() * 4 * y ) + x * 4;
 
-        set_framebuffer(
+        set_framebuffer_non_scaled(
             offset, 
             uwe::Colour{
                 static_cast<uint8_t>(rand() % 256), 
@@ -71,7 +71,7 @@ void MyApp::draw() {
 
 
 int main( int argc, char** argv ) {
-    uwe::App* app = new MyApp{width, height};
+    uwe::App* app = new MyApp{width, height, "Splat Example"};
 
     //app->dump_renderer_info();
     app->run();
diff --git a/examples/sprite.cpp b/examples/sprite.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b074fe72ec6b85c8f4b06616a5c47a01c3de2784
--- /dev/null
+++ b/examples/sprite.cpp
@@ -0,0 +1,270 @@
+#include <iostream>
+#include <iomanip>
+#include <vector>
+#include <cstring>
+#include <tuple>
+
+#include <context.hpp>
+#include <app.hpp>
+
+using namespace std;
+
+const int width = 640;
+const int height = 480;
+
+const int COLOUR_INDEX_X = 30;
+const int COLOUR_INDEX_Y = 420;
+
+const int COLOUR_PALATE_WIDTH = 20;
+const int COLOUR_PALATE_HEIGHT = 20;
+
+const int COLOUR_CURRENT_X = 30;
+const int COLOUR_CURRENT_Y = 30;
+
+const int SPRITE_WIDTH = 16;
+const int SPRITE_HEIGHT = 16;
+
+const int SPRITE_DISPLAY_X = 500;
+const int SPRITE_DISPLAY_Y = 220;
+
+const int SPRITE_EDITOR_X = 250;
+const int SPRITE_EDITOR_Y = 150;
+
+const int SPRITE_EDITOR_PIXELS_WIDTH = 8;
+const int SPRITE_EDITOR_PIXELS_HEIGHT = 8;
+
+const int SPRITE_EDITOR_CELL_TIMES = 8;
+
+const int SPRITE_START_X = 100;
+const int SPRITE_START_Y = 100;
+
+class MyApp: public uwe::App {
+private:
+    int width_;
+    int height_;
+    
+    int colour_index_x_;
+    int colour_index_y_;
+    int colour_index_overall_width_;
+    vector<uwe::Colour> colour_palate_;
+
+    uwe::Colour current_colour_;
+
+    vector<uwe::Colour> sprite_;
+
+    int sprite_x_;
+    int sprite_y_;
+
+    bool mouse_down_;
+
+    bool editor_active_;
+public:
+    MyApp(int width, int height, std::string title);
+    ~MyApp();
+
+    size_t number_colours() const {
+        return colour_palate_.size();
+    }
+
+    bool hit_palate(int x, int y, size_t& hit_index) {
+        if (x >= colour_index_x_ && x <= colour_index_overall_width_ * number_colours() &&
+            y >= colour_index_y_ && y <= colour_index_y_ + COLOUR_PALATE_HEIGHT) {
+                hit_index = (x - colour_index_x_) / COLOUR_PALATE_WIDTH;
+                return true;
+        }
+
+        return false;
+    }
+
+    bool hit_editor(int x, int y, size_t& hit_index) {
+        if (x >= SPRITE_EDITOR_X && x <= SPRITE_EDITOR_X + SPRITE_EDITOR_PIXELS_WIDTH*SPRITE_WIDTH &&
+            y >= SPRITE_EDITOR_Y && y <= SPRITE_EDITOR_Y + SPRITE_EDITOR_PIXELS_HEIGHT*SPRITE_HEIGHT ) {
+                hit_index = (x - SPRITE_EDITOR_X) / (SPRITE_EDITOR_PIXELS_WIDTH);
+                int tmp = (y - SPRITE_EDITOR_Y) / SPRITE_EDITOR_PIXELS_HEIGHT;
+                hit_index = hit_index + SPRITE_WIDTH*tmp;
+                return true;
+        }
+        return false;
+    }
+
+    void begin() override;
+    void update() override;
+    void draw() override;
+
+    void key_pressed(uwe::Scancode scancode, bool repeat) override;
+
+    void mouse_pressed(int x, int y, uwe::Button button) override;
+    void mouse_released(int x, int y, uwe::Button button) override;
+    void mouse_moved(int x, int y) override;
+};
+
+MyApp::MyApp(int width, int height, std::string title): 
+    width_{width},
+    height_{height},
+    colour_index_x_{COLOUR_INDEX_X},
+    colour_index_y_{COLOUR_INDEX_Y},
+    current_colour_{uwe::Colour::black()},
+    sprite_(SPRITE_WIDTH*SPRITE_HEIGHT, uwe::Colour::white()),
+    mouse_down_{false},
+    editor_active_{false},
+    sprite_x_{SPRITE_START_X},
+    sprite_y_{SPRITE_START_Y} {
+        init(width, height, title);
+
+        colour_palate_.push_back(uwe::Colour::white());
+        colour_palate_.push_back(uwe::Colour::green());
+        colour_palate_.push_back(uwe::Colour::blue());
+        colour_palate_.push_back(uwe::Colour::red());
+
+        colour_index_overall_width_ = COLOUR_PALATE_WIDTH * number_colours();
+
+        current_colour_ = colour_palate_[0];
+}
+
+MyApp::~MyApp() {
+
+}
+
+void MyApp::begin() {
+    
+}
+
+void MyApp::update() {
+
+}
+
+void MyApp::key_pressed(uwe::Scancode scancode, bool repeat) {
+    switch (scancode) {
+        // enable framerate dump
+        case uwe::Scancode::L: {
+            toggle_framerate();
+            break;
+        }
+        // switch to editor
+        case uwe::Scancode::D_1: {
+            editor_active_ = false;
+            break;
+        }
+        // switch to scene
+        case uwe::Scancode::D_2: {
+            editor_active_ = true;
+            break;
+        }
+        case uwe::Scancode::LEFT: {
+            if (!editor_active_) {
+                sprite_x_ = sprite_x_ - 2;
+            }
+            break;
+            // TODO: bounds check against window
+        }
+        case uwe::Scancode::RIGHT: {
+            if (!editor_active_) {
+                sprite_x_ = sprite_x_ + 2;
+            }
+            break;
+        }
+        case uwe::Scancode::UP: {
+            if (!editor_active_) {
+                sprite_y_ = sprite_y_ - 4;
+            }
+            break;
+        }
+        case uwe::Scancode::DOWN: {
+            if (!editor_active_) {
+                sprite_y_ = sprite_y_ + 2;
+            }
+            break;
+        }
+        default: {
+            // nothing see here
+        }
+    }
+}
+
+void MyApp::mouse_pressed(int x, int y, uwe::Button button) {
+    if (editor_active_) {
+        size_t hit_index;
+        if (hit_palate(x, y, hit_index)) {
+            current_colour_ = colour_palate_[hit_index];
+        }
+        else if (hit_editor(x, y, hit_index)) {
+            sprite_[hit_index] = current_colour_;
+        }
+    }
+
+    mouse_down_ = true;
+}
+    
+void MyApp::mouse_released(int x, int y, uwe::Button button) {
+    mouse_down_ = false;
+}
+    
+void MyApp::mouse_moved(int x, int y) {
+    size_t hit_index;
+    if (mouse_down_ && hit_editor(x, y, hit_index)) {
+        sprite_[hit_index] = current_colour_;
+    }
+}
+
+void MyApp::draw() {
+    clear(uwe::Colour::black());
+
+    // Below we demostrate the use of both the framebuffer and drawing primitives.
+    clear_framebuffer(uwe::Colour::black());
+
+    if (editor_active_) {
+        // draw sprite as actually seen
+        int i = 0;
+            for (int y = 0; y < SPRITE_HEIGHT; y++) {
+                for (int x = 0; x < SPRITE_WIDTH; x++) {
+                // draw sprite as actually seen
+                set_framebuffer(x + SPRITE_DISPLAY_X, y + SPRITE_DISPLAY_Y, sprite_[i]);
+
+                // draw sprite editor
+                for (int y_times = 0; y_times < SPRITE_EDITOR_PIXELS_HEIGHT; y_times++) {
+                    for (int x_times = 0; x_times < SPRITE_EDITOR_PIXELS_WIDTH; x_times++) {
+                        set_framebuffer(
+                            x*SPRITE_EDITOR_PIXELS_WIDTH + SPRITE_EDITOR_X + x_times, 
+                            y*SPRITE_EDITOR_PIXELS_HEIGHT + SPRITE_EDITOR_Y + y_times, 
+                            sprite_[i]);
+                    }
+                }
+                i++;
+            }
+        }
+
+        blit_framebuffer();
+
+        // draw colour palate
+        for (int i = 0; i < number_colours(); i++) {
+            set_draw_color(colour_palate_[i]);
+            draw_rect_fill(
+                colour_index_x_ + i*COLOUR_PALATE_WIDTH, colour_index_y_, COLOUR_PALATE_WIDTH, COLOUR_PALATE_HEIGHT);
+        }
+
+        // draw current colour
+        set_draw_color(current_colour_);
+        draw_rect_fill(COLOUR_CURRENT_X, COLOUR_CURRENT_Y, COLOUR_PALATE_WIDTH, COLOUR_PALATE_HEIGHT);
+    }
+    else {
+        // draw scene
+        int i = 0;
+        for (int y = 0; y < SPRITE_HEIGHT; y++) {
+            for (int x = 0; x < SPRITE_WIDTH; x++) {
+                // draw sprite as actually seen
+                set_framebuffer(x + sprite_x_, y + sprite_y_, sprite_[i]);
+                i++;
+            }
+        }
+        blit_framebuffer();
+    }
+}
+
+int main(int argc, char *argv[]) {
+    uwe::App* app = new MyApp{width, height, "Sprite Example"};
+    std::cout << "here 2" << std::endl;
+
+    app->run();
+
+    return 0;
+}
\ No newline at end of file
diff --git a/include/app.hpp b/include/app.hpp
index 90e1b2029fef62e201d48dbe431b05247ae1ed8b..3d13b91bc0bb745578f109484fc0cee6e4fdbdd0 100644
--- a/include/app.hpp
+++ b/include/app.hpp
@@ -18,7 +18,7 @@ namespace uwe {
         App();
         ~App();
 
-        void init(int width, int height);
+        void init(int width, int height, std::string title);
         void run();
 
         /// toggles output framerate to console
@@ -38,15 +38,15 @@ namespace uwe {
             
         };
 
-        virtual void mouse_pressed() {
+        virtual void mouse_pressed(int x, int y, Button button) {
 
         };
 
-        virtual void mouse_released() {
+        virtual void mouse_released(int x, int y, Button button) {
             
         };
 
-        virtual void mouse_moved() {
+        virtual void mouse_moved(int x, int y) {
             
         };
 
@@ -64,10 +64,21 @@ namespace uwe {
             return context_.pixel(offset);
         }
 
-        void set_framebuffer(size_t offset, Colour colour) {
+        void set_framebuffer_non_scaled(size_t offset, Colour colour) {
             context_.set_pixel(offset, colour);
         }
 
+        void set_framebuffer(int x, int y, Colour colour) {
+             int offset = x*sizeof(uwe::Colour) + get_framebuffer_width() * sizeof(uwe::Colour) * y;
+             context_.set_pixel(offset, colour);
+        }
+
+        void clear_framebuffer(Colour colour) {
+            for (int offset = 0; offset < get_framebuffer_width() * get_framebuffer_height() * 4; offset++) {
+                context_.set_pixel(offset, colour);
+            }
+        }
+
         void blit_framebuffer() {
             // copy framebuffer pixels to GPU texture for rendering
             SDL_UpdateTexture(
diff --git a/include/context.hpp b/include/context.hpp
index 47856456551d349784dc5e569ca56eeb0e07b4cd..b48cb91255620d4d0b3ccdb2faea3c6f1607c2f8 100644
--- a/include/context.hpp
+++ b/include/context.hpp
@@ -27,6 +27,12 @@ namespace uwe {
             alpha_{alpha} {
         }
 
+        Colour(const Colour& colour) : 
+           red_{colour.red_},
+            green_{colour.green_},
+            blue_{colour.blue_},
+            alpha_{colour.alpha_}  { }
+
         static Colour red() {
             return Colour{ 255, 0, 0, SDL_ALPHA_OPAQUE };
         }
@@ -78,7 +84,7 @@ namespace uwe {
         /// Destory context
         ~Context();
 
-        void init(int width, int height);
+        void init(int width, int height, std::string title);
 
         /// Output details of GPU backend and texture formats
         void dump_renderer_info();
@@ -115,9 +121,9 @@ namespace uwe {
         }
 
         void set_pixel(size_t offset, Colour colour) {
-            pixels_[offset + 0] = colour.red_;
+            pixels_[offset + 0] = colour.blue_;
             pixels_[offset + 1] = colour.green_;
-            pixels_[offset + 2] = colour.blue_;
+            pixels_[offset + 2] = colour.red_;
             pixels_[offset + 3] = colour.alpha_;
         }
 
diff --git a/include/events.hpp b/include/events.hpp
index 328beebfe51a4c0edee35a0b030c6e23d42fd77d..398b8fb08e40f0dd44e047ffb91f4deadf3b73ef 100644
--- a/include/events.hpp
+++ b/include/events.hpp
@@ -68,4 +68,9 @@ namespace uwe {
         RIGHT = SDL_SCANCODE_RIGHT,
     };
 
+    enum class Button {
+        LEFT = SDL_BUTTON_LEFT,
+        RIGHT = SDL_BUTTON_RIGHT,
+    };
+
 } // namespace uwe
\ No newline at end of file
diff --git a/src/app.cpp b/src/app.cpp
index a4dddc903751c29eac72ac94dc4065f45e0d1712..98f8ac9556ac2c485f2f7651745200b18cb78051 100644
--- a/src/app.cpp
+++ b/src/app.cpp
@@ -19,8 +19,8 @@ namespace uwe {
 
     }
 
-    void App::init(int width, int height) {
-        context_.init(width, height);
+    void App::init(int width, int height, std::string title) {
+        context_.init(width, height, title);
     }
 
     void App::run() {
@@ -34,17 +34,34 @@ namespace uwe {
 
         while( running )
         {
-            while( SDL_PollEvent( &event ) ) {
-                if( ( SDL_QUIT == event.type ) ||
-                    ( SDL_KEYDOWN == event.type && SDL_SCANCODE_ESCAPE == event.key.keysym.scancode ) ) {
+            while( SDL_PollEvent( &event ) && running ) {
+                if (event.type == SDL_QUIT || 
+                    (SDL_KEYDOWN == event.type && SDL_SCANCODE_ESCAPE == event.key.keysym.scancode) ) {
                     running = false;
                     break;
                 }
-                else if (event.type == SDL_KEYDOWN) {
-                    key_pressed(static_cast<Scancode>(event.key.keysym.scancode), event.key.repeat != 0);
-                }
-                else if (event.type == SDL_KEYUP) {
-                    key_released(static_cast<Scancode>(event.key.keysym.scancode));
+
+                switch (event.type) {
+                    case SDL_KEYDOWN: {
+                        key_pressed(static_cast<Scancode>(event.key.keysym.scancode), event.key.repeat != 0);
+                        break;
+                    }
+                    case SDL_KEYUP: {
+                        key_released(static_cast<Scancode>(event.key.keysym.scancode));
+                        break;
+                    }
+                    case SDL_MOUSEBUTTONDOWN: {
+                        mouse_pressed(event.button.x, event.button.y, static_cast<Button>(event.button.button));
+                        break;
+                    }
+                    case SDL_MOUSEBUTTONUP: {
+                        mouse_released(event.button.x, event.button.y, static_cast<Button>(event.button.button));
+                        break;
+                    }
+                    case SDL_MOUSEMOTION: {
+                        mouse_moved(event.motion.x, event.motion.y);
+                        break;
+                    }
                 }
             }
 
diff --git a/src/context.cpp b/src/context.cpp
index 10db6da8c7288d8170260181e4dc8a8fd6c77ccc..4fb269e44ac0a8c39853412fd04b4821eba95191 100644
--- a/src/context.cpp
+++ b/src/context.cpp
@@ -8,7 +8,7 @@ namespace uwe {
     Context::Context() {
     } 
 
-    void Context::init(int width, int height) {
+    void Context::init(int width, int height, std::string title) {
         width_ =  width; 
         height_ = height;
         tex_width_ = width;
@@ -22,6 +22,8 @@ namespace uwe {
             width_, height_,
             SDL_WINDOW_SHOWN);
 
+        SDL_SetWindowTitle(window_, title.c_str());
+
         renderer_ = SDL_CreateRenderer(
             window_,
             -1,