diff --git a/README.md b/README.md
index 023da2c..1c7f548 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ __[BUILD OPTIONS](/doc/BuildOptions.md) | [EXAMPLES](/examples/README.md)__ | [!
 # Introduction
 * This is an ESP32 Arduino/IDF library for HUB75 / HUB75E connection based RGB LED panels. 
 * This library 'out of the box' (mostly) supports HUB75 panels where simple TWO rows/lines are updated in parallel... referred to as 'two scan' panels within this documentation. 
-* 'Four scan' panels are also supported - but please refer to the Four Scan Panel example sketch.
+* 1/4 (aka. 'Four Scan') outdoor panels are also supported - but please refer to the VirtualMatrixPanel example.
 * The library uses the DMA functionality provided by the ESP32's 'LCD Mode' for fast data output.
 
 ## Features
diff --git a/doc/VirtualMatrixPanel (old).odp b/doc/VirtualMatrixPanel (old).odp
deleted file mode 100644
index 4e3a066..0000000
Binary files a/doc/VirtualMatrixPanel (old).odp and /dev/null differ
diff --git a/doc/VirtualMatrixPanel.odp b/doc/VirtualMatrixPanel.odp
index c9ce91f..ecb226f 100644
Binary files a/doc/VirtualMatrixPanel.odp and b/doc/VirtualMatrixPanel.odp differ
diff --git a/doc/VirtualMatrixPanel.pdf b/doc/VirtualMatrixPanel.pdf
index f6e7157..b8cd845 100644
Binary files a/doc/VirtualMatrixPanel.pdf and b/doc/VirtualMatrixPanel.pdf differ
diff --git a/examples/Four_Scan_Panel/Four_Scan_Panel.ino b/examples/Four_Scan_Panel/Four_Scan_Panel.ino
deleted file mode 100644
index 5086b62..0000000
--- a/examples/Four_Scan_Panel/Four_Scan_Panel.ino
+++ /dev/null
@@ -1,153 +0,0 @@
-/*************************************************************************
- * Description: 
- * 
- * The underlying implementation of the ESP32-HUB75-MatrixPanel-I2S-DMA only
- * supports output to HALF scan panels - which means outputting 
- * two lines at the same time, 16 or 32 rows apart if a 32px or 64px high panel
- * respectively. 
- * This cannot be changed at the DMA layer as it would require a messy and complex 
- * rebuild of the library's internals.
- *
- * However, it is possible to connect QUARTER (i.e. FOUR lines updated in parallel)
- * scan panels to this same library and
- * 'trick' the output to work correctly on these panels by way of adjusting the
- * pixel co-ordinates that are 'sent' to the ESP32-HUB75-MatrixPanel-I2S-DMA
- * library.
- * 
- **************************************************************************/
-#include "ESP32-HUB75-MatrixPanel-I2S-DMA.h"
-
-/* Use the Virtual Display class to re-map co-ordinates such that they draw 
- * correctly on a 32x16 1/8 Scan panel (or chain of such panels).
- */
-#include "ESP32-VirtualMatrixPanel-I2S-DMA.h" 
-
-
-  // Panel configuration
-  #define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module. 
-  #define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
-  
-  
-  #define NUM_ROWS 1 // Number of rows of chained INDIVIDUAL PANELS
-  #define NUM_COLS 2 // Number of INDIVIDUAL PANELS per ROW
-  
-  // ^^^ NOTE: DEFAULT EXAMPLE SETUP IS FOR A CHAIN OF TWO x 1/8 SCAN PANELS
-    
-  // Change this to your needs, for details on VirtualPanel pls read the PDF!
-  #define SERPENT true
-  #define TOPDOWN false
-  
-  // placeholder for the matrix object
-  MatrixPanel_I2S_DMA *dma_display = nullptr;
-
-  // placeholder for the virtual display object
-  VirtualMatrixPanel  *FourScanPanel = nullptr;
-  
-  /******************************************************************************
-   * Setup!
-   ******************************************************************************/
-  void setup()
-  {
-    delay(250);
-   
-    Serial.begin(115200);
-    Serial.println(""); Serial.println(""); Serial.println("");
-    Serial.println("*****************************************************");
-    Serial.println("*         1/8 Scan Panel Demonstration              *");
-    Serial.println("*****************************************************");
-  
-/* 
-     // 62x32 1/8 Scan Panels don't have a D and E pin!
-     
-     HUB75_I2S_CFG::i2s_pins _pins = {
-      R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, 
-      A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, 
-      LAT_PIN, OE_PIN, CLK_PIN
-     };
-*/
-    HUB75_I2S_CFG mxconfig(
-                PANEL_RES_X*2,              // DO NOT CHANGE THIS
-                PANEL_RES_Y/2,              // DO NOT CHANGE THIS
-                NUM_ROWS*NUM_COLS           // DO NOT CHANGE THIS
-                //,_pins            // Uncomment to enable custom pins
-    );
-    
-    mxconfig.clkphase = false; // Change this if you see pixels showing up shifted wrongly by one column the left or right.
-    
-    //mxconfig.driver   = HUB75_I2S_CFG::FM6126A;     // in case that we use panels based on FM6126A chip, we can set it here before creating MatrixPanel_I2S_DMA object
-  
-    // OK, now we can create our matrix object
-    dma_display = new MatrixPanel_I2S_DMA(mxconfig);
-  
-    // let's adjust default brightness to about 75%
-    dma_display->setBrightness8(96);    // range is 0-255, 0 - 0%, 255 - 100%
-  
-    // Allocate memory and start DMA display
-    if( not dma_display->begin() )
-      Serial.println("****** !KABOOM! I2S memory allocation failed ***********");
-
-   
-    dma_display->clearScreen();
-    delay(500);
-    
-    // create FourScanPanellay object based on our newly created dma_display object
-    FourScanPanel = new VirtualMatrixPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y);
-    
-	// THE IMPORTANT BIT BELOW!
-    FourScanPanel->setPhysicalPanelScanRate(FOUR_SCAN_32PX_HIGH);
-  }
-
-  
-  void loop() {
-
-      // What the panel sees from the DMA engine!
-      for (int i=PANEL_RES_X*2+10; i< PANEL_RES_X*(NUM_ROWS*NUM_COLS)*2; i++)
-      {
-        dma_display->drawLine(i, 0, i, 7, dma_display->color565(255, 0, 0)); // red
-        delay(10);
-      }
-          
-      dma_display->clearScreen();
-      delay(1000);
-/*
-      // Try again using the pixel / dma memory remapper
-      for (int i=PANEL_RES_X+5; i< (PANEL_RES_X*2)-1; i++)
-      {
-        FourScanPanel->drawLine(i, 0, i, 7, dma_display->color565(0, 0, 255)); // blue    
-        delay(10);
-      } 
-*/
-
-      // Try again using the pixel / dma memory remapper
-      int offset = PANEL_RES_X*((NUM_ROWS*NUM_COLS)-1);
-      for (int i=0; i< PANEL_RES_X; i++)
-      {
-        FourScanPanel->drawLine(i+offset, 0, i+offset, 7, dma_display->color565(0, 0, 255)); // blue
-        FourScanPanel->drawLine(i+offset, 8, i+offset, 15, dma_display->color565(0, 128,0)); // g        
-        FourScanPanel->drawLine(i+offset, 16, i+offset, 23, dma_display->color565(128, 0,0)); // red
-        FourScanPanel->drawLine(i+offset, 24, i+offset, 31, dma_display->color565(0, 128, 128)); // blue        
-        delay(10);
-      } 
-
-      delay(1000);
-
-
-      // Print on each chained panel 1/8 module!
-      // This only really works for a single horizontal chain
-      for (int i = 0; i < NUM_ROWS*NUM_COLS; i++)
-      {
-        FourScanPanel->setTextColor(FourScanPanel->color565(255, 255, 255));
-        FourScanPanel->setCursor(i*PANEL_RES_X+7, FourScanPanel->height()/3); 
-      
-        // Red text inside red rect (2 pix in from edge)
-        FourScanPanel->print("Panel " + String(i+1));
-        FourScanPanel->drawRect(1,1, FourScanPanel->width()-2, FourScanPanel->height()-2, FourScanPanel->color565(255,0,0));
-      
-        // White line from top left to bottom right
-        FourScanPanel->drawLine(0,0, FourScanPanel->width()-1, FourScanPanel->height()-1, FourScanPanel->color565(255,255,255));
-      }
-
-      delay(2000);
-      dma_display->clearScreen();
-  
-  } // end loop
diff --git a/examples/Four_Scan_Panel/README.md b/examples/Four_Scan_Panel/README.md
deleted file mode 100644
index dd75176..0000000
--- a/examples/Four_Scan_Panel/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Using this library with 32x16 1/4 Scan Panels
-
-## Problem
-ESP32-HUB75-MatrixPanel-I2S-DMA library will not display output correctly with 'Four Scan' 64x32 1/8 or 32x16 1/4 scan panels such [as this](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/154) by default.
-
-## Solution
-It is possible to connect 1/8 scan panels to this library and 'trick' the output to work correctly on these panels by way of adjusting the pixel co-ordinates that are 'sent' to the underlying ESP32-HUB75-MatrixPanel-I2S-DMA library (in this example, it is the 'dmaOutput' class).
diff --git a/examples/VirtualMatrixPanel/README.md b/examples/VirtualMatrixPanel/README.md
index c5aca88..7012f3f 100644
--- a/examples/VirtualMatrixPanel/README.md
+++ b/examples/VirtualMatrixPanel/README.md
@@ -1,4 +1,9 @@
-## Chained Panels example - Chaining individual LED matrix panels to make a larger panel ##
+# The 'VirtualMatrixPanel_T' class
+The `VirtualMatrixPanel_T` is used to perform pixel re-mapping in order to support the following use-cases that can be used together:
+1. To create a larger display based on a chain of individual physical panels connected electrically in a Serpentine or Zig-Zag manner.
+2. To provide support for physical panels with non-standard (i.e. Not a 1/2 scan panel) pixel mapping approaches. This is often seen with 1/4 scan outdoor panels.
+
+## 1. Chaining individual LED matrix panels to make a larger virtual display ##
 
 This is the PatternPlasma Demo adopted for use with multiple LED Matrix Panel displays arranged in a non standard order (i.e. a grid) to make a bigger display.
 
