Responsive Dumb Browser Viewport

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

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Advertisement:

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

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();
})();