diff --git a/examples/web/index.css b/examples/web/index.css
index fc4edd1ecb12f0696f93872660a92dae70f8547f..49b3eb97227dd4bcc3afd1bb7aaca88909fea02d 100644
--- a/examples/web/index.css
+++ b/examples/web/index.css
@@ -56,78 +56,6 @@ p {
     text-align: center;
 }
 
-.main > .side-left .canvas-container {
-    max-width: 100%;
-}
-
-.main > .side-left .canvas-container.fullscreen {
-    align-items: center;
-    background-color: #2d2d2d;
-    display: flex;
-    height: 100%;
-    justify-content: center;
-    left: 0px;
-    position: fixed;
-    top: 0px;
-    width: 100%;
-    z-index: 6;
-}
-
-.main > .side-left .canvas-container > .canvas-close {
-    bottom: 22px;
-    display: none;
-    position: absolute;
-    right: 22px;
-    user-select: none;
-    -o-user-select: none;
-    -ms-user-select: none;
-    -moz-user-select: none;
-    -khtml-user-select: none;
-    -webkit-user-select: none;
-}
-
-.main > .side-left .canvas-container > .canvas-close > img {
-    height: 32px;
-    width: 32px;
-}
-
-.main > .side-left .canvas-container.fullscreen > .canvas-close {
-    display: block;
-}
-
-.main > .side-left .canvas-container > .canvas-frame {
-    background-color: #1b1a17;
-    border: 2px solid #50cb93;
-    font-size: 0px;
-    margin-top: 78px;
-    max-width: 320px;
-    padding: 8px 8px 8px 8px;
-}
-
-@media only screen and (max-width: 1120px) {
-    .main > .side-left .canvas-container > .canvas-frame {
-        margin-top: 12px;
-    }
-}
-
-.main > .side-left .canvas-container.fullscreen > .canvas-frame {
-    background-color: transparent;
-    border: none;
-    box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.24);
-    -o-box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.24);
-    -ms-box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.24);
-    -moz-box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.24);
-    -khtml-box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.24);
-    -webkit-box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.24);
-    margin: 0px 0px 0px 0px;
-    max-width: unset;
-    padding: 0px 0px 0px 0px;
-}
-
-.main > .side-left .canvas-container > .canvas-frame > .canvas {
-    width: 100%;
-}
-
 .main > .side-right {
     flex: 0 1;
     max-width: 100%;
diff --git a/examples/web/index.html b/examples/web/index.html
index 3455761548a038a1d338e988d6df3ec6828f6314..5deae36ea921969bc31867fd5aa7fe78fe09685a 100644
--- a/examples/web/index.html
+++ b/examples/web/index.html
@@ -16,14 +16,6 @@
     <div id="app"></div>
     <div class="main">
         <div class="side-left">
-            <div id="canvas-container" class="canvas-container">
-                <span id="canvas-close" class="magnify-button canvas-close">
-                    <img class="large" src="res/minimise.svg" alt="minimise" />
-                </span>
-                <div class="canvas-frame">
-                    <canvas id="engine-canvas" class="canvas" width="320" height="288"></canvas>
-                </div>
-            </div>
         </div>
         <div class="side-right">
             <h1>Boytacean <a id="version" href="https://gitlab.stage.hive.pt/joamag/boytacean/-/blob/master/CHANGELOG.md" target="_blank"></a> <img class="logo-image" src="res/thunder.png" alt="thunder" />
diff --git a/examples/web/index.ts b/examples/web/index.ts
index b680317e63984e8b343a270f32bd0fd06132d9ae..921ce62943a05334228894cf77d5180efa68cf72 100644
--- a/examples/web/index.ts
+++ b/examples/web/index.ts
@@ -78,12 +78,6 @@ class GameboyEmulator extends Observable implements Emulator {
     private timerFrequency: number = TIMER_HZ;
     private idleFrequency: number = IDLE_HZ;
 
-    private canvas: HTMLCanvasElement | null = null;
-    private canvasScaled: HTMLCanvasElement | null = null;
-    private canvasCtx: CanvasRenderingContext2D | null = null;
-    private canvasScaledCtx: CanvasRenderingContext2D | null = null;
-    private image: ImageData | null = null;
-    private videoBuff: DataView | null = null;
     private toastTimeout: number | null = null;
     private paused: boolean = false;
     private nextTickTime: number = 0;
@@ -162,13 +156,10 @@ class GameboyEmulator extends Observable implements Emulator {
                 // system and the machine state (to be able to recover)
                 // also sets the default color on screen to indicate the issue
                 if (isPanic) {
-                    await this.clearCanvas(undefined, {
-                        image: require("./res/storm.png"),
-                        imageScale: 0.2
-                    });
-
                     await wasm();
                     await this.start({ restore: false });
+
+                    this.trigger("error");
                 }
             }
 
@@ -224,12 +215,6 @@ class GameboyEmulator extends Observable implements Emulator {
                 this.gameBoy!.ppu_mode() == PpuMode.VBlank &&
                 this.gameBoy!.ppu_frame() != lastFrame
             ) {
-                // updates the canvas object with the new
-                // visual information coming in
-                this.updateCanvas(
-                    this.gameBoy!.frame_buffer_eager(),
-                    PixelFormat.RGB
-                );
                 lastFrame = this.gameBoy!.ppu_frame();
 
                 // triggers the frame event indicating that
@@ -344,14 +329,13 @@ class GameboyEmulator extends Observable implements Emulator {
             this.registerKeys(),
             this.registerButtons(),
             this.registerKeyboard(),
-            this.registerCanvas(),
             this.registerToast(),
             this.registerModal()
         ]);
     }
 
     async init() {
-        await Promise.all([this.initBase(), this.initCanvas()]);
+        await Promise.all([this.initBase()]);
     }
 
     registerDrop() {
@@ -429,10 +413,6 @@ class GameboyEmulator extends Observable implements Emulator {
                         this.logicFrequency - FREQUENCY_DELTA
                     );
                     break;
-
-                case "Escape":
-                    this.minimize();
-                    break;
             }
         });
 