@@ -19,33 +24,34 @@ For example: You bought four (4) 64x32px panels, and wanted to use them to creat
 
 1. [Refer to this document](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/blob/master/doc/VirtualMatrixPanel.pdf) for an explanation and refer to this example on how to use.
 
-2. In your Arduino sketch, configure these defines accordingly:
+2. Read the `VirtualMatrixPanel.ino` code
+
+## 2. Using this library with 1/4 Scan Panels (Four Scan)
+
+This library does not natively support 'Four Scan' 64x32 1/8 or 32x16 1/4 scan panels such [as this](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/154) by default.
+
+### Solution
+Read the `VirtualMatrixPanel.ino` code. 
+
+The VirtualMatrixPanel_T class provides a way to additionally remap pixel for each individual panel by way of the `ScanTypeMapping` class.
+
+You can create your own custom per-panel pixel mapping class as well should you wish.
+
+```cpp
+// --- Example 3: Single non-standard 1/4 Scan (Four-Scan 1/8) ---
+
+// Use an existing library user-contributed Scan Type pixel mapping
+using MyScanTypeMapping = ScanTypeMapping<FOUR_SCAN_32PX_HIGH>;
+
+// Create a pointer to the specific instantiation of the VirtualMatrixPanel_T class
+VirtualMatrixPanel_T<CHAIN_NONE, MyScanTypeMapping>* virtualDisp = nullptr;
 ```
