Responsive Dumb Browser Viewport

Responsive max-500px grayscale viewport with scale, fake slow links, page delay, and video delay.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

Advertisement:

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

Advertisement:

// ==UserScript==
// @name         Responsive Dumb Browser Viewport
// @namespace    https://greasyfork.org/users/your-name
// @version      1.2
// @description  Responsive max-500px grayscale viewport with scale, fake slow links, page delay, and video delay.
// @author       You
// @match        *://*/*
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function () {
  "use strict";

  /*
    Main settings
  */
  const MAX_BOX_WIDTH = "500px";
  const MAX_BOX_HEIGHT = "500px";

  /*
    Mobile fit settings

    Width and height are capped at 500px, but shrink on small screens.
    Lower these if the box still feels too large on mobile.
  */
  const MOBILE_BOX_WIDTH = "92vw";
  const MOBILE_BOX_HEIGHT = "78vh";

  /*
    Scale setting

    1.0 = normal size
    0.9 = slightly smaller
    0.8 = much smaller
    1.1 = larger, not recommended on mobile
  */
  const PAGE_SCALE = 1;

  /*
    Delay settings

    PAGE_REVEAL_DELAY_MS hides the page after load, like slow loading.
    LINK_CLICK_DELAY_MS delays link navigation, like slow internet.
    VIDEO_START_DELAY_MS delays video playback after pressing play.
  */
  const PAGE_REVEAL_DELAY_MS = 700;
  const LINK_CLICK_DELAY_MS = 1200;
  const VIDEO_START_DELAY_MS = 1800;

  /*
    Visual degradation
  */
  const ENABLE_GRAYSCALE = true;
  const ENABLE_MONOSPACE_FONT = false;
  const ENABLE_NO_ROUNDED_CORNERS = false;
  const ENABLE_NO_ANIMATIONS = false;

  /*
    Internal state
  */
  let dumbBrowserAllowNavigation = false;

  function injectStyle() {
    if (document.getElementById("dumb-browser-viewport-style")) return;

    const grayscaleFilter = ENABLE_GRAYSCALE
      ? "grayscale(100%)"
      : "none";

    const monospaceRule = ENABLE_MONOSPACE_FONT
      ? "font-family: monospace !important;"
      : "";

    const noRoundedCornersRule = ENABLE_NO_ROUNDED_CORNERS
      ? "border-radius: 0 !important;"
      : "";

    const noAnimationsRule = ENABLE_NO_ANIMATIONS
      ? `
        animation: none !important;
        transition: none !important;
        scroll-behavior: auto !important;
      `
      : "";

    const style = document.createElement("style");
    style.id = "dumb-browser-viewport-style";

    style.textContent = `
      :root {
        --dumb-box-width: min(${MAX_BOX_WIDTH}, ${MOBILE_BOX_WIDTH});
        --dumb-box-height: min(${MAX_BOX_HEIGHT}, ${MOBILE_BOX_HEIGHT});
        --dumb-page-scale: ${PAGE_SCALE};
      }

      html {
        width: 100vw !important;
        height: 100vh !important;
        min-width: 100vw !important;
        min-height: 100vh !important;
        margin: 0 !important;
        padding: 0 !important;
        overflow: hidden !important;
        background: #111 !important;
        filter: ${grayscaleFilter} !important;
      }

      body {
        width: var(--dumb-box-width) !important;
        height: var(--dumb-box-height) !important;
        max-width: var(--dumb-box-width) !important;
        max-height: var(--dumb-box-height) !important;

        position: fixed !important;
        left: 50% !important;
        top: 50% !important;

        transform:
          translate(-50%, -50%)
          scale(var(--dumb-page-scale)) !important;

        transform-origin: center center !important;

        margin: 0 !important;
        padding: 0 !important;

        overflow-x: auto !important;
        overflow-y: auto !important;
        overscroll-behavior: contain !important;

        background: #fff !important;
        color: #000 !important;

        box-sizing: border-box !important;
        box-shadow: 0 0 0 9999px #111 !important;

        filter: ${grayscaleFilter} !important;
        opacity: 0 !important;

        ${monospaceRule}
      }

      body.dumb-browser-visible {
        opacity: 1 !important;
      }

      body,
      body * {
        box-sizing: border-box !important;
        filter: ${grayscaleFilter} !important;
        ${noRoundedCornersRule}
        ${noAnimationsRule}
      }

      img,
      video,
      canvas,
      iframe,
      svg,
      picture {
        filter: ${grayscaleFilter} !important;
      }
    `;

    document.documentElement.appendChild(style);
  }

  function revealPageAfterDelay() {
    const reveal = () => {
      if (!document.body) return;

      setTimeout(() => {
        document.body.classList.add("dumb-browser-visible");
      }, PAGE_REVEAL_DELAY_MS);
    };

    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", reveal, { once: true });
    } else {
      reveal();
    }
  }

  function addSlowLinkClicks() {
    document.addEventListener(
      "click",
      function (event) {
        const link = event.target.closest && event.target.closest("a[href]");

        if (!link) return;
        if (dumbBrowserAllowNavigation) return;

        const href = link.href;

        if (!href) return;
        if (href.startsWith("javascript:")) return;
        if (href.startsWith("#")) return;

        event.preventDefault();
        event.stopPropagation();

        setTimeout(() => {
          dumbBrowserAllowNavigation = true;
          window.location.href = href;
        }, LINK_CLICK_DELAY_MS);
      },
      true
    );
  }

  function addVideoStartDelay() {
    const delayedVideos = new WeakSet();

    function patchVideo(video) {
      if (!video || delayedVideos.has(video)) return;

      video.addEventListener(
        "play",
        function () {
          if (video.dataset.dumbBrowserVideoAllowed === "true") {
            video.dataset.dumbBrowserVideoAllowed = "false";
            return;
          }

          video.pause();

          setTimeout(() => {
            video.dataset.dumbBrowserVideoAllowed = "true";
            video.play().catch(() => {
              /*
                Some browsers block programmatic play.
                If that happens, the user has to press play again.
              */
            });
          }, VIDEO_START_DELAY_MS);
        },
        true
      );

      delayedVideos.add(video);
    }

    function patchAllVideos() {
      document.querySelectorAll("video").forEach(patchVideo);
    }

    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", patchAllVideos);
    } else {
      patchAllVideos();
    }

    const observer = new MutationObserver(() => {
      patchAllVideos();
    });

    observer.observe(document.documentElement, {
      childList: true,
      subtree: true,
    });
  }

  injectStyle();
  revealPageAfterDelay();
  addSlowLinkClicks();
  addVideoStartDelay();
})();