forked from nyancrimew/maia.crimew.gay
oneko: honor prefers reduced motion
This commit is contained in:
parent
584aa15038
commit
454b6eaaf7
1 changed files with 197 additions and 192 deletions
|
@ -1,199 +1,204 @@
|
||||||
// based on oneko.js from https://github.com/adryd325/oneko.js, licensed under MIT, with art from https://twitter.com/_Anunnery
|
// based on oneko.js from https://github.com/adryd325/oneko.js, licensed under MIT, with art from https://twitter.com/_Anunnery
|
||||||
|
|
||||||
(function oneko() {
|
function oneko() {
|
||||||
const nekoEl = document.createElement("div");
|
const nekoEl = document.createElement("div");
|
||||||
let nekoPosX = 32;
|
let nekoPosX = 32;
|
||||||
let nekoPosY = 32;
|
let nekoPosY = 32;
|
||||||
let mousePosX = 0;
|
let mousePosX = 0;
|
||||||
let mousePosY = 0;
|
let mousePosY = 0;
|
||||||
let frameCount = 0;
|
let frameCount = 0;
|
||||||
let idleTime = 0;
|
let idleTime = 0;
|
||||||
let idleAnimation = null;
|
let idleAnimation = null;
|
||||||
let idleAnimationFrame = 0;
|
let idleAnimationFrame = 0;
|
||||||
const nekoSpeed = 10;
|
const nekoSpeed = 10;
|
||||||
const spriteSets = {
|
const spriteSets = {
|
||||||
idle: [[-3, -3]],
|
idle: [[-3, -3]],
|
||||||
alert: [[-7, -3]],
|
alert: [[-7, -3]],
|
||||||
scratchSelf: [
|
scratchSelf: [
|
||||||
[-5, 0],
|
[-5, 0],
|
||||||
[-6, 0],
|
[-6, 0],
|
||||||
[-7, 0],
|
[-7, 0],
|
||||||
],
|
],
|
||||||
scratchWallN: [
|
scratchWallN: [
|
||||||
[0, 0],
|
[0, 0],
|
||||||
[0, -1],
|
[0, -1],
|
||||||
],
|
],
|
||||||
scratchWallS: [
|
scratchWallS: [
|
||||||
[-7, -1],
|
[-7, -1],
|
||||||
[-6, -2],
|
[-6, -2],
|
||||||
],
|
],
|
||||||
scratchWallE: [
|
scratchWallE: [
|
||||||
[-2, -2],
|
[-2, -2],
|
||||||
[-2, -3],
|
[-2, -3],
|
||||||
],
|
],
|
||||||
scratchWallW: [
|
scratchWallW: [
|
||||||
[-4, 0],
|
[-4, 0],
|
||||||
[-4, -1],
|
[-4, -1],
|
||||||
],
|
],
|
||||||
tired: [[-3, -2]],
|
tired: [[-3, -2]],
|
||||||
sleeping: [
|
sleeping: [
|
||||||
[-2, 0],
|
[-2, 0],
|
||||||
[-2, -1],
|
[-2, -1],
|
||||||
],
|
],
|
||||||
N: [
|
N: [
|
||||||
[-1, -2],
|
[-1, -2],
|
||||||
[-1, -3],
|
[-1, -3],
|
||||||
],
|
],
|
||||||
NE: [
|
NE: [
|
||||||
[0, -2],
|
[0, -2],
|
||||||
[0, -3],
|
[0, -3],
|
||||||
],
|
],
|
||||||
E: [
|
E: [
|
||||||
[-3, 0],
|
[-3, 0],
|
||||||
[-3, -1],
|
[-3, -1],
|
||||||
],
|
],
|
||||||
SE: [
|
SE: [
|
||||||
[-5, -1],
|
[-5, -1],
|
||||||
[-5, -2],
|
[-5, -2],
|
||||||
],
|
],
|
||||||
S: [
|
S: [
|
||||||
[-6, -3],
|
[-6, -3],
|
||||||
[-7, -2],
|
[-7, -2],
|
||||||
],
|
],
|
||||||
SW: [
|
SW: [
|
||||||
[-5, -3],
|
[-5, -3],
|
||||||
[-6, -1],
|
[-6, -1],
|
||||||
],
|
],
|
||||||
W: [
|
W: [
|
||||||
[-4, -2],
|
[-4, -2],
|
||||||
[-4, -3],
|
[-4, -3],
|
||||||
],
|
],
|
||||||
NW: [
|
NW: [
|
||||||
[-1, 0],
|
[-1, 0],
|
||||||
[-1, -1],
|
[-1, -1],
|
||||||
],
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
function create() {
|
||||||
|
nekoEl.id = "oneko";
|
||||||
|
nekoEl.style.width = "32px";
|
||||||
|
nekoEl.style.height = "32px";
|
||||||
|
nekoEl.style.position = "fixed";
|
||||||
|
nekoEl.style.pointerEvents = "none";
|
||||||
|
nekoEl.style.backgroundImage = "url('/img/maia_oneko.gif')";
|
||||||
|
nekoEl.style.imageRendering = "pixelated";
|
||||||
|
nekoEl.style.left = "16px";
|
||||||
|
nekoEl.style.top = "16px";
|
||||||
|
|
||||||
|
document.body.appendChild(nekoEl);
|
||||||
|
|
||||||
|
document.onmousemove = (event) => {
|
||||||
|
mousePosX = event.clientX;
|
||||||
|
mousePosY = event.clientY;
|
||||||
};
|
};
|
||||||
|
|
||||||
function create() {
|
window.onekoInterval = setInterval(frame, 100);
|
||||||
nekoEl.id = "oneko";
|
}
|
||||||
nekoEl.style.width = "32px";
|
|
||||||
nekoEl.style.height = "32px";
|
function setSprite(name, frame) {
|
||||||
nekoEl.style.position = "fixed";
|
const sprite = spriteSets[name][frame % spriteSets[name].length];
|
||||||
nekoEl.style.pointerEvents = "none";
|
nekoEl.style.backgroundPosition = `${sprite[0] * 32}px ${sprite[1] * 32}px`;
|
||||||
nekoEl.style.backgroundImage = "url('/img/maia_oneko.gif')";
|
}
|
||||||
nekoEl.style.imageRendering = "pixelated";
|
|
||||||
nekoEl.style.left = "16px";
|
function resetIdleAnimation() {
|
||||||
nekoEl.style.top = "16px";
|
idleAnimation = null;
|
||||||
|
idleAnimationFrame = 0;
|
||||||
document.body.appendChild(nekoEl);
|
}
|
||||||
|
|
||||||
document.onmousemove = (event) => {
|
function idle() {
|
||||||
mousePosX = event.clientX;
|
idleTime += 1;
|
||||||
mousePosY = event.clientY;
|
|
||||||
};
|
// every ~ 20 seconds
|
||||||
|
if (idleTime > 10 && true && idleAnimation == null) {
|
||||||
window.onekoInterval = setInterval(frame, 100);
|
let avalibleIdleAnimations = ["sleeping", "scratchSelf"];
|
||||||
}
|
if (nekoPosX < 32) {
|
||||||
|
avalibleIdleAnimations.push("scratchWallW");
|
||||||
function setSprite(name, frame) {
|
|
||||||
const sprite = spriteSets[name][frame % spriteSets[name].length];
|
|
||||||
nekoEl.style.backgroundPosition = `${sprite[0] * 32}px ${sprite[1] * 32}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetIdleAnimation() {
|
|
||||||
idleAnimation = null;
|
|
||||||
idleAnimationFrame = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function idle() {
|
|
||||||
idleTime += 1;
|
|
||||||
|
|
||||||
// every ~ 20 seconds
|
|
||||||
if (idleTime > 10 && true && 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)
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
if (nekoPosY < 32) {
|
||||||
switch (idleAnimation) {
|
avalibleIdleAnimations.push("scratchWallN");
|
||||||
case "sleeping":
|
}
|
||||||
if (idleAnimationFrame < 8) {
|
if (nekoPosX > window.innerWidth - 32) {
|
||||||
setSprite("tired", 0);
|
avalibleIdleAnimations.push("scratchWallE");
|
||||||
break;
|
}
|
||||||
}
|
if (nekoPosY > window.innerHeight - 32) {
|
||||||
setSprite("sleeping", Math.floor(idleAnimationFrame / 4));
|
avalibleIdleAnimations.push("scratchWallS");
|
||||||
if (idleAnimationFrame > 192) {
|
}
|
||||||
resetIdleAnimation();
|
idleAnimation =
|
||||||
}
|
avalibleIdleAnimations[
|
||||||
|
Math.floor(Math.random() * avalibleIdleAnimations.length)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (idleAnimation) {
|
||||||
|
case "sleeping":
|
||||||
|
if (idleAnimationFrame < 8) {
|
||||||
|
setSprite("tired", 0);
|
||||||
break;
|
break;
|
||||||
case "scratchWallN":
|
}
|
||||||
case "scratchWallS":
|
setSprite("sleeping", Math.floor(idleAnimationFrame / 4));
|
||||||
case "scratchWallE":
|
if (idleAnimationFrame > 192) {
|
||||||
case "scratchWallW":
|
resetIdleAnimation();
|
||||||
case "scratchSelf":
|
}
|
||||||
setSprite(idleAnimation, idleAnimationFrame);
|
break;
|
||||||
if (idleAnimationFrame > 9) {
|
case "scratchWallN":
|
||||||
resetIdleAnimation();
|
case "scratchWallS":
|
||||||
}
|
case "scratchWallE":
|
||||||
break;
|
case "scratchWallW":
|
||||||
default:
|
case "scratchSelf":
|
||||||
setSprite("idle", 0);
|
setSprite(idleAnimation, idleAnimationFrame);
|
||||||
return;
|
if (idleAnimationFrame > 9) {
|
||||||
}
|
resetIdleAnimation();
|
||||||
idleAnimationFrame += 1;
|
}
|
||||||
}
|
break;
|
||||||
|
default:
|
||||||
function frame() {
|
setSprite("idle", 0);
|
||||||
frameCount += 1;
|
|
||||||
const diffX = nekoPosX - mousePosX;
|
|
||||||
const diffY = nekoPosY - mousePosY;
|
|
||||||
const distance = Math.sqrt(diffX ** 2 + diffY ** 2);
|
|
||||||
|
|
||||||
if (distance < nekoSpeed || distance < 48) {
|
|
||||||
idle();
|
|
||||||
return;
|
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`;
|
|
||||||
}
|
}
|
||||||
|
idleAnimationFrame += 1;
|
||||||
create();
|
}
|
||||||
})();
|
|
||||||
|
function frame() {
|
||||||
|
frameCount += 1;
|
||||||
|
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();
|
||||||
|
};
|
||||||
|
|
||||||
|
const isReduced = window.matchMedia(`(prefers-reduced-motion: reduce)`) === true || window.matchMedia(`(prefers-reduced-motion: reduce)`).matches === true;
|
||||||
|
if (!isReduced) {
|
||||||
|
oneko();
|
||||||
|
}
|
Loading…
Reference in a new issue