-#define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module. 
-#define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module.
 
-#define NUM_ROWS 2 // Number of rows of chained INDIVIDUAL PANELS
-#define NUM_COLS 2 // Number of INDIVIDUAL PANELS per ROW
+The library has these user-contributed additions, but given the variety of panels on the market, your success with any of these may vary.
 
-#define PANEL_CHAIN NUM_ROWS*NUM_COLS    // total number of panels chained one to another
-
-#define VIRTUAL_MATRIX_CHAIN_TYPE <INSERT CHAINING TYPE HERE - Refer to documentation or example>
-	
-```
-VIRTUAL_MATRIX_CHAIN_TYPE's:
-![image](https://user-images.githubusercontent.com/12006953/224537356-e3c8e87b-0bc0-4185-8f5d-d2d3b328d176.png)
-
-
-3. In your Arduino sketch, use the 'VirtualMatrixPanel' class instance (virtualDisp) to draw to the display (i.e. drawPixel), instead of the underling MatrixPanel_I2S_DMA class instance (dma_display).
-
-
-#### Thanks to ####
-* Brian Lough for the Virtual to Real pixel co-ordinate code.
-
-YouTube: https://www.youtube.com/brianlough
-
-Tindie: https://www.tindie.com/stores/brianlough/
-
-Twitter: https://twitter.com/witnessmenow
-
-* Galaxy-Man for the donation of hardware for testing.
+```cpp
+    FOUR_SCAN_32PX_HIGH,   ///< Four-scan mode, 32-pixel high panels.
+    FOUR_SCAN_16PX_HIGH,   ///< Four-scan mode, 16-pixel high panels.
+    FOUR_SCAN_64PX_HIGH,   ///< Four-scan mode, 64-pixel high panels.
+    FOUR_SCAN_40PX_HIGH    ///< Four-scan mode, 40-pixel high panels.
+```
\ No newline at end of file
diff --git a/src/ESP32-HUB75-VirtualMatrixPanel_T.hpp b/src/ESP32-HUB75-VirtualMatrixPanel_T.hpp
index 5936cb6..089bc06 100644
--- a/src/ESP32-HUB75-VirtualMatrixPanel_T.hpp
+++ b/src/ESP32-HUB75-VirtualMatrixPanel_T.hpp
@@ -39,10 +39,8 @@
 
 #ifdef USE_GFX_LITE
   #include "GFX_Lite.h"
-//  #include <Fonts/FreeSansBold12pt7b.h>
 #elif !defined(NO_GFX)
   #include "Adafruit_GFX.h"
-//  #include <Fonts/FreeSansBold12pt7b.h>
 #endif
 
 // ----------------------------------------------------------------------
@@ -273,14 +271,40 @@ public:
       //  this->setFont(&FreeSansBold12pt7b);
         this->setTextColor(display->color565(255, 255, 0));
      //   this->setTextSize(1);
-        for (int panel = 0; panel < vmodule_cols * vmodule_rows; panel++) {
-            int top_left_x = (panel == 0) ? 0 : (panel * panel_res_x);
-            this->drawRect(top_left_x, 0, panel_res_x, panel_res_y, this->color565(0, 255, 0));
-            this->setCursor((panel * panel_res_x) + 2, panel_res_y - 10);
-            this->print((vmodule_cols * vmodule_rows) - panel);
+        for (int col = 0; col < vmodule_cols; col++) {
+            for (int row = 0; row < vmodule_rows; row++) {
+
+                int start_x = col * panel_res_x;
+                int start_y = row * panel_res_y;
+
+                int panel_id = col + (row * vmodule_cols) + 1;
+                //int top_left_x = panel * panel_res_x;
+                this->drawRect(start_x, start_y, panel_res_x, panel_res_y, this->color565(0, 255, 0));
+                this->setCursor(start_x + panel_res_x/2 - 2, start_y + panel_res_y/2 - 4);
+                this->print(panel_id);
+
+                log_d("drawDisplayTest() Panel: %d, start_x: %d, start_y: %d", panel_id, start_x, start_y);
+            }
         }  
         
     }
+
+    inline void drawDisplayTestDMA()
+    {
+        // Write to the underlying panels only via the dma_display instance.
+        // This only works on standard panels with a linear mapping (i.e. two-scan).
+        this->display->setTextColor(this->display->color565(255, 255, 0));
+        this->display->setTextSize(1);
+    
+        for (int panel = 0; panel < vmodule_cols * vmodule_rows; panel++)
+        {
+            int top_left_x = panel * panel_res_x;
+            this->display->drawRect(top_left_x, 0, panel_res_x, panel_res_y, this->display->color565(0, 255, 0));
+            this->display->setCursor((panel * panel_res_x) + 6, panel_res_y - 12);
+            this->display->print((vmodule_cols * vmodule_rows) - panel);
+        }
+    }
+
 #endif
 
     inline void clearScreen() { display->clearScreen(); }
@@ -427,16 +451,11 @@ public:
             coords.y = virt_y;
         }
 
-        //log_d("calcCoords post-chain: virt_x: %d, virt_y: %d", virt_x, virt_y);    
+        //log_d("calcCoords post-chain: virt_x: %d, virt_y: %d", virt_x, virt_y);  
 
-        if constexpr (ScanTypeMapping != STANDARD_TWO_SCAN) {
+        // --- Apply physical LED panel scan–type mapping / fix ---
+        coords = ScanTypeMapping::apply(coords, virt_y, panel_pixel_base);
 
-            // --- Apply physical LED panel scan–type mapping / fix ---
-            coords = ScanTypeMapping::apply(coords, virt_y, panel_pixel_base);
-
-        }
-
-        //return coords;
     }
 
 #ifdef NO_GFX