@@ -511,11 +491,6 @@ class GameboyEmulator extends Observable implements Emulator {
             }
         });
 
-        const buttonFullscreen = document.getElementById("button-fullscreen")!;
-        buttonFullscreen.addEventListener("click", () => {
-            this.maximize();
-        });
-
         const buttonKeyboard = document.getElementById("button-keyboard")!;
         buttonKeyboard.addEventListener("click", () => {
             const sectionKeyboard =
@@ -734,13 +709,6 @@ class GameboyEmulator extends Observable implements Emulator {
         });
     }
 
-    registerCanvas() {
-        const canvasClose = document.getElementById("canvas-close")!;
-        canvasClose.addEventListener("click", () => {
-            this.minimize();
-        });
-    }
-
     registerToast() {
         const toast = document.getElementById("toast")!;
         toast.addEventListener("click", () => {
@@ -775,104 +743,6 @@ class GameboyEmulator extends Observable implements Emulator {
         this.setVersion(info.version);
     }
 
-    async initCanvas() {
-        // initializes the off-screen canvas that is going to be
-        // used in the drawing process
-        this.canvas = document.createElement("canvas");
-        this.canvas.width = DISPLAY_WIDTH;
-        this.canvas.height = DISPLAY_HEIGHT;
-        this.canvasCtx = this.canvas.getContext("2d")!;
-
-        this.canvasScaled = document.getElementById(
-            "engine-canvas"
-        ) as HTMLCanvasElement;
-        this.canvasScaled.width =
-            this.canvasScaled.width * window.devicePixelRatio;
-        this.canvasScaled.height =
-            this.canvasScaled.height * window.devicePixelRatio;
-        this.canvasScaledCtx = this.canvasScaled.getContext("2d")!;
-
-        this.canvasScaledCtx.scale(
-            this.canvasScaled.width / this.canvas.width,
-            this.canvasScaled.height / this.canvas.height
-        );
-        this.canvasScaledCtx.imageSmoothingEnabled = false;
-
-        this.image = this.canvasCtx.createImageData(
-            this.canvas.width,
-            this.canvas.height
-        );
-        this.videoBuff = new DataView(this.image.data.buffer);
-    }
-
-    updateCanvas(pixels: Uint8Array, format: PixelFormat = PixelFormat.RGB) {
-        let offset = 0;
-        for (let index = 0; index < pixels.length; index += format) {
-            const color =
-                (pixels[index] << 24) |
-                (pixels[index + 1] << 16) |
-                (pixels[index + 2] << 8) |
-                (format == PixelFormat.RGBA ? pixels[index + 3] : 0xff);
-            this.videoBuff!.setUint32(offset, color);
-            offset += PixelFormat.RGBA;
-        }
-        this.canvasCtx!.putImageData(this.image!, 0, 0);
-        this.canvasScaledCtx!.drawImage(this.canvas!, 0, 0);
-    }
-
-    async clearCanvas(
-        color = PIXEL_UNSET_COLOR,
-        {
-            image = null,
-            imageScale = 1
-        }: { image?: string | null; imageScale?: number } = {}
-    ) {
-        this.canvasScaledCtx!.fillStyle = `#${color
-            .toString(16)
-            .toUpperCase()}`;
-        this.canvasScaledCtx!.fillRect(
-            0,
-            0,
-            this.canvasScaled!.width,
-            this.canvasScaled!.height
-        );
-
-        // in case an image was requested then uses that to load
-        // an image at the center of the screen properly scaled
-        if (image) {
-            const img = await new Promise<HTMLImageElement>((resolve) => {
-                const img = new Image();
-                img.onload = () => {
-                    resolve(img);
-                };
-                img.src = image;
-            });
-            const [imgWidth, imgHeight] = [
-                img.width * imageScale * window.devicePixelRatio,
-                img.height * imageScale * window.devicePixelRatio
-            ];
-            const [x0, y0] = [
-                this.canvasScaled!.width / 2 - imgWidth / 2,
-                this.canvasScaled!.height / 2 - imgHeight / 2
-            ];
-            this.canvasScaledCtx!.setTransform(1, 0, 0, 1, 0, 0);
-            try {
-                this.canvasScaledCtx!.drawImage(
-                    img,
-                    x0,
-                    y0,
-                    imgWidth,
-                    imgHeight
-                );
-            } finally {
-                this.canvasScaledCtx!.scale(
-                    this.canvasScaled!.width / this.canvas!.width,
-                    this.canvasScaled!.height / this.canvas!.height
-                );
-            }
-        }
-    }
-
     async showToast(message: string, error = false, timeout = 3500) {
         const toast = document.getElementById("toast")!;
         toast.classList.remove("error");
@@ -1015,60 +885,6 @@ class GameboyEmulator extends Observable implements Emulator {
         this.start({ engine: null });
     }
 
-    toggleWindow() {
-        this.maximize();
-    }
-
-    /**
-     * Maximizes the emulator's viewport taking up all the available
-     * window space. This method is responsible for keeping the aspect
-     * ratio of the emulator canvas according to the width/height ratio.
-     */
-    maximize() {
-        const canvasContainer = document.getElementById("canvas-container")!;
-        canvasContainer.classList.add("fullscreen");
-
-        window.addEventListener("resize", this.crop);
-
-        this.crop();
-    }
-
-    /**
-     * Restore the emulator's viewport to the minimal size, should make all
-     * the other emulator's meta-information (info, buttons, etc.) visible.
-     */
-    minimize() {
-        const canvasContainer = document.getElementById("canvas-container")!;
-        const engineCanvas = document.getElementById("engine-canvas")!;
-        canvasContainer.classList.remove("fullscreen");
-        engineCanvas.style.width = "";
-        engineCanvas.style.height = "";
-        window.removeEventListener("resize", this.crop);
-    }
-
-    crop() {
-        // @todo let's make this more flexible
-        const engineCanvas = document.getElementById("engine-canvas")!;
-
-        // calculates the window ratio as this is fundamental to
-        // determine the proper way to crop the fullscreen
-        const windowRatio = window.innerWidth / window.innerHeight;
-
-        // in case the window is wider (more horizontal than the base ratio)
-        // this means that we must crop horizontally
-        if (windowRatio > DISPLAY_RATIO) {
-            engineCanvas.style.width = `${
-                window.innerWidth * (DISPLAY_RATIO / windowRatio)
-            }px`;
-            engineCanvas.style.height = `${window.innerHeight}px`;
-        } else {
-            engineCanvas.style.width = `${window.innerWidth}px`;
-            engineCanvas.style.height = `${
-                window.innerHeight * (windowRatio / DISPLAY_RATIO)
-            }px`;
-        }
-    }
-
     async fetchRom(romPath: string): Promise<[string, Uint8Array]> {
         // extracts the name of the ROM from the provided
         // path by splitting its structure
diff --git a/examples/web/react/app.tsx b/examples/web/react/app.tsx
index 8bc482f37cae54eb4d05e9bbbfae7f2c9b037fe6..bd91cb759d0a78e710f198215864e22178087f48 100644
--- a/examples/web/react/app.tsx
+++ b/examples/web/react/app.tsx
@@ -8,6 +8,7 @@ import {
     ButtonContainer,
     ButtonIncrement,
     ButtonSwitch,
+    ClearHandler,
     Display,
     DrawHandler,
     Footer,
@@ -98,6 +99,7 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
     const [romInfo, setRomInfo] = useState<RomInfo>({});
     const [framerate, setFramerate] = useState(0);
     const frameRef = useRef<boolean>(false);
+    const errorRef = useRef<boolean>(false);
     const getPauseText = () => (paused ? "Resume" : "Pause");
     const getPauseIcon = () =>
         paused ? require("../res/play.svg") : require("../res/pause.svg");
@@ -126,6 +128,13 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
             setFramerate(emulator.getFramerate());
         });
     };
+    const onClearHandler = (handler: ClearHandler) => {
+        if (errorRef.current) return;
+        errorRef.current = true;
+        emulator.bind("error", async () => {
+            await handler(undefined, require("../res/storm.png"), 0.2);
+        });
+    };
     useEffect(() => {
         document.body.style.backgroundColor = `#${getBackground()}`;
     });
@@ -133,6 +142,13 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
         document.addEventListener("keydown", (event) => {
             if (event.key === "Escape") {
                 setFullscreen(false);
+                event.stopPropagation();
+                event.preventDefault();
+            }
+            if (event.key === "f" && event.ctrlKey === true) {
+                setFullscreen(true);
+                event.stopPropagation();
+                event.preventDefault();
             }
         });
         emulator.bind("loaded", () => {
@@ -154,6 +170,7 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
                         <Display
                             fullscreen={fullscreen}
                             onDrawHandler={onDrawHandler}
+                            onClearHandler={onClearHandler}
                             onMinimize={onMinimize}
                         />
                     </div>
diff --git a/examples/web/react/components/display/display.tsx b/examples/web/react/components/display/display.tsx
index aac3b51ec94e9468b13ae7fb382cdf9ff319b569..f8457f296f2a2ed86e5fe5767963faa03aa8638f 100644
--- a/examples/web/react/components/display/display.tsx
+++ b/examples/web/react/components/display/display.tsx
@@ -3,6 +3,8 @@ import { PixelFormat } from "../../app";
 
 import "./display.css";
 
+const PIXEL_UNSET_COLOR = 0x1b1a17ff;
+
 declare const require: any;
 
 /**
@@ -11,6 +13,12 @@ declare const require: any;
  */
 export type DrawHandler = (pixels: Uint8Array, format: PixelFormat) => void;
 
+export type ClearHandler = (
+    color?: number,
+    image?: string,
+    imageScale?: number
+) => Promise<void>;
+
 type DisplayOptions = {
     width: number;
     height: number;
@@ -25,10 +33,12 @@ type DisplayProps = {
     fullscreen?: boolean;
     style?: string[];
     onDrawHandler?: (caller: DrawHandler) => void;
+    onClearHandler?: (caller: ClearHandler) => void;
     onMinimize?: () => void;
 };
 
 type CanvasContents = {
+    canvas: HTMLCanvasElement;
     canvasCtx: CanvasRenderingContext2D;
     canvasBuffer: HTMLCanvasElement;
     canvasBufferCtx: CanvasRenderingContext2D;
@@ -42,6 +52,7 @@ export const Display: FC<DisplayProps> = ({
     fullscreen = false,
     style = [],
     onDrawHandler,
+    onClearHandler,
     onMinimize
 }) => {
     options = {
@@ -88,12 +99,22 @@ export const Display: FC<DisplayProps> = ({
     }, [canvasRef, fullscreen]);
 
     if (onDrawHandler) {
-        onDrawHandler((pixels: Uint8Array, format: PixelFormat) => {
+        onDrawHandler((pixels, format) => {
             if (!canvasContentsRef.current) return;
             updateCanvas(canvasContentsRef.current, pixels, format);
         });
     }
 
+    if (onClearHandler) {
+        onClearHandler(async (color, image, imageScale) => {
+            if (!canvasContentsRef.current) return;
+            await clearCanvas(canvasContentsRef.current, color, {
+                image: image,
+                imageScale: imageScale
+            });
+        });
+    }
+
     return (
         <div id="display" className={classes()}>
             <span
@@ -151,6 +172,7 @@ const initCanvas = (
     canvasCtx.imageSmoothingEnabled = false;
 
     return {
+        canvas: canvas,
         canvasCtx: canvasCtx,
         canvasBuffer: canvasBuffer,
         canvasBufferCtx: canvasBufferCtx,
@@ -178,6 +200,62 @@ const updateCanvas = (
     canvasContents.canvasCtx.drawImage(canvasContents.canvasBuffer, 0, 0);
 };
 
+const clearCanvas = async (
+    canvasContents: CanvasContents,
+    color = PIXEL_UNSET_COLOR,
+    {
+        image = null,
+        imageScale = 1
+    }: { image?: string | null; imageScale?: number } = {}
+) => {
+    // uses the "clear" color to fill a rectangle with the complete
+    // size of the canvas contents
+    canvasContents.canvasCtx.fillStyle = `#${color.toString(16).toUpperCase()}`;
+    canvasContents.canvasCtx.fillRect(
+        0,
+        0,
+        canvasContents.canvas.width,
+        canvasContents.canvas.height
+    );
+
+    // in case an image was requested then uses that to load
+    // an image at the center of the screen properly scaled
+    if (image) {
+        await drawImageCanvas(canvasContents, image, imageScale);
+    }
+};
+
+const drawImageCanvas = async (
+    canvasContents: CanvasContents,
+    image: string,
+    imageScale = 1.0
+) => {
+    const img = await new Promise<HTMLImageElement>((resolve) => {
+        const img = new Image();
+        img.onload = () => {
+            resolve(img);
+        };
+        img.src = image;
+    });
+    const [imgWidth, imgHeight] = [
+        img.width * imageScale * window.devicePixelRatio,
+        img.height * imageScale * window.devicePixelRatio
+    ];
+    const [x0, y0] = [
+        canvasContents.canvas.width / 2 - imgWidth / 2,
+        canvasContents.canvas.height / 2 - imgHeight / 2
+    ];
+    canvasContents.canvasCtx.setTransform(1, 0, 0, 1, 0, 0);
+    try {
+        canvasContents.canvasCtx.drawImage(img, x0, y0, imgWidth, imgHeight);
+    } finally {
+        canvasContents.canvasCtx.scale(
+            canvasContents.canvas.width / canvasContents.canvasBuffer.width,
+            canvasContents.canvas.height / canvasContents.canvasBuffer.height
+        );
+    }
+};
+
 const crop = (ratio: number): [number, number] => {
     // calculates the window ratio as this is fundamental to
     // determine the proper way to crop the fullscreen