Responsive Dumb Browser Viewport

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

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

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

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Advertisement:

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

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