MediaWiki:Gadget-oneko.js: Difference between revisions

From Discord Client Modding Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
Line 3: Line 3:
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
// https://github.com/adryd325/oneko.js
// https://github.com/adryd325/oneko.js
// compiled to es5 with babel because mediawiki is insane and needs es5


(function oneko() {
(function oneko() {
   const isReducedMotion =
   var isReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)") === true || window.matchMedia("(prefers-reduced-motion: reduce)").matches === true;
    window.matchMedia(`(prefers-reduced-motion: reduce)`) === true ||
    window.matchMedia(`(prefers-reduced-motion: reduce)`).matches === true;
 
   if (isReducedMotion) return;
   if (isReducedMotion) return;
 
   var nekoEl = document.createElement("div");
   const nekoEl = document.createElement("div");
   var nekoPosX = 32;
 
   var nekoPosY = 32;
   let nekoPosX = 32;
   var mousePosX = 0;
   let nekoPosY = 32;
   var mousePosY = 0;
 
   var frameCount = 0;
   let mousePosX = 0;
   var idleTime = 0;
   let mousePosY = 0;
   var idleAnimation = null;
 
   var idleAnimationFrame = 0;
   let frameCount = 0;
   var nekoSpeed = 10;
   let idleTime = 0;
   var spriteSets = {
   let idleAnimation = null;
   let idleAnimationFrame = 0;
 
   const nekoSpeed = 10;
   const spriteSets = {
     idle: [[-3, -3]],
     idle: [[-3, -3]],
     alert: [[-7, -3]],
     alert: [[-7, -3]],
     scratchSelf: [
     scratchSelf: [[-5, 0], [-6, 0], [-7, 0]],
      [-5, 0],
     scratchWallN: [[0, 0], [0, -1]],
      [-6, 0],
     scratchWallS: [[-7, -1], [-6, -2]],
      [-7, 0],
     scratchWallE: [[-2, -2], [-2, -3]],
    ],
     scratchWallW: [[-4, 0], [-4, -1]],
     scratchWallN: [
      [0, 0],
      [0, -1],
    ],
     scratchWallS: [
      [-7, -1],
      [-6, -2],
    ],
     scratchWallE: [
      [-2, -2],
      [-2, -3],
    ],
     scratchWallW: [
      [-4, 0],
      [-4, -1],
    ],
     tired: [[-3, -2]],
     tired: [[-3, -2]],
     sleeping: [
     sleeping: [[-2, 0], [-2, -1]],
      [-2, 0],
     N: [[-1, -2], [-1, -3]],
      [-2, -1],
     NE: [[0, -2], [0, -3]],
    ],
     E: [[-3, 0], [-3, -1]],
     N: [
     SE: [[-5, -1], [-5, -2]],
      [-1, -2],
     S: [[-6, -3], [-7, -2]],
      [-1, -3],
     SW: [[-5, -3], [-6, -1]],
    ],
     W: [[-4, -2], [-4, -3]],
     NE: [
     NW: [[-1, 0], [-1, -1]]
      [0, -2],
      [0, -3],
    ],
     E: [
      [-3, 0],
      [-3, -1],
    ],
     SE: [
      [-5, -1],
      [-5, -2],
    ],
     S: [
      [-6, -3],
      [-7, -2],
    ],
     SW: [
      [-5, -3],
      [-6, -1],
    ],
     W: [
      [-4, -2],
      [-4, -3],
    ],
     NW: [
      [-1, 0],
      [-1, -1],
    ],
   };
   };
   function init() {
   function init() {
     nekoEl.id = "oneko";
     nekoEl.id = "oneko";
Line 96: Line 46:
     nekoEl.style.pointerEvents = "none";
     nekoEl.style.pointerEvents = "none";
     nekoEl.style.imageRendering = "pixelated";
     nekoEl.style.imageRendering = "pixelated";
     nekoEl.style.left = `${nekoPosX - 16}px`;
     nekoEl.style.left = "".concat(nekoPosX - 16, "px");
     nekoEl.style.top = `${nekoPosY - 16}px`;
     nekoEl.style.top = "".concat(nekoPosY - 16, "px");
     nekoEl.style.zIndex = Number.MAX_VALUE;
     nekoEl.style.zIndex = Number.MAX_VALUE;
 
     var nekoFile = "https://wiki.vencord.dev/images/8/8c/Oneko.gif";
     let nekoFile = "https://wiki.vencord.dev/images/8/8c/Oneko.gif";
     var curScript = document.currentScript;
     const curScript = document.currentScript;
     if (curScript && curScript.dataset.cat) {
     if (curScript && curScript.dataset.cat) {
       nekoFile = curScript.dataset.cat;
       nekoFile = curScript.dataset.cat;
     }
     }
     nekoEl.style.backgroundImage = `url(${nekoFile})`;
     nekoEl.style.backgroundImage = "url(".concat(nekoFile, ")");
 
     document.body.appendChild(nekoEl);
     document.body.appendChild(nekoEl);
     document.addEventListener("mousemove", function (event) {
     document.addEventListener("mousemove", function (event) {
       mousePosX = event.clientX;
       mousePosX = event.clientX;
       mousePosY = event.clientY;
       mousePosY = event.clientY;
     });
     });
     window.requestAnimationFrame(onAnimationFrame);
     window.requestAnimationFrame(onAnimationFrame);
   }
   }
 
   var lastFrameTimestamp;
   let lastFrameTimestamp;
 
   function onAnimationFrame(timestamp) {
   function onAnimationFrame(timestamp) {
     // Stops execution if the neko element is removed from DOM
     // Stops execution if the neko element is removed from DOM
Line 133: Line 77:
     window.requestAnimationFrame(onAnimationFrame);
     window.requestAnimationFrame(onAnimationFrame);
   }
   }
   function setSprite(name, frame) {
   function setSprite(name, frame) {
     const sprite = spriteSets[name][frame % spriteSets[name].length];
     var sprite = spriteSets[name][frame % spriteSets[name].length];
     nekoEl.style.backgroundPosition = `${sprite[0] * 32}px ${sprite[1] * 32}px`;
     nekoEl.style.backgroundPosition = "".concat(sprite[0] * 32, "px ").concat(sprite[1] * 32, "px");
   }
   }
   function resetIdleAnimation() {
   function resetIdleAnimation() {
     idleAnimation = null;
     idleAnimation = null;
     idleAnimationFrame = 0;
     idleAnimationFrame = 0;
   }
   }
   function idle() {
   function idle() {
     idleTime += 1;
     idleTime += 1;


     // every ~ 20 seconds
     // every ~ 20 seconds
     if (
     if (idleTime > 10 && Math.floor(Math.random() * 200) == 0 && idleAnimation == null) {
      idleTime > 10 &&
       var avalibleIdleAnimations = ["sleeping", "scratchSelf"];
      Math.floor(Math.random() * 200) == 0 &&
      idleAnimation == null
    ) {
       let avalibleIdleAnimations = ["sleeping", "scratchSelf"];
       if (nekoPosX < 32) {
       if (nekoPosX < 32) {
         avalibleIdleAnimations.push("scratchWallW");
         avalibleIdleAnimations.push("scratchWallW");
Line 166: Line 103:
         avalibleIdleAnimations.push("scratchWallS");
         avalibleIdleAnimations.push("scratchWallS");
       }
       }
       idleAnimation =
       idleAnimation = avalibleIdleAnimations[Math.floor(Math.random() * avalibleIdleAnimations.length)];
        avalibleIdleAnimations[
          Math.floor(Math.random() * avalibleIdleAnimations.length)
        ];
     }
     }
     switch (idleAnimation) {
     switch (idleAnimation) {
       case "sleeping":
       case "sleeping":
Line 199: Line 132:
     idleAnimationFrame += 1;
     idleAnimationFrame += 1;
   }
   }
   function frame() {
   function frame() {
     frameCount += 1;
     frameCount += 1;
     const diffX = nekoPosX - mousePosX;
     var diffX = nekoPosX - mousePosX;
     const diffY = nekoPosY - mousePosY;
     var diffY = nekoPosY - mousePosY;
     const distance = Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2));
     var distance = Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2));
 
     if (distance < nekoSpeed || distance < 48) {
     if (distance < nekoSpeed || distance < 48) {
       idle();
       idle();
       return;
       return;
     }
     }
     idleAnimation = null;
     idleAnimation = null;
     idleAnimationFrame = 0;
     idleAnimationFrame = 0;
     if (idleTime > 1) {
     if (idleTime > 1) {
       setSprite("alert", 0);
       setSprite("alert", 0);
Line 221: Line 150:
       return;
       return;
     }
     }
 
     var direction;
     let direction;
     direction = diffY / distance > 0.5 ? "N" : "";
     direction = diffY / distance > 0.5 ? "N" : "";
     direction += diffY / distance < -0.5 ? "S" : "";
     direction += diffY / distance < -0.5 ? "S" : "";
Line 228: Line 156:
     direction += diffX / distance < -0.5 ? "E" : "";
     direction += diffX / distance < -0.5 ? "E" : "";
     setSprite(direction, frameCount);
     setSprite(direction, frameCount);
 
     nekoPosX -= diffX / distance * nekoSpeed;
     nekoPosX -= (diffX / distance) * nekoSpeed;
     nekoPosY -= diffY / distance * nekoSpeed;
     nekoPosY -= (diffY / distance) * nekoSpeed;
 
     nekoPosX = Math.min(Math.max(16, nekoPosX), window.innerWidth - 16);
     nekoPosX = Math.min(Math.max(16, nekoPosX), window.innerWidth - 16);
     nekoPosY = Math.min(Math.max(16, nekoPosY), window.innerHeight - 16);
     nekoPosY = Math.min(Math.max(16, nekoPosY), window.innerHeight - 16);
 
     nekoEl.style.left = "".concat(nekoPosX - 16, "px");
     nekoEl.style.left = `${nekoPosX - 16}px`;
     nekoEl.style.top = "".concat(nekoPosY - 16, "px");
     nekoEl.style.top = `${nekoPosY - 16}px`;
   }
   }
   init();
   init();
})();
})();

