diff --git a/.gitignore b/.gitignore
index 735ed65b7c9f1967b928c55fc74971bc91004ca6..4d12e758022acb9340e405129af54f4b796b84ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,10 @@
 *
 !*/
 
+# Ignore build directories generated by default MSVC CMake integration
+# (otherwise causes terribly slow indexing)
+out/
+
 # Allowed top-level files:
 !.clang-format
 !.clang-tidy
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1246145c5dc91b737f09f3f53777ca8f0b240320..be16cc670de3e80f9600a286db8c33f30b317e41 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -32,6 +32,9 @@ current (development)
   reflecting the current scroll position. Proposed by @ibrahimnasson in
   [issue 752](https://github.com/ArthurSonzogni/FTXUI/issues/752)
 
+### Screen
+- Feature: Add `Box::IsEmpty()`.
+
 ### Build
 - Support for cmake's "unity/jumbo" builds. Fixed by @ClausKlein.
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 583ed46a2723070e9ce959e152c6322a3c81d6e4..65f41dbdb448f3c395be6f7a09cfec8e0a4bc4ed 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,11 +33,14 @@ add_library(screen
   include/ftxui/screen/box.hpp
   include/ftxui/screen/color.hpp
   include/ftxui/screen/color_info.hpp
+  include/ftxui/screen/image.hpp
+  include/ftxui/screen/pixel.hpp
   include/ftxui/screen/screen.hpp
   include/ftxui/screen/string.hpp
   src/ftxui/screen/box.cpp
   src/ftxui/screen/color.cpp
   src/ftxui/screen/color_info.cpp
+  src/ftxui/screen/image.cpp
   src/ftxui/screen/screen.cpp
   src/ftxui/screen/string.cpp
   src/ftxui/screen/terminal.cpp
diff --git a/include/ftxui/dom/canvas.hpp b/include/ftxui/dom/canvas.hpp
index 928683807d3bd6bc11ff119c5e17f5488e9c62ba..ffc487c7d4d1c6cdddd722e597bc4d97ad502af2 100644
--- a/include/ftxui/dom/canvas.hpp
+++ b/include/ftxui/dom/canvas.hpp
@@ -10,7 +10,7 @@
 #include <unordered_map>  // for unordered_map
 
 #include "ftxui/screen/color.hpp"   // for Color
-#include "ftxui/screen/screen.hpp"  // for Pixel
+#include "ftxui/screen/image.hpp"   // for Pixel, Image
 
 #ifdef DrawText
 // Workaround for WinUsr.h (via Windows.h) defining macros that break things.
@@ -94,6 +94,12 @@ struct Canvas {
   void DrawText(int x, int y, const std::string& value);
   void DrawText(int x, int y, const std::string& value, const Color& color);
   void DrawText(int x, int y, const std::string& value, const Stylizer& style);
+  
+  // Draw using directly pixels or images --------------------------------------
+  // x is considered to be a multiple of 2.
+  // y is considered to be a multiple of 4.
+  void DrawPixel(int x, int y, const Pixel&);
+  void DrawImage(int x, int y, const Image&);
 
   // Decorator:
   // x is considered to be a multiple of 2.
@@ -104,15 +110,18 @@ struct Canvas {
   bool IsIn(int x, int y) const {
     return x >= 0 && x < width_ && y >= 0 && y < height_;
   }
+
   enum CellType {
-    kBraille,
-    kBlock,
-    kText,
+    kCell,     // Units of size 2x4
+    kBlock,    // Units of size 2x2
+    kBraille,  // Units of size 1x1
   };
+
   struct Cell {
-    CellType type = kText;
+    CellType type = kCell;
     Pixel content;
   };
+
   struct XY {
     int x;
     int y;
diff --git a/include/ftxui/screen/box.hpp b/include/ftxui/screen/box.hpp
index 701b600c2c45491b051985923a2c0f7aee8902df..9fc27921549ae2cae4ef2f293f8da0990f95866b 100644
--- a/include/ftxui/screen/box.hpp
+++ b/include/ftxui/screen/box.hpp
@@ -15,6 +15,7 @@ struct Box {
   static auto Intersection(Box a, Box b) -> Box;
   static auto Union(Box a, Box b) -> Box;
   bool Contain(int x, int y) const;
+  bool IsEmpty();
   bool operator==(const Box& other) const;
   bool operator!=(const Box& other) const;
 };
diff --git a/include/ftxui/screen/image.hpp b/include/ftxui/screen/image.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..1790a9710121809abeecc0ee93538edc90a3509b
--- /dev/null
+++ b/include/ftxui/screen/image.hpp
@@ -0,0 +1,50 @@
+// Copyright 2024 Arthur Sonzogni. All rights reserved.
+// Use of this source code is governed by the MIT license that can be found in
+// the LICENSE file.
+#ifndef FTXUI_SCREEN_IMAGE_HPP
+#define FTXUI_SCREEN_IMAGE_HPP
+
+#include <cstdint>  // for uint8_t
+#include <memory>
+#include <string>  // for string, basic_string, allocator
+#include <vector>  // for vector
+
+#include "ftxui/screen/box.hpp"    // for Box
+#include "ftxui/screen/pixel.hpp"  // for Pixel
+
+namespace ftxui {
+
+/// @brief A rectangular grid of Pixel.
+/// @ingroup screen
+class Image {
+ public:
+  // Constructors:
+  Image() = delete;
+  Image(int dimx, int dimy);
+
+  // Access a character in the grid at a given position.
+  std::string& at(int x, int y);
+  const std::string& at(int x, int y) const;
+
+  // Access a cell (Pixel) in the grid at a given position.
+  Pixel& PixelAt(int x, int y);
+  const Pixel& PixelAt(int x, int y) const;
+
+  // Get screen dimensions.
+  int dimx() const { return dimx_; }
+  int dimy() const { return dimy_; }
+
+  // Fill the image with space and default style
+  void Clear();
+
+  Box stencil;
+
+ protected:
+  int dimx_;
+  int dimy_;
+  std::vector<std::vector<Pixel>> pixels_;
+};
+
+}  // namespace ftxui
+
+#endif  // FTXUI_SCREEN_IMAGE_HPP
diff --git a/include/ftxui/screen/pixel.hpp b/include/ftxui/screen/pixel.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0a58a389802d6bf5f78167691700159eeb8f6621
--- /dev/null
+++ b/include/ftxui/screen/pixel.hpp
@@ -0,0 +1,48 @@
+// Copyright 2024 Arthur Sonzogni. All rights reserved.
+// Use of this source code is governed by the MIT license that can be found in
+// the LICENSE file.
+
+#include <cstdint>                 // for uint8_t
+#include <string>                  // for string, basic_string, allocator
+#include "ftxui/screen/color.hpp"  // for Color, Color::Default
+
+namespace ftxui {
+
+/// @brief A Unicode character and its associated style.
+/// @ingroup screen
+struct Pixel {
+  Pixel()
+      : blink(false),
+        bold(false),
+        dim(false),
+        inverted(false),
+        underlined(false),
+        underlined_double(false),
+        strikethrough(false),
+        automerge(false) {}
+
+  // A bit field representing the style:
+  bool blink : 1;
+  bool bold : 1;
+  bool dim : 1;
+  bool inverted : 1;
+  bool underlined : 1;
+  bool underlined_double : 1;
+  bool strikethrough : 1;
+  bool automerge : 1;
+
+  // The hyperlink associated with the pixel.
+  // 0 is the default value, meaning no hyperlink.
+  // It's an index for accessing Screen meta data
+  uint8_t hyperlink = 0;
+
+  // The graphemes stored into the pixel. To support combining characters,
+  // like: a?, this can potentially contain multiple codepoints.
+  std::string character = " ";
+
+  // Colors:
+  Color background_color = Color::Default;
+  Color foreground_color = Color::Default;
+};
+
+}  // namespace ftxui
diff --git a/include/ftxui/screen/screen.hpp b/include/ftxui/screen/screen.hpp
index 8d27900d148aa893af5ac391bbcbe7a379850ec7..6dd6eedfc52bb22f9bc0fffce1013df1fa276202 100644
--- a/include/ftxui/screen/screen.hpp
+++ b/include/ftxui/screen/screen.hpp
@@ -9,48 +9,12 @@
 #include <string>  // for string, basic_string, allocator
 #include <vector>  // for vector
 
-#include "ftxui/screen/box.hpp"       // for Box
 #include "ftxui/screen/color.hpp"     // for Color, Color::Default
+#include "ftxui/screen/image.hpp"     // for Pixel, Image
 #include "ftxui/screen/terminal.hpp"  // for Dimensions
 
 namespace ftxui {
 
-/// @brief A unicode character and its associated style.
-/// @ingroup screen
-struct Pixel {
-  Pixel()
-      : blink(false),
-        bold(false),
-        dim(false),
-        inverted(false),
-        underlined(false),
-        underlined_double(false),
-        strikethrough(false),
-        automerge(false) {}
-
-  // A bit field representing the style:
-  bool blink : 1;
-  bool bold : 1;
-  bool dim : 1;
-  bool inverted : 1;
-  bool underlined : 1;
-  bool underlined_double : 1;
-  bool strikethrough : 1;
-  bool automerge : 1;
-
-  // The hyperlink associated with the pixel.
-  // 0 is the default value, meaning no hyperlink.
-  uint8_t hyperlink = 0;
-
-  // The graphemes stored into the pixel. To support combining characters,
-  // like: a⃦, this can potentially contain multiple codepoints.
-  std::string character = " ";
-
-  // Colors:
-  Color background_color = Color::Default;
-  Color foreground_color = Color::Default;
-};
-
 /// @brief Define how the Screen's dimensions should look like.
 /// @ingroup screen
 namespace Dimension {
@@ -60,36 +24,24 @@ Dimensions Full();
 
 /// @brief A rectangular grid of Pixel.
 /// @ingroup screen
-class Screen {
+class Screen : public Image {
  public:
   // Constructors:
   Screen(int dimx, int dimy);
   static Screen Create(Dimensions dimension);
   static Screen Create(Dimensions width, Dimensions height);
 
-  // Access a character in the grid at a given position.
-  std::string& at(int x, int y);
-  const std::string& at(int x, int y) const;
-
-  // Access a cell (Pixel) in the grid at a given position.
-  Pixel& PixelAt(int x, int y);
-  const Pixel& PixelAt(int x, int y) const;
-
   std::string ToString() const;
 
   // Print the Screen on to the terminal.
   void Print() const;
 
-  // Get screen dimensions.
-  int dimx() const { return dimx_; }
-  int dimy() const { return dimy_; }
+  // Fill the screen with space and reset any screen state, like hyperlinks, and cursor
+  void Clear();
 
   // Move the terminal cursor n-lines up with n = dimy().
   std::string ResetPosition(bool clear = false) const;
 
-  // Fill the screen with space.
-  void Clear();
-
   void ApplyShader();
 
   struct Cursor {
@@ -107,6 +59,7 @@ class Screen {
     };
     Shape shape;
   };
+
   Cursor cursor() const { return cursor_; }
   void SetCursor(Cursor cursor) { cursor_ = cursor; }
 
@@ -115,12 +68,7 @@ class Screen {
   uint8_t RegisterHyperlink(const std::string& link);
   const std::string& Hyperlink(uint8_t id) const;
 
-  Box stencil;
-
  protected:
-  int dimx_;
-  int dimy_;
-  std::vector<std::vector<Pixel>> pixels_;
   Cursor cursor_;
   std::vector<std::string> hyperlinks_ = {""};
 };
diff --git a/src/ftxui/dom/canvas.cpp b/src/ftxui/dom/canvas.cpp
index 58c24904df4521ece7337331bfd9337a8cf54e63..81d415b03339e03566834070ad38fd262680b200 100644
--- a/src/ftxui/dom/canvas.cpp
+++ b/src/ftxui/dom/canvas.cpp
@@ -810,13 +810,49 @@ void Canvas::DrawText(int x,
       continue;
     }
     Cell& cell = storage_[XY{x / 2, y / 4}];
-    cell.type = CellType::kText;
+    cell.type = CellType::kCell;
     cell.content.character = it;
     style(cell.content);
     x += 2;
   }
 }
 
+/// @brief Directly draw a predefined pixel at the given coordinate
+/// @param x the x coordinate of the pixel.
+/// @param y the y coordinate of the pixel.
+/// @param p the pixel to draw.
+void Canvas::DrawPixel(int x, int y, const Pixel& p) {
+  Cell& cell = storage_[XY{x / 2, y / 4}];
+  cell.type = CellType::kCell;
+  cell.content = p;
+}
+
+/// @brief Draw a predefined image, with top-left corner at the given coordinate
+///   You can supply negative coordinates to align the image however you like - 
+///   only the 'visible' portion will be drawn
+/// @param x the x coordinate corresponding to the top-left corner of the image.
+/// @param y the y coordinate corresponding to the top-left corner of the image.
+/// @param image the image to draw.
+void Canvas::DrawImage(int x, int y, const Image& image) {
+  x /= 2;
+  y /= 4;
+  const int dx_begin = std::max(0, -x);
+  const int dy_begin = std::max(0, -y);
+  const int dx_end = std::min(image.dimx(), width_ - x);
+  const int dy_end = std::min(image.dimy(), height_ - y);
+
+  for (int dy = dy_begin; dy < dy_end; ++dy) {
+    for (int dx = dx_begin; dx < dx_end; ++dx) {
+      Cell& cell = storage_[XY{
+          x + dx,
+          y + dy,
+      }];
+      cell.type = CellType::kCell;
+      cell.content = image.PixelAt(dx, dy);
+    }
+  }
+}
+
 /// @brief Modify a pixel at a given location.
 /// @param style a function that modifies the pixel.
 void Canvas::Style(int x, int y, const Stylizer& style) {
diff --git a/src/ftxui/screen/box.cpp b/src/ftxui/screen/box.cpp
index 38fe484c13ee1d1f886358780ae8e99d2f3169b8..0210153b05e0242a51d9961c82b46f03123a7a70 100644
--- a/src/ftxui/screen/box.cpp
+++ b/src/ftxui/screen/box.cpp
@@ -39,6 +39,12 @@ bool Box::Contain(int x, int y) const {
          y_max >= y;
 }
 
+/// @return whether the box is empty.
+/// @ingroup screen
+bool Box::IsEmpty() {
+  return x_min > x_max || y_min > y_max;
+}
+
 /// @return whether |other| is the same as |this|
 /// @ingroup screen
 bool Box::operator==(const Box& other) const {
diff --git a/src/ftxui/screen/image.cpp b/src/ftxui/screen/image.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..adee91b25638c266d2e8fb7e26dae01cbfea08e8
--- /dev/null
+++ b/src/ftxui/screen/image.cpp
@@ -0,0 +1,68 @@
+// Copyright 2020 Arthur Sonzogni. All rights reserved.
+// Use of this source code is governed by the MIT license that can be found in
+// the LICENSE file.
+#include <cstdint>  // for size_t
+#include <iostream>  // for operator<<, stringstream, basic_ostream, flush, cout, ostream
+#include <limits>
+#include <map>      // for _Rb_tree_const_iterator, map, operator!=, operator==
+#include <memory>   // for allocator, allocator_traits<>::value_type
+#include <sstream>  // IWYU pragma: keep
+#include <utility>  // for pair
+
+#include "ftxui/screen/image.hpp"
+#include "ftxui/screen/string.hpp"    // for string_width
+
+namespace ftxui {
+
+namespace
+{
+   Pixel& dev_null_pixel() {
+      static Pixel pixel;
+      return pixel;
+   }
+}
+
+Image::Image(int dimx, int dimy)
+    : stencil{0, dimx - 1, 0, dimy - 1},
+      dimx_(dimx),
+      dimy_(dimy),
+      pixels_(dimy, std::vector<Pixel>(dimx)) {}
+
+/// @brief Access a character in a cell at a given position.
+/// @param x The cell position along the x-axis.
+/// @param y The cell position along the y-axis.
+std::string& Image::at(int x, int y) {
+  return PixelAt(x, y).character;
+}
+
+/// @brief Access a character in a cell at a given position.
+/// @param x The cell position along the x-axis.
+/// @param y The cell position along the y-axis.
+const std::string& Image::at(int x, int y) const {
+  return PixelAt(x, y).character;
+}
+
+/// @brief Access a cell (Pixel) at a given position.
+/// @param x The cell position along the x-axis.
+/// @param y The cell position along the y-axis.
+Pixel& Image::PixelAt(int x, int y) {
+  return stencil.Contain(x, y) ? pixels_[y][x] : dev_null_pixel();
+}
+
+/// @brief Access a cell (Pixel) at a given position.
+/// @param x The cell position along the x-axis.
+/// @param y The cell position along the y-axis.
+const Pixel& Image::PixelAt(int x, int y) const {
+  return stencil.Contain(x, y) ? pixels_[y][x] : dev_null_pixel();
+}
+
+/// @brief Clear all the pixel from the screen.
+void Image::Clear() {
+  for (auto& line : pixels_) {
+    for (auto& cell : line) {
+      cell = Pixel();
+    }
+  }
+}
+
+}  // namespace ftxui
diff --git a/src/ftxui/screen/screen.cpp b/src/ftxui/screen/screen.cpp
index 2a12219ea3fa55c2f518c1148122cfcf3d27d126..981a3f62a2870aa6b0fcdd3f8a3d517d575f2c90 100644
--- a/src/ftxui/screen/screen.cpp
+++ b/src/ftxui/screen/screen.cpp
@@ -42,11 +42,6 @@ namespace ftxui {
 
 namespace {
 
-Pixel& dev_null_pixel() {
-  static Pixel pixel;
-  return pixel;
-}
-
 #if defined(_WIN32)
 void WindowsEmulateVT100Terminal() {
   static bool done = false;
@@ -392,15 +387,11 @@ Screen Screen::Create(Dimensions dimension) {
   return {dimension.dimx, dimension.dimy};
 }
 
-Screen::Screen(int dimx, int dimy)
-    : stencil{0, dimx - 1, 0, dimy - 1},
-      dimx_(dimx),
-      dimy_(dimy),
-      pixels_(dimy, std::vector<Pixel>(dimx)) {
+Screen::Screen(int dimx, int dimy) : Image{dimx, dimy} {
 #if defined(_WIN32)
   // The placement of this call is a bit weird, however we can assume that
   // anybody who instantiates a Screen object eventually wants to output
-  // something to the console.
+  // something to the console. If that is not the case, use an instance of Image instead.
   // As we require UTF8 for all input/output operations we will just switch to
   // UTF8 encoding here
   SetConsoleOutputCP(CP_UTF8);
@@ -450,34 +441,6 @@ void Screen::Print() const {
   std::cout << ToString() << '\0' << std::flush;
 }
 
-/// @brief Access a character in a cell at a given position.
-/// @param x The cell position along the x-axis.
-/// @param y The cell position along the y-axis.
-std::string& Screen::at(int x, int y) {
-  return PixelAt(x, y).character;
-}
-
-/// @brief Access a character in a cell at a given position.
-/// @param x The cell position along the x-axis.
-/// @param y The cell position along the y-axis.
-const std::string& Screen::at(int x, int y) const {
-  return PixelAt(x, y).character;
-}
-
-/// @brief Access a cell (Pixel) at a given position.
-/// @param x The cell position along the x-axis.
-/// @param y The cell position along the y-axis.
-Pixel& Screen::PixelAt(int x, int y) {
-  return stencil.Contain(x, y) ? pixels_[y][x] : dev_null_pixel();
-}
-
-/// @brief Access a cell (Pixel) at a given position.
-/// @param x The cell position along the x-axis.
-/// @param y The cell position along the y-axis.
-const Pixel& Screen::PixelAt(int x, int y) const {
-  return stencil.Contain(x, y) ? pixels_[y][x] : dev_null_pixel();
-}
-
 /// @brief Return a string to be printed in order to reset the cursor position
 ///        to the beginning of the screen.
 ///
@@ -517,11 +480,8 @@ std::string Screen::ResetPosition(bool clear) const {
 
 /// @brief Clear all the pixel from the screen.
 void Screen::Clear() {
-  for (auto& line : pixels_) {
-    for (auto& cell : line) {
-      cell = Pixel();
-    }
-  }
+  Image::Clear();
+
   cursor_.x = dimx_ - 1;
   cursor_.y = dimy_ - 1;