URI:
       Merge pull request #13 from Lana-chan/refactor - webgbcam - [fork] gameboy webcam
  HTML git clone git://src.adamsgaard.dk/webgbcam
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 6c7d243f939fe3b2e0712f3d5576dd77d7974ee3
   DIR parent 3044c6ce014f3bccd7acf3ac57d2cebf1e6c86e5
  HTML Author: Erin Pinheiro <Lana-chan@users.noreply.github.com>
       Date:   Mon,  6 Nov 2023 23:12:20 +0000
       
       Merge pull request #13 from Lana-chan/refactor
       
       Add 1bpp mode
       Diffstat:
         M .gitignore                          |       7 +++++--
         M app.js                              |     569 ++++++++++++++++++++-----------
         M index.html                          |       2 +-
         M sw.js                               |       4 ++--
         M ui/ui-settings.png                  |       0 
       
       5 files changed, 373 insertions(+), 209 deletions(-)
       ---
   DIR diff --git a/.gitignore b/.gitignore
       @@ -1,2 +1,5 @@
        *.aseprite
       -todo.txt
       -\ No newline at end of file
       +todo.txt
       +key.pem
       +server.pem
       +simple-https-server.py
       +\ No newline at end of file
   DIR diff --git a/app.js b/app.js
       @@ -236,12 +236,6 @@ const cameraStream = document.querySelector("#camera-stream"),
                                cameraOutput = document.querySelector("#camera-output"),
                                cameraDiv = document.querySelector("#camera"),
                                appView = document.querySelector("#app-view"),
       -                        uiMain = document.querySelector("#ui-main"),
       -                        uiCapture = document.querySelector("#ui-capture"),
       -                        uiSettings = document.querySelector("#ui-settings"),
       -                        uiHidden = document.querySelector("#ui-hidden"),
       -                        uiTimer = document.querySelector("#ui-timer"),
       -                        uiRecord = document.querySelector("#ui-record"),
                                gifPreview = document.querySelector("#gif-preview"),
                                gifImg = document.querySelector("#gif-img"),
                                gifButtons = document.querySelector("#gif-buttons");
       @@ -250,31 +244,12 @@ var currentFacingMode = 'user';
        var appScale;
        var frameDrawing;
        const gifLength = 50;
       -const outputScale = 5;
       +var outputScale = 6;
        var gifRecording,
                        gifEncoder,
                        gifFrames,
                        gifBlob;
        
       -// global settings for gbcamera
       -var renderWidth = 160,
       -                renderHeight = 144,
       -                currentPalette = 0,
       -                currentUI = uiMain;
       -
       -var cameraVars = {
       -        width: 128,
       -        height: 112,
       -        dither: 0.6,
       -        contrast: 3,
       -        gamma: 3,
       -        sharpness: 3,
       -        xOffset: 0,
       -        yOffset: 0,
       -        xScale: 1,
       -        yScale: 1
       -};
       -
        const sliderGamma = [
                2.5,
                2,
       @@ -319,88 +294,6 @@ const bayer8 = [
        
        const clampNumber = (num, a, b) => Math.min(Math.max(num, a), b);
        
       -// function to check if phone is portrait oriented
       -function screenIsPortrait() {
       -        try {
       -                let orientation = (screen.orientation || {}).type || screen.mozOrientation || screen.msOrientation;
       -                if(orientation != undefined) {
       -                        if(orientation.includes('portrait')) return true;
       -                } else if(window.orientation != undefined) {
       -                        if(window.orientation == 0) return true;
       -                }
       -                return false;
       -        } catch(e) {
       -                return false;
       -        }
       -}
       -
       -//Function to get the mouse position
       -function getMousePos(canvas, event) {
       -        var rect = canvas.getBoundingClientRect();
       -        return {
       -                        x: (event.clientX - rect.left) / appScale,
       -                        y: (event.clientY - rect.top) / appScale
       -        };
       -}
       -//Function to check whether a point is inside a rectangle
       -function isInside(pos, rect){
       -        return pos.x > rect.x && pos.x < rect.x+rect.width && pos.y < rect.y+rect.height && pos.y > rect.y
       -}
       -
       -function switchCameras() {
       -        if(amountOfCameras > 1) {
       -                if (currentFacingMode === 'environment') currentFacingMode = 'user';
       -                else currentFacingMode = 'environment';
       -                initCameraStream();
       -        }
       -}
       -
       -function download(filename, content) {
       -        var element = document.createElement('a');
       -        element.setAttribute('href', content);
       -        element.setAttribute('download', filename);
       -
       -        element.style.display = 'none';
       -        document.body.appendChild(element);
       -
       -        element.click();
       -
       -        document.body.removeChild(element);
       -}
       -
       -function getFileDate() {
       -        let now = new Date();
       -        // i love javascript
       -        let dateString = now.getDate() + "-" + (now.getMonth()+1) + "-"+ now.getFullYear() + " " + now.getHours() + " " + now.getMinutes() + " " + now.getSeconds();
       -        return dateString;
       -}
       -
       -function savePicture() {
       -        let ctx = cameraOutput.getContext("2d");
       -        ctx.drawImage(cameraView, 0,0, cameraOutput.width, cameraOutput.height);
       -        Filters.filterImage(Filters.paletteSwap, cameraOutput, [palettes[currentPalette]])
       -        var dataURL = cameraOutput.toDataURL('image/png');
       -        download("webgbcam " + getFileDate() + ".png", dataURL);
       -}
       -
       -function loadPrefs() {
       -        let localContrast = parseInt(localStorage.getItem("cameraContrast"));
       -        let localGamma = parseInt(localStorage.getItem("cameraGamma"));
       -        let localPalette = parseInt(localStorage.getItem("cameraPalette"));
       -        let localSharpness = parseInt(localStorage.getItem("cameraSharpness"));
       -        cameraVars.contrast = (localContrast ? localContrast : 3);
       -        cameraVars.gamma = (localGamma ? localGamma : 3);
       -        cameraVars.sharpness = (localSharpness ? localSharpness : 3);
       -        currentPalette = (localPalette ? localPalette : 0);
       -}
       -
       -function savePrefs() {
       -        localStorage.setItem("cameraContrast", cameraVars.contrast);
       -        localStorage.setItem("cameraGamma", cameraVars.gamma);
       -        localStorage.setItem("cameraSharpness", cameraVars.sharpness);
       -        localStorage.setItem("cameraPalette", currentPalette);
       -}
       -
        // bounding boxes for each button in the app
        var buttons = {
                bottomLeft: {
       @@ -492,9 +385,308 @@ var buttons = {
                        y:131,
                        width:16,
                        height:13
       +        },
       +        bppSwitch: {
       +                x:45,
       +                y:133,
       +                width:50,
       +                height:9
                }
        };
        
       +var screens = {
       +        uiMain: {
       +                elem: document.querySelector("#ui-main"),
       +                buttons: [
       +                        {
       +                                bounding: buttons.bottomLeft,
       +                                action: captureImage
       +                        },
       +                        {
       +                                bounding: buttons.screenHotspot,
       +                                action: captureImage
       +                        },
       +                        {
       +                                bounding: buttons.bottomRight,
       +                                action: switchCameras
       +                        },
       +                        {
       +                                bounding: buttons.topLeft,
       +                                action: ()=> {
       +                                        currentUI = screens.uiSettings;
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.hideUI,
       +                                action: ()=> {
       +                                        currentUI = screens.uiHidden;
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.timer,
       +                                action: ()=> {
       +                                        // change UI to timer and trigger 3s delay to capture
       +                                        currentUI = screens.uiTimer;
       +                                        setTimeout(captureImage, 3000);
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.record,
       +                                action: gifStart
       +                        }
       +                ]
       +        },
       +        uiCapture: {
       +                elem: document.querySelector("#ui-capture"),
       +                buttons: [
       +                        {
       +                                bounding: buttons.bottomLeft,
       +                                action: ()=> {
       +                                        // return
       +                                        cameraStream.play();
       +                                        currentUI = screens.uiMain;
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.bottomRight,
       +                                action: savePicture
       +                        },
       +                        {
       +                                bounding: buttons.topLeft,
       +                                action: ()=> {
       +                                        // go to settings
       +                                        currentUI = screens.uiSettings;
       +                                }
       +                        }
       +                ]
       +        },
       +        uiSettings: {
       +                elem: document.querySelector("#ui-settings"),
       +                buttons: [
       +                        {
       +                                bounding: buttons.bottomLeft,
       +                                action: ()=> {
       +                                        // return
       +                                        if(cameraStream.paused == true) {
       +                                                // we're in capture
       +                                                currentUI = screens.uiCapture;
       +                                        } else {
       +                                                currentUI = screens.uiMain;
       +                                        }
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.contrastLeft,
       +                                action: ()=> {
       +                                        if(cameraVars.contrast > 0) cameraVars.contrast--;
       +                                        savePrefs();
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.contrastRight,
       +                                action: ()=> {
       +                                        if(cameraVars.contrast < 6) cameraVars.contrast++;
       +                                        savePrefs();
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.brightnessLeft,
       +                                action: ()=> {
       +                                        if(cameraVars.gamma > 0) cameraVars.gamma--;
       +                                        savePrefs();
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.brightnessRight,
       +                                action: ()=> {
       +                                        if(cameraVars.gamma < 6) cameraVars.gamma++;
       +                                        savePrefs();
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.sharpnessLeft,
       +                                action: ()=> {
       +                                        if(cameraVars.sharpness > 0) cameraVars.sharpness--;
       +                                        savePrefs();
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.sharpnessRight,
       +                                action: ()=> {
       +                                        if(cameraVars.sharpness < 6) cameraVars.sharpness++;
       +                                        savePrefs();
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.paletteLeft,
       +                                action: ()=> {
       +                                        currentPalette--;
       +                                        if(currentPalette < 0) currentPalette = palettes.length-1;
       +                                        savePrefs(); 
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.paletteRight,
       +                                action: ()=> {
       +                                        currentPalette++;
       +                                        if(currentPalette >= palettes.length) currentPalette = 0;
       +                                        savePrefs();
       +                                }
       +                        },
       +                        {
       +                                bounding: buttons.bppSwitch,
       +                                action: bppSwitch
       +                        }
       +                ]
       +        },
       +        uiHidden: {
       +                elem: document.querySelector("#ui-hidden"),
       +                buttons: [
       +                        {
       +                                bounding: buttons.hideUI,
       +                                action: ()=> {
       +                                        // go back to main
       +                                        currentUI = screens.uiMain;
       +                                }
       +                        }
       +                ]
       +        },
       +        uiTimer: {
       +                elem: document.querySelector("#ui-timer"),
       +                buttons: []
       +        },
       +        uiRecord: {
       +                elem: document.querySelector("#ui-record"),
       +                buttons: []
       +        }
       +};
       +
       +// global settings for gbcamera
       +var renderWidth = 320,
       +                renderHeight = 288,
       +                currentPalette = 0,
       +                currentUI = screens.uiMain;
       +
       +var cameraVars = {
       +        width: 128,
       +        height: 112,
       +        dither: 0.6,
       +        contrast: 3,
       +        gamma: 3,
       +        sharpness: 3,
       +        xOffset: 0,
       +        yOffset: 0,
       +        xScale: 1,
       +        yScale: 1,
       +        bppSwitch: 2 // 2bpp = gameboy, 1bpp = atkinson, doubleres
       +};
       +
       +// function to check if phone is portrait oriented
       +function screenIsPortrait() {
       +        try {
       +                let orientation = (screen.orientation || {}).type || screen.mozOrientation || screen.msOrientation;
       +                if(orientation != undefined) {
       +                        if(orientation.includes('portrait')) return true;
       +                } else if(window.orientation != undefined) {
       +                        if(window.orientation == 0) return true;
       +                }
       +                return false;
       +        } catch(e) {
       +                return false;
       +        }
       +}
       +
       +//Function to get the mouse position
       +function getMousePos(canvas, event) {
       +        var rect = canvas.getBoundingClientRect();
       +        return {
       +                        x: (event.clientX - rect.left) / appScale,
       +                        y: (event.clientY - rect.top) / appScale
       +        };
       +}
       +//Function to check whether a point is inside a rectangle
       +function isInside(pos, rect){
       +        const scale = 2;
       +        return pos.x > rect.x * scale && pos.x < (rect.x+rect.width) * scale && pos.y < (rect.y+rect.height) * scale && pos.y > rect.y * scale;
       +}
       +
       +function switchCameras() {
       +        if(amountOfCameras > 1) {
       +                if (currentFacingMode === 'environment') currentFacingMode = 'user';
       +                else currentFacingMode = 'environment';
       +                initCameraStream();
       +        }
       +}
       +
       +function download(filename, content) {
       +        var element = document.createElement('a');
       +        element.setAttribute('href', content);
       +        element.setAttribute('download', filename);
       +
       +        element.style.display = 'none';
       +        document.body.appendChild(element);
       +
       +        element.click();
       +
       +        document.body.removeChild(element);
       +}
       +
       +function getFileDate() {
       +        let now = new Date();
       +        // i love javascript
       +        let dateString = now.getDate() + "-" + (now.getMonth()+1) + "-"+ now.getFullYear() + " " + now.getHours() + " " + now.getMinutes() + " " + now.getSeconds();
       +        return dateString;
       +}
       +
       +function savePicture() {
       +        let ctx = cameraOutput.getContext("2d");
       +        ctx.drawImage(cameraView, 0,0, cameraOutput.width, cameraOutput.height);
       +        Filters.filterImage(Filters.paletteSwap, cameraOutput, [palettes[currentPalette]])
       +        var dataURL = cameraOutput.toDataURL('image/png');
       +        download("webgbcam " + getFileDate() + ".png", dataURL);
       +}
       +
       +function loadPrefs() {
       +        let localContrast = parseInt(localStorage.getItem("cameraContrast"));
       +        let localGamma = parseInt(localStorage.getItem("cameraGamma"));
       +        let localPalette = parseInt(localStorage.getItem("cameraPalette"));
       +        let localSharpness = parseInt(localStorage.getItem("cameraSharpness"));
       +        let localBpp = parseInt(localStorage.getItem("cameraBpp"));
       +        cameraVars.contrast = (localContrast ? localContrast : 3);
       +        cameraVars.gamma = (localGamma ? localGamma : 3);
       +        cameraVars.sharpness = (localSharpness ? localSharpness : 3);
       +        cameraVars.bppSwitch = (localBpp ? localBpp : 2);
       +        outputScale = (cameraVars.bppSwitch == 2 ? 6 : 3);
       +        currentPalette = (localPalette ? localPalette : 0);
       +}
       +
       +function savePrefs() {
       +        localStorage.setItem("cameraContrast", cameraVars.contrast);
       +        localStorage.setItem("cameraGamma", cameraVars.gamma);
       +        localStorage.setItem("cameraSharpness", cameraVars.sharpness);
       +        localStorage.setItem("cameraBpp", cameraVars.bppSwitch);
       +        localStorage.setItem("cameraPalette", currentPalette);
       +}
       +
       +function bppSwitch() {
       +        if (cameraVars.bppSwitch == 2) {
       +                // to 1bpp
       +                cameraVars.bppSwitch = 1;
       +                cameraVars.width = 256;
       +                cameraVars.height = 224;
       +                outputScale = 3;
       +        } else {
       +                // to 2bpp
       +                cameraVars.bppSwitch = 2;
       +                cameraVars.width = 128;
       +                cameraVars.height = 112;
       +                outputScale = 6;
       +        }
       +        cameraView.width = cameraVars.width;
       +        cameraView.height = cameraVars.height;
       +        initCameraDrawing(false);
       +}
       +
        function applyLevels(value, brightness, contrast, gamma) {
                let newValue = value / 255.0;
                newValue = (newValue - 0.5) * contrast + 0.5;
       @@ -591,6 +783,23 @@ Filters.gbcamera = function(pixels, ditherFactor) {
                return pixels;
        }
        
       +// thanks to https://beyondloom.com/blog/dither.html
       +Filters.atkinson = function(pixels) {
       +        let w = pixels.width;
       +        let d = pixels.data;
       +        const e=Array(2*w).fill(0), m=[0,1,w-2,w-1,w,2*w-1];
       +        for (i = 0; i < d.length; i=i+4) {
       +                let x = d[i]/256.0;
       +                const pix=x+(e.push(0),e.shift()), col=pix>.5, err=(pix-col)/8;
       +                m.forEach(x => e[x]+=err);
       +                let c = col ? 255 : 0;
       +                d[i] = c;
       +                d[i+1] = c;
       +                d[i+2] = c;
       +        }
       +        return pixels;
       +}
       +
        // takes grayscale and paints it with palette
        Filters.paletteSwap = function(pixels, palette) {
                let d = pixels.data;
       @@ -698,7 +907,7 @@ window.onresize = restartCamera;
        
        function captureImage() {
                cameraStream.pause();
       -        currentUI = uiCapture;
       +        currentUI = screens.uiCapture;
        }
        
        function initCameraUI() {
       @@ -707,89 +916,18 @@ function initCameraUI() {
                const queryString = window.location.search;
                const urlParams = new URLSearchParams(queryString);
                if (urlParams.has('hideui')) {
       -                currentUI = uiHidden;
       +                currentUI = screens.uiHidden;
                }
        
                // handle canvas app clicks
                appView.addEventListener('click', function(e) {
                        var mousePos = getMousePos(appView, e);
        
       -                // buttons in main screen
       -                if(currentUI === uiMain) {
       -                        if(isInside(mousePos, buttons.bottomLeft) || isInside(mousePos, buttons.screenHotspot)) {
       -                                // shutter
       -                                captureImage();
       -                        } else if(isInside(mousePos, buttons.bottomRight)) {
       -                                // switch camera
       -                                switchCameras();
       -                        } else if(isInside(mousePos, buttons.topLeft)) {
       -                                // go to settings
       -                                currentUI = uiSettings;
       -                        } else if(isInside(mousePos, buttons.hideUI)) {
       -                                // hide UI buttons
       -                                currentUI = uiHidden;
       -                        } else if(isInside(mousePos, buttons.timer)) {
       -                                // change UI to timer and trigger 3s delay to capture
       -                                currentUI = uiTimer;
       -                                setTimeout(captureImage, 3000);
       -                        } else if(isInside(mousePos, buttons.record)) {
       -                                // start GIF recording
       -                                gifStart();
       -                        }
       -                } else if(currentUI === uiCapture) {
       -                        if(isInside(mousePos, buttons.bottomLeft)) {
       -                                // return
       -                                cameraStream.play();
       -                                currentUI = uiMain;
       -                        } else if(isInside(mousePos, buttons.bottomRight)) {
       -                                // save picture
       -                                savePicture();
       -                        } else if(isInside(mousePos, buttons.topLeft)) {
       -                                // go to settings
       -                                currentUI = uiSettings;
       -                        } 
       -                } else if(currentUI === uiSettings) {
       -                        if(isInside(mousePos, buttons.bottomLeft)) {
       -                                // return
       -                                if(cameraStream.paused == true) {
       -                                        // we're in capture
       -                                        currentUI = uiCapture;
       -                                } else {
       -                                        currentUI = uiMain;
       -                                }
       -                        } else if(isInside(mousePos, buttons.contrastLeft)) {
       -                                if(cameraVars.contrast > 0) cameraVars.contrast--;
       -                                savePrefs();
       -                        } else if(isInside(mousePos, buttons.contrastRight)) {
       -                                if(cameraVars.contrast < 6) cameraVars.contrast++;
       -                                savePrefs();
       -                        } else if(isInside(mousePos, buttons.brightnessLeft)) {
       -                                if(cameraVars.gamma > 0) cameraVars.gamma--;
       -                                savePrefs();
       -                        } else if(isInside(mousePos, buttons.brightnessRight)) {
       -                                if(cameraVars.gamma < 6) cameraVars.gamma++;
       -                                savePrefs();
       -                        } else if(isInside(mousePos, buttons.sharpnessLeft)) {
       -                                if(cameraVars.sharpness > 0) cameraVars.sharpness--;
       -                                savePrefs();
       -                        } else if(isInside(mousePos, buttons.sharpnessRight)) {
       -                                if(cameraVars.sharpness < 6) cameraVars.sharpness++;
       -                                savePrefs();
       -                        } else if(isInside(mousePos, buttons.paletteLeft)) {
       -                                currentPalette--;
       -                                if(currentPalette < 0) currentPalette = palettes.length-1;
       -                                savePrefs(); 
       -                        } else if(isInside(mousePos, buttons.paletteRight)) {
       -                                currentPalette++;
       -                                if(currentPalette >= palettes.length) currentPalette = 0;
       -                                savePrefs();
       -                        }
       -                } else if(currentUI === uiHidden) {
       -                        if(isInside(mousePos, buttons.hideUI)) {
       -                                // go back to main
       -                                currentUI = uiMain;
       +                currentUI.buttons.forEach((button) => {
       +                        if (isInside(mousePos, button.bounding)) {
       +                                button.action();
                                }
       -                }
       +                });
                        
                }, false);
        }
       @@ -811,6 +949,11 @@ function initAppScaling() {
                cameraView.height = cameraVars.height;
                appView.width = renderWidth;
                appView.height = renderHeight;
       +
       +        let ctx = appView.getContext("2d");
       +        ctx.imageSmoothingEnabled = false;
       +        ctx = cameraView.getContext("2d");
       +        ctx.imageSmoothingEnabled = false;
        }
        
        // https://github.com/webrtc/samples/blob/gh-pages/src/content/devices/input-output/js/main.js
       @@ -855,14 +998,14 @@ function initCameraStream() {
                        .catch(handleError);
        }
        
       -function initCameraDrawing() {
       +function initCameraDrawing(start = true) {
                // if cameraStream has vertical or horizontal resolution of 0 then it's not initialized, we retry until the browser decides to properly work
                if (cameraStream.videoHeight == 0) setTimeout(restartCamera, 500);
        
                const track = window.stream.getVideoTracks()[0];
                let settings = track.getSettings();
       -        let str = JSON.stringify(settings, null, 4);
       -        console.log('settings ' + str);
       +        //let str = JSON.stringify(settings, null, 4);
       +        //console.log('settings ' + str);
        
                // calculate scale and offset to render camera stream to camera view canvas
                if(cameraStream.videoWidth >= cameraStream.videoHeight) {
       @@ -885,17 +1028,18 @@ function initCameraDrawing() {
                } else {
                        cameraView.getContext('2d').setTransform(1, 0, 0, 1, 0, 0);
                }
       -        console.log(cameraVars);
       +        //console.log(cameraVars);
                
                cameraOutput.width = cameraVars.width * outputScale;
                cameraOutput.height = cameraVars.height * outputScale;
                let ctx = cameraOutput.getContext("2d");
                ctx.imageSmoothingEnabled = false;
        
       -        cameraStream.play();
       -        
       -        clearInterval(frameDrawing)
       -        frameDrawing = setInterval(drawFrame, 100);
       +        if (start) {
       +                cameraStream.play();
       +                clearInterval(frameDrawing)
       +                frameDrawing = setInterval(drawFrame, 100);
       +        }
        }
        
        function showGifModal() {
       @@ -934,13 +1078,13 @@ function gifStart() {
                        //download("webgbcam " + getFileDate() + ".gif", URL.createObjectURL(blob));
                });
                gifFrames = gifLength;
       -        currentUI = uiRecord;
       +        currentUI = screens.uiRecord;
                gifRecording = true;
        }
        
        function gifEnd() {
                gifRecording = false;
       -        currentUI = uiMain;
       +        currentUI = screens.uiMain;
                gifEncoder.render();
                showGifModal();
        }
       @@ -953,34 +1097,51 @@ function gifFrame() {
                if(--gifFrames == 0) gifEnd();
        }
        
       +function scaledFillRect(ctx, x, y, width, height) {
       +        const scale = 2;
       +        ctx.fillRect(x * scale, y * scale, width * scale, height * scale);
       +}
       +
        function drawFrame() {
                let camctx = cameraView.getContext('2d');
                camctx.drawImage(cameraStream, cameraVars.xOffset, cameraVars.yOffset, cameraVars.xScale, cameraVars.yScale, 0, 0, cameraVars.width, cameraVars.height);
                
                Filters.filterImage(Filters.grayscale, cameraView, []);
                Filters.filterImage(Filters.sharpen, cameraView, [sliderSharpness[cameraVars.sharpness]]);
       -        Filters.filterImage(Filters.gbcamera, cameraView, [cameraVars.dither]);
       +        
       +        if (cameraVars.bppSwitch == 2) {
       +                Filters.filterImage(Filters.gbcamera, cameraView, [cameraVars.dither]);
       +        } else {
       +                Filters.filterImage(Filters.atkinson, cameraView, []);
       +        }
                
                let ctx = appView.getContext("2d");
       -        ctx.drawImage(cameraView, 16, 16);
       -        ctx.drawImage(currentUI, 0, 0);
       +        ctx.drawImage(cameraView, 32, 32, 256, 224);
       +        ctx.drawImage(currentUI.elem, 0, 0, 160, 144, 0, 0, 320, 288);
        
       -        if (currentUI === uiSettings) {
       +        if (currentUI === screens.uiSettings) {
                        // update settings values        
                        ctx.fillStyle = "rgb(192,192,192)";
                        for(let i = 1; i <= cameraVars.contrast; i++) {
       -                        ctx.fillRect(42, 22 - (i*3), 4, 2);
       +                        scaledFillRect(ctx, 42, 22 - (i*3), 4, 2);
                        }
                        for(let i = 1; i <= cameraVars.gamma; i++) {
       -                        ctx.fillRect(97, 22 - (i*3), 4, 2);
       +                        scaledFillRect(ctx, 97, 22 - (i*3), 4, 2);
                        }
                        for(let i = 1; i <= cameraVars.sharpness; i++) {
       -                        ctx.fillRect(152, 135 - (i*3), 4, 2);
       +                        scaledFillRect(ctx, 152, 135 - (i*3), 4, 2);
       +                }
       +                
       +                ctx.fillStyle = "rgb(130,130,130)";
       +                if (cameraVars.bppSwitch == 2) {
       +                        scaledFillRect(ctx, 70, 135, 4, 4);
       +                } else {
       +                        scaledFillRect(ctx, 65, 135, 4, 4);
                        }
       -        } else if (currentUI === uiRecord) {
       +        } else if (currentUI === screens.uiRecord) {
                        // update record length
                        ctx.fillStyle = "rgb(64,64,64)";
       -                ctx.fillRect(25, 134, 110 - (gifFrames / gifLength * 110), 6);
       +                scaledFillRect(ctx, 25, 134, 110 - (gifFrames / gifLength * 110), 6);
                }
        
                try {
   DIR diff --git a/index.html b/index.html
       @@ -15,7 +15,7 @@
        </head>
        <body>
                <div class="maple-window">
       -                <div class="maple-window-title"><span>webgbcam v4.1</span></div>
       +                <div class="maple-window-title"><span>webgbcam v4.2</span></div>
                        <div id="camera">
                                <canvas id="app-view"></canvas>
                                <canvas id="camera-view"></canvas>
   DIR diff --git a/sw.js b/sw.js
       @@ -1,4 +1,4 @@
       -const cacheName = 'webgbcam-v4.1'
       +const cacheName = 'webgbcam-v4.2'
        
        // Install a service worker
        self.addEventListener("install", (event) => {
       @@ -58,5 +58,5 @@ self.addEventListener("activate", (event) => {
                                        }
                                }));
                        })
       -  );
       +  ).then(self.clients.claim());
        });
        \ No newline at end of file
   DIR diff --git a/ui/ui-settings.png b/ui/ui-settings.png
       Binary files differ.