Latest revision as of 20:09, 7 March 2024

// oneko.js
// Copyright © 2022 adryd
// SPDX-License-Identifier: MIT
// https://github.com/adryd325/oneko.js

// compiled to es5 with babel because mediawiki is insane and needs es5

(function oneko() {
  var isReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)") === true || window.matchMedia("(prefers-reduced-motion: reduce)").matches === true;
  if (isReducedMotion) return;
  var nekoEl = document.createElement("div");
  var nekoPosX = 32;
  var nekoPosY = 32;
  var mousePosX = 0;
  var mousePosY = 0;
  var frameCount = 0;
  var idleTime = 0;
  var idleAnimation = null;
  var idleAnimationFrame = 0;
  var nekoSpeed = 10;
  var spriteSets = {
    idle: [[-3, -3]],
    alert: [[-7, -3]],
    scratchSelf: [[-5, 0], [-6, 0], [-7, 0]],
    scratchWallN: [[0, 0], [0, -1]],
    scratchWallS: [[-7, -1], [-6, -2]],
    scratchWallE: [[-2, -2], [-2, -3]],
    scratchWallW: [[-4, 0], [-4, -1]],
    tired: [[-3, -2]],
    sleeping: [[-2, 0], [-2, -1]],
    N: [[-1, -2], [-1, -3]],
    NE: [[0, -2], [0, -3]],
    E: [[-3, 0], [-3, -1]],
    SE: [[-5, -1], [-5, -2]],
    S: [[-6, -3], [-7, -2]],
    SW: [[-5, -3], [-6, -1]],
    W: [[-4, -2], [-4, -3]],
    NW: [[-1, 0], [-1, -1]]
  };
  function init() {
    nekoEl.id = "oneko";
    nekoEl.ariaHidden = true;
    nekoEl.style.width = "32px";
    nekoEl.style.height = "32px";
    nekoEl.style.position = "fixed";
    nekoEl.style.pointerEvents = "none";
    nekoEl.style.imageRendering = "pixelated";
    nekoEl.style.left = "".concat(nekoPosX - 16, "px");
    nekoEl.style.top = "".concat(nekoPosY - 16, "px");
    nekoEl.style.zIndex = Number.MAX_VALUE;
    var nekoFile = "https://wiki.vencord.dev/images/8/8c/Oneko.gif";
    var curScript = document.currentScript;
    if (curScript && curScript.dataset.cat) {
      nekoFile = curScript.dataset.cat;
    }
    nekoEl.style.backgroundImage = "url(".concat(nekoFile, ")");
    document.body.appendChild(nekoEl);
    document.addEventListener("mousemove", function (event) {
      mousePosX = event.clientX;
      mousePosY = event.clientY;
    });
    window.requestAnimationFrame(onAnimationFrame);
  }
  var lastFrameTimestamp;
  function onAnimationFrame(timestamp) {
    // Stops execution if the neko element is removed from DOM
    if (!nekoEl.isConnected) {
      return;
    }
    if (!lastFrameTimestamp) {
      lastFrameTimestamp = timestamp;
    }
    if (timestamp - lastFrameTimestamp > 100) {
      lastFrameTimestamp = timestamp;
      frame();
    }
    window.requestAnimationFrame(onAnimationFrame);
  }
  function setSprite(name, frame) {
    var sprite = spriteSets[name][frame % spriteSets[name].length];
    nekoEl.style.backgroundPosition = "".concat(sprite[0] * 32, "px ").concat(sprite[1] * 32, "px");
  }
  function resetIdleAnimation() {
    idleAnimation = null;
    idleAnimationFrame = 0;
  }
  function idle() {
    idleTime += 1;

    // every ~ 20 seconds
    if (idleTime > 10 && Math.floor(Math.random() * 200) == 0 && idleAnimation == null) {
      var avalibleIdleAnimations = ["sleeping", "scratchSelf"];
      if (nekoPosX < 32) {
        avalibleIdleAnimations.push("scratchWallW");
      }
      if (nekoPosY < 32) {
        avalibleIdleAnimations.push("scratchWallN");
      }
      if (nekoPosX > window.innerWidth - 32) {
        avalibleIdleAnimations.push("scratchWallE");
      }
      if (nekoPosY > window.innerHeight - 32) {
        avalibleIdleAnimations.push("scratchWallS");
      }
      idleAnimation = avalibleIdleAnimations[Math.floor(Math.random() * avalibleIdleAnimations.length)];
    }
    switch (idleAnimation) {
      case "sleeping":
        if (idleAnimationFrame < 8) {
          setSprite("tired", 0);
          break;
        }
        setSprite("sleeping", Math.floor(idleAnimationFrame / 4));
        if (idleAnimationFrame > 192) {
          resetIdleAnimation();
        }
        break;
      case "scratchWallN":
      case "scratchWallS":
      case "scratchWallE":
      case "scratchWallW":
      case "scratchSelf":
        setSprite(idleAnimation, idleAnimationFrame);
        if (idleAnimationFrame > 9) {
          resetIdleAnimation();
        }
        break;
      default:
        setSprite("idle", 0);
        return;
    }
    idleAnimationFrame += 1;
  }
  function frame() {
    frameCount += 1;
    var diffX = nekoPosX - mousePosX;
    var diffY = nekoPosY - mousePosY;
    var distance = Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2));
    if (distance < nekoSpeed || distance < 48) {
      idle();
      return;
    }
    idleAnimation = null;
    idleAnimationFrame = 0;
    if (idleTime > 1) {
      setSprite("alert", 0);
      // count down after being alerted before moving
      idleTime = Math.min(idleTime, 7);
      idleTime -= 1;
      return;
    }
    var direction;
    direction = diffY / distance > 0.5 ? "N" : "";
    direction += diffY / distance < -0.5 ? "S" : "";
    direction += diffX / distance > 0.5 ? "W" : "";
    direction += diffX / distance < -0.5 ? "E" : "";
    setSprite(direction, frameCount);
    nekoPosX -= diffX / distance * nekoSpeed;
    nekoPosY -= diffY / distance * nekoSpeed;
    nekoPosX = Math.min(Math.max(16, nekoPosX), window.innerWidth - 16);
    nekoPosY = Math.min(Math.max(16, nekoPosY), window.innerHeight - 16);
    nekoEl.style.left = "".concat(nekoPosX - 16, "px");
    nekoEl.style.top = "".concat(nekoPosY - 16, "px");
  }
  init();
})();