window.addEventListener("load", () => main()); const main = () => { /* Handle change of focus */ const title = document.title; const blurMessage = "Hey.. come back!"; window.addEventListener("blur", function () { document.title = blurMessage; }); window.addEventListener("focus", function () { document.title = title; }); /* Mouse cursor */ const nb_available_cursors = 2; const id = Math.floor(Math.random() * nb_available_cursors); document.body.style = `cursor: url('/cursors/${id}.png'), default;`; new cursoreffects.fairyDustCursor(); oneko(); /* Nb of visitors */ document.getElementById("visitors-number").innerHTML = Math.floor(Math.random() * 3578) + 1312; /* Scroll text */ document.getElementById("scroll-text").firstElementChild.innerHTML = "WELCOME HERE IN MY WEBSPACE! ".repeat(3); }; /** https://github.com/adryd325/oneko.js */ const oneko = () => { const nekoEl = document.createElement("div"); let nekoPosX = 32; let nekoPosY = 32; let mousePosX = 0; let mousePosY = 0; let frameCount = 0; let idleTime = 0; let idleAnimation = null; let idleAnimationFrame = 0; const nekoSpeed = 10; const 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], ], }; const create = () => { nekoEl.id = "oneko"; nekoEl.style.width = "32px"; nekoEl.style.height = "32px"; nekoEl.style.position = "fixed"; nekoEl.style.pointerEvents = "none"; nekoEl.style.backgroundImage = "url('./pics/oneko.gif')"; nekoEl.style.imageRendering = "pixelated"; nekoEl.style.left = `${nekoPosX - 16}px`; nekoEl.style.top = `${nekoPosY - 16}px`; nekoEl.style.zIndex = "999"; document.body.appendChild(nekoEl); document.onmousemove = (event) => { mousePosX = event.clientX; mousePosY = event.clientY; }; window.onekoInterval = setInterval(frame, 100); }; const setSprite = (name, frame) => { const sprite = spriteSets[name][frame % spriteSets[name].length]; nekoEl.style.backgroundPosition = `${sprite[0] * 32}px ${sprite[1] * 32}px`; }; const resetIdleAnimation = () => { idleAnimation = null; idleAnimationFrame = 0; }; const idle = () => { idleTime++; /* every ~ 20 seconds */ if ( idleTime > 10 && Math.floor(Math.random() * 200) == 0 && idleAnimation == null ) { let 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++; }; const frame = () => { frameCount++; const diffX = nekoPosX - mousePosX; const diffY = nekoPosY - mousePosY; const distance = Math.sqrt(diffX ** 2 + 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; } 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 = `${nekoPosX - 16}px`; nekoEl.style.top = `${nekoPosY - 16}px`; }; create(); };