URI:
       chore: normalize line endings and remove gitignore - webgbcam - [fork] gameboy webcam
  HTML git clone git://src.adamsgaard.dk/webgbcam
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit e49591b1954c1eae6ff4fe280185a475bb8180e2
   DIR parent 6335cc127af852aa1af7f5ca6ee91bde91291dc4
  HTML Author: Anders Damsgaard <anders@adamsgaard.dk>
       Date:   Sat, 14 Feb 2026 16:34:19 +0100
       
       chore: normalize line endings and remove gitignore
       
       Diffstat:
         D .gitignore                          |       6 ------
         M index.html                          |     176 ++++++++++++++++----------------
         M manifest.webmanifest                |      28 ++++++++++++++--------------
         M style.css                           |     330 ++++++++++++++++----------------
         M sw.js                               |     122 ++++++++++++++++----------------
       
       5 files changed, 328 insertions(+), 334 deletions(-)
       ---
   DIR diff --git a/.gitignore b/.gitignore
       @@ -1,5 +0,0 @@
       -*.aseprite
       -todo.txt
       -key.pem
       -server.pem
       -simple-https-server.py
       -\ No newline at end of file
   DIR diff --git a/index.html b/index.html
       @@ -1,89 +1,89 @@
       -<!doctype html>
       -<html lang=”en”>
       -<head>
       -        <meta charset="utf-8">
       -        <meta http-equiv="x-ua-compatible" content="ie=edge">
       -        <meta name="viewport" content="width=device-width, initial-scale=1">
       -        <title>webgbcam</title>
       -        <link rel="stylesheet" href="style.css">
       -        <link rel="manifest" href="manifest.webmanifest">
       -
       -        <meta property="og:title" content="webgbcam">
       -        <meta property="og:description" content="gameboy camera-like experience in your browser!">
       -        <meta property="og:image" content="https://maple.pet/webgbcam/icon.png">
       -        <meta property="og:url" content="https://maple.pet/webgbcam/">
       -</head>
       -<body>
       -        <div id="main-app-window" class="maple-window centered">
       -                <div class="maple-window-title"><span>webgbcam v4.3</span></div>
       -                <div id="camera">
       -                        <canvas id="app-view"></canvas>
       -                        <canvas id="camera-view"></canvas>
       -                        <canvas id="camera-output"></canvas>
       -                        <video id="camera-stream" autoplay playsinline></video>
       -                </div><br/>
       -                <button id="button-about" onclick="toggleAbout();">about</button>
       -        </div>
       -
       -        <div id="about" class="maple-window centered modal hidden">
       -                <div class="maple-window-title"><span>about</span></div>
       -                <h2 class="blink">NFTs: No Fucking Thanks</h2>
       -
       -                <p>made by <a href="https://maple.pet">maple</a> - inspired by christine love's interstellar selfie station</p>
       -
       -                <p>if the app is blank, make sure you have cameras connected and browser camera permissions enabled!</p>
       -
       -                <p>webgbcam uses <a href="https://github.com/jnordberg/gif.js">gif.js</a><br/>
       -                you can check the source code on <a href="https://github.com/Lana-chan/webgbcam">github</a>!</p>
       -
       -                <p>as seen on:
       -                        <ul>
       -                                <li>Mashable: <a href="https://mashable.com/article/game-boy-camera-style-web-app">New web app lets you take Game Boy Camera-style pics and pretend it's 1998</a></li>
       -                                <li>Nerdist: <a href="https://nerdist.com/article/game-boy-app-camera-selfies/">Web App Lets You Take 1998 Game Boy Camera-Style Selfies</a></li>
       -                                <li>Hackaday: <a href="https://hackaday.com/2020/10/26/the-game-boy-camera-or-how-i-learned-to-stop-worrying-and-love-the-pixels/">The Game Boy Camera, Or: How I Learned To Stop Worrying And Love The Pixels</a></li>
       -                        </ul>
       -                </p>
       -
       -                <p>if you like the stuff i do, check out <a href="https://maple.pet/">my website</a> and please <a href="https://ko-fi.com/squirrel">donate to me on ko-fi</a>!</p>
       -
       -                <p>ps: you look great today!</p>
       -
       -                <button id="button-close" onclick="toggleAbout();">close</button>
       -        </div>
       -
       -        <div id="gif-preview" class="maple-window modal hidden">
       -                <div class="maple-window-title"><span>gif preview</span></div>
       -                <img id="gif-img" src="ui/loading.gif"/>
       -                <div id="gif-buttons" class="hidden">
       -                        <button type="button" onclick="downloadGif();">yes!!!</button>
       -                        <button class="right" type="button" onclick="resetGifModal();">no!!!</button>
       -                </div>
       -        </div>
       -        
       -        <div class="hidden">
       -                <img src="ui/ui-main.png" id="ui-main" />
       -                <img src="ui/ui-settings.png" id="ui-settings" />
       -                <img src="ui/ui-capture.png" id="ui-capture" />
       -                <img src="ui/ui-hidden.png" id="ui-hidden" />
       -                <img src="ui/ui-timer.png" id="ui-timer" />
       -                <img src="ui/ui-record.png" id="ui-record" />
       -        </div>
       -
       -        <script type="text/javascript" src="gifjs/gif.js"></script>
       -        <script src="app.js"></script>
       -        <script>
       -        if('serviceWorker' in navigator) {
       -                navigator.serviceWorker
       -                                                .register('sw.js', {scope: './'})
       -                                                .then(function(registration) {
       -                                                        // Registration was successful
       -                                                        console.log('ServiceWorker registration successful with scope: ', registration.scope);
       -                                                        registration.update();
       -                                                }, function(err) {
       -                                                        // registration failed :(
       -                                                        console.log('ServiceWorker registration failed: ', err);
       -                                                });
       -        }
       -        </script>
       -</body>
       +<!doctype html>
       +<html lang=”en”>
       +<head>
       +        <meta charset="utf-8">
       +        <meta http-equiv="x-ua-compatible" content="ie=edge">
       +        <meta name="viewport" content="width=device-width, initial-scale=1">
       +        <title>webgbcam</title>
       +        <link rel="stylesheet" href="style.css">
       +        <link rel="manifest" href="manifest.webmanifest">
       +
       +        <meta property="og:title" content="webgbcam">
       +        <meta property="og:description" content="gameboy camera-like experience in your browser!">
       +        <meta property="og:image" content="https://maple.pet/webgbcam/icon.png">
       +        <meta property="og:url" content="https://maple.pet/webgbcam/">
       +</head>
       +<body>
       +        <div id="main-app-window" class="maple-window centered">
       +                <div class="maple-window-title"><span>webgbcam v4.3</span></div>
       +                <div id="camera">
       +                        <canvas id="app-view"></canvas>
       +                        <canvas id="camera-view"></canvas>
       +                        <canvas id="camera-output"></canvas>
       +                        <video id="camera-stream" autoplay playsinline></video>
       +                </div><br/>
       +                <button id="button-about" onclick="toggleAbout();">about</button>
       +        </div>
       +
       +        <div id="about" class="maple-window centered modal hidden">
       +                <div class="maple-window-title"><span>about</span></div>
       +                <h2 class="blink">NFTs: No Fucking Thanks</h2>
       +
       +                <p>made by <a href="https://maple.pet">maple</a> - inspired by christine love's interstellar selfie station</p>
       +
       +                <p>if the app is blank, make sure you have cameras connected and browser camera permissions enabled!</p>
       +
       +                <p>webgbcam uses <a href="https://github.com/jnordberg/gif.js">gif.js</a><br/>
       +                you can check the source code on <a href="https://github.com/Lana-chan/webgbcam">github</a>!</p>
       +
       +                <p>as seen on:
       +                        <ul>
       +                                <li>Mashable: <a href="https://mashable.com/article/game-boy-camera-style-web-app">New web app lets you take Game Boy Camera-style pics and pretend it's 1998</a></li>
       +                                <li>Nerdist: <a href="https://nerdist.com/article/game-boy-app-camera-selfies/">Web App Lets You Take 1998 Game Boy Camera-Style Selfies</a></li>
       +                                <li>Hackaday: <a href="https://hackaday.com/2020/10/26/the-game-boy-camera-or-how-i-learned-to-stop-worrying-and-love-the-pixels/">The Game Boy Camera, Or: How I Learned To Stop Worrying And Love The Pixels</a></li>
       +                        </ul>
       +                </p>
       +
       +                <p>if you like the stuff i do, check out <a href="https://maple.pet/">my website</a> and please <a href="https://ko-fi.com/squirrel">donate to me on ko-fi</a>!</p>
       +
       +                <p>ps: you look great today!</p>
       +
       +                <button id="button-close" onclick="toggleAbout();">close</button>
       +        </div>
       +
       +        <div id="gif-preview" class="maple-window modal hidden">
       +                <div class="maple-window-title"><span>gif preview</span></div>
       +                <img id="gif-img" src="ui/loading.gif"/>
       +                <div id="gif-buttons" class="hidden">
       +                        <button type="button" onclick="downloadGif();">yes!!!</button>
       +                        <button class="right" type="button" onclick="resetGifModal();">no!!!</button>
       +                </div>
       +        </div>
       +        
       +        <div class="hidden">
       +                <img src="ui/ui-main.png" id="ui-main" />
       +                <img src="ui/ui-settings.png" id="ui-settings" />
       +                <img src="ui/ui-capture.png" id="ui-capture" />
       +                <img src="ui/ui-hidden.png" id="ui-hidden" />
       +                <img src="ui/ui-timer.png" id="ui-timer" />
       +                <img src="ui/ui-record.png" id="ui-record" />
       +        </div>
       +
       +        <script type="text/javascript" src="gifjs/gif.js"></script>
       +        <script src="app.js"></script>
       +        <script>
       +        if('serviceWorker' in navigator) {
       +                navigator.serviceWorker
       +                                                .register('sw.js', {scope: './'})
       +                                                .then(function(registration) {
       +                                                        // Registration was successful
       +                                                        console.log('ServiceWorker registration successful with scope: ', registration.scope);
       +                                                        registration.update();
       +                                                }, function(err) {
       +                                                        // registration failed :(
       +                                                        console.log('ServiceWorker registration failed: ', err);
       +                                                });
       +        }
       +        </script>
       +</body>
        </html>
        \ No newline at end of file
   DIR diff --git a/manifest.webmanifest b/manifest.webmanifest
       @@ -1,15 +1,15 @@
       -{
       -  "background_color": "#99ccff",
       -  "description": "A web-based camera filter that emulates the look of the Game Boy Camera.",
       -  "display": "standalone",
       -  "icons": [
       -    {
       -      "src": "icon.png",
       -      "sizes": "256x256",
       -      "type": "image/png"
       -    }
       -  ],
       -  "name": "webgbcam",
       -  "short_name": "webgbcam",
       -  "start_url": "index.html"
       +{
       +  "background_color": "#99ccff",
       +  "description": "A web-based camera filter that emulates the look of the Game Boy Camera.",
       +  "display": "standalone",
       +  "icons": [
       +    {
       +      "src": "icon.png",
       +      "sizes": "256x256",
       +      "type": "image/png"
       +    }
       +  ],
       +  "name": "webgbcam",
       +  "short_name": "webgbcam",
       +  "start_url": "index.html"
        }
        \ No newline at end of file
   DIR diff --git a/style.css b/style.css
       @@ -1,166 +1,166 @@
       -html, body{
       -  margin: 0;
       -  padding: 0;
       -  height: 100%;
       -  width: 100%;
       -  touch-action: manipulation;
       -}
       -
       -body {
       -  background: url("ui/bg.png");
       -  text-align: center;
       -  font: 12px sans-serif;
       -}
       -
       -.centered {
       -  text-align: center !important;
       -}
       -
       -.maple-window {
       -  margin: 5px;
       -  vertical-align: top;
       -        display: inline-block;
       -        border-width: 26px 12px 20px 12px;
       -        border-style: solid;
       -        border-image: url("ui/mac-frame.png") 30 40 22 22 fill repeat;
       -        border-image-width: 30px 40px 22px 22px;
       -        color: #000;
       -        position: relative;
       -        text-align: left;
       -        font-size: 12px;
       -        font-family: geneva, sans-serif;
       -        min-width: 200px;
       -        box-sizing: border-box;
       -}
       -
       -.maple-window a {
       -  color: #9999cc;
       -  text-shadow: none;
       -}
       -.maple-window a:hover {
       -  color: #ccccff;
       -}
       -
       -.maple-window-title {
       -  position: absolute;
       -  top: -23px;
       -  text-align: center;
       -  width: 100%;
       -  left: 0;
       -}
       -
       -.maple-window-title > span {
       -  background: #ccc;
       -  padding: 1px 5px 1px 5px;
       -        font-size: 12px;
       -        font-weight: bold;
       -  font-family: chicago, sans-serif;
       -  /*vertical-align: middle;*/
       -  margin-right: 20px;
       -  white-space: nowrap;
       -}
       -
       -/*#camera {
       -        position: fixed;
       -        left: 50%;
       -        top: 50%;
       -        transform: translate(-50%, -50%);
       -}*/
       -
       -#app-view {
       -        height: 100%;
       -        width: 100%;
       -        /*image-rendering: -moz-crisp-edges;
       -        image-rendering: -webkit-optimize-contrast;
       -        image-rendering: -o-crisp-edges;
       -        image-rendering: crisp-edges;*/
       -}
       -
       -#camera-stream, #camera-output, #camera-view, .hidden {
       -        display: none;
       -}
       -
       -.button {
       -        width: 200px;
       -        background-color: black;
       -        color: white;
       -        font-size: 16px;
       -        border-radius: 30px;
       -        border: none;
       -        padding: 15px 20px;
       -        text-align: center;
       -        box-shadow: 0 5px 10px 0 rgba(0,0,0,0.2);
       -        /*position: fixed;
       -        bottom: 30px;
       -        left: calc(50% - 100px);*/
       -}
       -.right {
       -        float: right;
       -}
       -
       -.modal {
       -        position: absolute;
       -        top: 0;
       -        left: 0;
       -        max-width: 80%;
       -        max-height: 80%;
       -        transform: translate(calc(50vw - 50%),calc(50vh - 50%));
       -}
       -
       -#gif-img {
       -        object-fit: scale-down;
       -        max-width:100%;
       -        display: block;
       -        margin: auto;
       -}
       -#gif-buttons {
       -        margin: .5em;
       -}
       -
       -.blink {
       -        color: #f00;
       -        text-align: center;
       -        animation: blink-animation 1s steps(5, start) 4;
       -        -webkit-animation: blink-animation 1s steps(5, start) 4;
       -}
       -@keyframes blink-animation {
       -        to {
       -                visibility: hidden;
       -        }
       -}
       -@-webkit-keyframes blink-animation {
       -        to {
       -                visibility: hidden;
       -        }
       -}
       -
       -ul {
       -        margin-top: -1em;
       -        padding: 0;
       -        list-style: none;
       -}
       -
       -#main-app-window {
       -        width: 98%;
       -        top: 48%;
       -  transform: translateY(-50%);
       -}
       -
       -#camera {
       -        display: inline-block;
       -        width: 100%;
       -}
       -
       -@media (orientation:landscape)  {
       -        #main-app-window {
       -                width: unset;
       -                height: 98%;
       -                top: unset;
       -                transform: unset;
       -        }
       -
       -        #camera {
       -                width: unset;
       -                height: calc(100% - 2rem);
       -        }
       +html, body{
       +  margin: 0;
       +  padding: 0;
       +  height: 100%;
       +  width: 100%;
       +  touch-action: manipulation;
       +}
       +
       +body {
       +  background: url("ui/bg.png");
       +  text-align: center;
       +  font: 12px sans-serif;
       +}
       +
       +.centered {
       +  text-align: center !important;
       +}
       +
       +.maple-window {
       +  margin: 5px;
       +  vertical-align: top;
       +        display: inline-block;
       +        border-width: 26px 12px 20px 12px;
       +        border-style: solid;
       +        border-image: url("ui/mac-frame.png") 30 40 22 22 fill repeat;
       +        border-image-width: 30px 40px 22px 22px;
       +        color: #000;
       +        position: relative;
       +        text-align: left;
       +        font-size: 12px;
       +        font-family: geneva, sans-serif;
       +        min-width: 200px;
       +        box-sizing: border-box;
       +}
       +
       +.maple-window a {
       +  color: #9999cc;
       +  text-shadow: none;
       +}
       +.maple-window a:hover {
       +  color: #ccccff;
       +}
       +
       +.maple-window-title {
       +  position: absolute;
       +  top: -23px;
       +  text-align: center;
       +  width: 100%;
       +  left: 0;
       +}
       +
       +.maple-window-title > span {
       +  background: #ccc;
       +  padding: 1px 5px 1px 5px;
       +        font-size: 12px;
       +        font-weight: bold;
       +  font-family: chicago, sans-serif;
       +  /*vertical-align: middle;*/
       +  margin-right: 20px;
       +  white-space: nowrap;
       +}
       +
       +/*#camera {
       +        position: fixed;
       +        left: 50%;
       +        top: 50%;
       +        transform: translate(-50%, -50%);
       +}*/
       +
       +#app-view {
       +        height: 100%;
       +        width: 100%;
       +        /*image-rendering: -moz-crisp-edges;
       +        image-rendering: -webkit-optimize-contrast;
       +        image-rendering: -o-crisp-edges;
       +        image-rendering: crisp-edges;*/
       +}
       +
       +#camera-stream, #camera-output, #camera-view, .hidden {
       +        display: none;
       +}
       +
       +.button {
       +        width: 200px;
       +        background-color: black;
       +        color: white;
       +        font-size: 16px;
       +        border-radius: 30px;
       +        border: none;
       +        padding: 15px 20px;
       +        text-align: center;
       +        box-shadow: 0 5px 10px 0 rgba(0,0,0,0.2);
       +        /*position: fixed;
       +        bottom: 30px;
       +        left: calc(50% - 100px);*/
       +}
       +.right {
       +        float: right;
       +}
       +
       +.modal {
       +        position: absolute;
       +        top: 0;
       +        left: 0;
       +        max-width: 80%;
       +        max-height: 80%;
       +        transform: translate(calc(50vw - 50%),calc(50vh - 50%));
       +}
       +
       +#gif-img {
       +        object-fit: scale-down;
       +        max-width:100%;
       +        display: block;
       +        margin: auto;
       +}
       +#gif-buttons {
       +        margin: .5em;
       +}
       +
       +.blink {
       +        color: #f00;
       +        text-align: center;
       +        animation: blink-animation 1s steps(5, start) 4;
       +        -webkit-animation: blink-animation 1s steps(5, start) 4;
       +}
       +@keyframes blink-animation {
       +        to {
       +                visibility: hidden;
       +        }
       +}
       +@-webkit-keyframes blink-animation {
       +        to {
       +                visibility: hidden;
       +        }
       +}
       +
       +ul {
       +        margin-top: -1em;
       +        padding: 0;
       +        list-style: none;
       +}
       +
       +#main-app-window {
       +        width: 98%;
       +        top: 48%;
       +  transform: translateY(-50%);
       +}
       +
       +#camera {
       +        display: inline-block;
       +        width: 100%;
       +}
       +
       +@media (orientation:landscape)  {
       +        #main-app-window {
       +                width: unset;
       +                height: 98%;
       +                top: unset;
       +                transform: unset;
       +        }
       +
       +        #camera {
       +                width: unset;
       +                height: calc(100% - 2rem);
       +        }
        }
        \ No newline at end of file
   DIR diff --git a/sw.js b/sw.js
       @@ -1,62 +1,62 @@
       -const cacheName = 'webgbcam-v4.3b'
       -
       -// Install a service worker
       -self.addEventListener("install", (event) => {
       -  // Perform install steps
       -  caches.open(cacheName).then(function(cache) {
       -                return cache.addAll([
       -                        '/',
       -                        '/index.html',
       -                        '/style.css',
       -                        '/app.js',
       -                        '/ui/bg.png',
       -                        '/ui/mac-frame.png',
       -                        '/ui/ui-capture.png',
       -                        '/ui/ui-settings.png',
       -                        '/ui/ui-main.png',
       -                        '/ui/ui-hidden.png',
       -                        '/ui/ui-timer.png',
       -                        '/ui/ui-record.png',
       -                        '/ui/loading.gif',
       -                        '/gifjs/gif.js',
       -                        '/gifjs/gif.worker.js'
       -                ]);
       -        });
       -});
       -
       -// Cache lookup and fetch the request
       -self.addEventListener("fetch", (event) => {
       -  event.respondWith(
       -    caches.match(event.request).then(function (response) {
       -      // Cache hit - return response
       -      if (response) {
       -        return response;
       -      }
       -      return fetch(event.request).then(function (response) {
       -        if (!response || response.status !== 200 || response.type !== "basic") {
       -          return response;
       -        }
       -
       -        //Clone the response before putting into cache so that response to browser and response to cache happens in two difference streams
       -        var responseForCache = response.clone();
       -        caches.open(cacheName).then(function (cache) {
       -          cache.put(event.request, responseForCache);
       -        });
       -        return response;
       -      });
       -    })
       -  );
       -});
       -
       -// Update a service worker
       -self.addEventListener("activate", (event) => {
       -  event.waitUntil(
       -    caches.keys().then(function(keyList) {
       -                        return Promise.all(keyList.map(function(key) {
       -                                if (key != cacheName) {
       -                                        return caches.delete(key);
       -                                }
       -                        }));
       -                })
       -  ).then(self.clients.claim());
       +const cacheName = 'webgbcam-v4.3b'
       +
       +// Install a service worker
       +self.addEventListener("install", (event) => {
       +  // Perform install steps
       +  caches.open(cacheName).then(function(cache) {
       +                return cache.addAll([
       +                        '/',
       +                        '/index.html',
       +                        '/style.css',
       +                        '/app.js',
       +                        '/ui/bg.png',
       +                        '/ui/mac-frame.png',
       +                        '/ui/ui-capture.png',
       +                        '/ui/ui-settings.png',
       +                        '/ui/ui-main.png',
       +                        '/ui/ui-hidden.png',
       +                        '/ui/ui-timer.png',
       +                        '/ui/ui-record.png',
       +                        '/ui/loading.gif',
       +                        '/gifjs/gif.js',
       +                        '/gifjs/gif.worker.js'
       +                ]);
       +        });
       +});
       +
       +// Cache lookup and fetch the request
       +self.addEventListener("fetch", (event) => {
       +  event.respondWith(
       +    caches.match(event.request).then(function (response) {
       +      // Cache hit - return response
       +      if (response) {
       +        return response;
       +      }
       +      return fetch(event.request).then(function (response) {
       +        if (!response || response.status !== 200 || response.type !== "basic") {
       +          return response;
       +        }
       +
       +        //Clone the response before putting into cache so that response to browser and response to cache happens in two difference streams
       +        var responseForCache = response.clone();
       +        caches.open(cacheName).then(function (cache) {
       +          cache.put(event.request, responseForCache);
       +        });
       +        return response;
       +      });
       +    })
       +  );
       +});
       +
       +// Update a service worker
       +self.addEventListener("activate", (event) => {
       +  event.waitUntil(
       +    caches.keys().then(function(keyList) {
       +                        return Promise.all(keyList.map(function(key) {
       +                                if (key != cacheName) {
       +                                        return caches.delete(key);
       +                                }
       +                        }));
       +                })
       +  ).then(self.clients.claim());
        });
        \ No newline at end of file