feat!: inserted new site
This commit is contained in:
7
src/js/bootstrap.min.js
vendored
Normal file
7
src/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
49
src/js/main.js
Normal file
49
src/js/main.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const starback = new Starback("#canvas", {
|
||||
width: document.body.clientWidth,
|
||||
height: document.body.clientHeight,
|
||||
type: 'dot',
|
||||
quantity: 100,
|
||||
direction: 225,
|
||||
backgroundColor: ['#0e1118', '#232b3e'],
|
||||
randomOpacity: true,
|
||||
});
|
||||
const mountain = new Image();
|
||||
mountain.src = 'img/mountain2.png';
|
||||
mountain.onload = () => {
|
||||
starback.addToFront((ctx) => {
|
||||
ctx.drawImage(
|
||||
mountain,
|
||||
0,
|
||||
0,
|
||||
mountain.width,
|
||||
mountain.height,
|
||||
0,
|
||||
canvas.height - mountain.height,
|
||||
canvas.width,
|
||||
mountain.height
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function resizeCanvas() {
|
||||
const canvas = document.getElementById("canvas");
|
||||
canvas.setAttribute("width", window.innerWidth);
|
||||
canvas.setAttribute("height", window.innerHeight);
|
||||
}
|
||||
|
||||
function onLoadDoc() {
|
||||
resizeCanvas();
|
||||
const elements = document.getElementsByClassName("nav-link");
|
||||
for (const el of elements) {
|
||||
el.onclick = onNavLinkClick;
|
||||
}
|
||||
}
|
||||
|
||||
function onNavLinkClick() {
|
||||
const collapse = document.getElementsByClassName('navbar-collapse');
|
||||
if (collapse[0] != null)
|
||||
collapse[0].classList.remove('show');
|
||||
}
|
||||
|
||||
window.addEventListener("resize", resizeCanvas);
|
||||
window.addEventListener("load", onLoadDoc);
|
310
src/js/oneko.js
Normal file
310
src/js/oneko.js
Normal file
@@ -0,0 +1,310 @@
|
||||
// oneko.js: https://github.com/adryd325/oneko.js
|
||||
|
||||
var onekoEnabled = true;
|
||||
|
||||
(function oneko() {
|
||||
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
||||
|
||||
const isReducedMotion =
|
||||
window.matchMedia(`(prefers-reduced-motion: reduce)`) === true ||
|
||||
window.matchMedia(`(prefers-reduced-motion: reduce)`).matches === true;
|
||||
|
||||
if (isReducedMotion || isMobile)
|
||||
{
|
||||
console.log("disabling cat");
|
||||
onekoEnabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const nekoEl = document.createElement("div");
|
||||
|
||||
let nekoPosX = window.innerWidth + 32;
|
||||
let nekoPosY = window.innerHeight + 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],
|
||||
],
|
||||
};
|
||||
|
||||
function init() {
|
||||
nekoEl.id = "oneko";
|
||||
nekoEl.ariaHidden = true;
|
||||
nekoEl.style.width = "32px";
|
||||
nekoEl.style.height = "32px";
|
||||
nekoEl.style.position = "fixed";
|
||||
nekoEl.style.pointerEvents = "none"; // no petting :(
|
||||
nekoEl.style.imageRendering = "pixelated";
|
||||
nekoEl.style.left = `${nekoPosX - 16}px`;
|
||||
nekoEl.style.top = `${nekoPosY - 16}px`;
|
||||
nekoEl.style.zIndex = 999999;
|
||||
|
||||
let nekoFile = "/img/oneko.gif"
|
||||
const curScript = document.currentScript
|
||||
if (curScript && curScript.dataset.cat) {
|
||||
nekoFile = curScript.dataset.cat
|
||||
}
|
||||
nekoEl.style.backgroundImage = `url(${nekoFile})`;
|
||||
|
||||
document.body.appendChild(nekoEl);
|
||||
|
||||
document.addEventListener("mousemove", function(event) {
|
||||
mousePosX = event.clientX;
|
||||
mousePosY = event.clientY;
|
||||
});
|
||||
|
||||
window.requestAnimationFrame(onAnimationFrame);
|
||||
}
|
||||
|
||||
let 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) {
|
||||
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 &&
|
||||
Math.floor(Math.random() * 200) == 0 &&
|
||||
idleAnimation == null
|
||||
) {
|
||||
let avalibleIdleAnimations = ["sleeping", "scratchSelf"];
|
||||
let scratchDist = 64;
|
||||
if (nekoPosX < scratchDist) {
|
||||
avalibleIdleAnimations.push("scratchWallW");
|
||||
}
|
||||
if (nekoPosY < scratchDist) {
|
||||
avalibleIdleAnimations.push("scratchWallN");
|
||||
}
|
||||
if (nekoPosX > window.innerWidth - scratchDist) {
|
||||
avalibleIdleAnimations.push("scratchWallE");
|
||||
}
|
||||
if (nekoPosY > window.innerHeight - scratchDist) {
|
||||
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 explodeHearts() {
|
||||
const parent = nekoEl.parentElement;
|
||||
const rect = nekoEl.getBoundingClientRect();
|
||||
const scrollLeft = window.scrollX || document.documentElement.scrollLeft;
|
||||
const scrollTop = window.scrollY || document.documentElement.scrollTop;
|
||||
const centerX = rect.left + rect.width / 2 + scrollLeft;
|
||||
const centerY = rect.top + rect.height / 2 + scrollTop;
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const heart = document.createElement('div');
|
||||
heart.className = 'heart';
|
||||
heart.textContent = 'â¤';
|
||||
const offsetX = (Math.random() - 0.5) * 50;
|
||||
const offsetY = (Math.random() - 0.5) * 50;
|
||||
heart.style.left = `${centerX + offsetX - 16}px`;
|
||||
heart.style.top = `${centerY + offsetY - 16}px`;
|
||||
heart.style.transform = `translate(-50%, -50%) rotate(${Math.random() * 360}deg)`;
|
||||
parent.appendChild(heart);
|
||||
|
||||
setTimeout(() => {
|
||||
parent.removeChild(heart);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
const style = document.createElement('style');
|
||||
style.innerHTML = `
|
||||
@keyframes heartBurst {
|
||||
0% { transform: scale(0); opacity: 1; }
|
||||
100% { transform: scale(1); opacity: 0; }
|
||||
}
|
||||
.heart {
|
||||
position: absolute;
|
||||
font-size: 2em;
|
||||
animation: heartBurst 1s ease-out;
|
||||
animation-fill-mode: forwards;
|
||||
color: #ab9df2;
|
||||
user-select: none;
|
||||
}
|
||||
`;
|
||||
|
||||
document.head.appendChild(style);
|
||||
nekoEl.addEventListener('click', explodeHearts);
|
||||
|
||||
let previousOnekoEnabled = onekoEnabled;
|
||||
function frame() {
|
||||
if(previousOnekoEnabled != onekoEnabled)
|
||||
{
|
||||
nekoEl.style.display = onekoEnabled ? "block" : "none";
|
||||
|
||||
if(onekoEnabled)
|
||||
document.getElementById("toggle-cat").classList.remove("sleepy");
|
||||
else
|
||||
document.getElementById("toggle-cat").classList.add("sleepy");
|
||||
|
||||
previousOnekoEnabled = onekoEnabled;
|
||||
}
|
||||
|
||||
if (!onekoEnabled || mousePosX == 0 || mousePosY == 0)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
let 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 = `${nekoPosX - 16}px`;
|
||||
nekoEl.style.top = `${nekoPosY - 16}px`;
|
||||
}
|
||||
|
||||
init();
|
||||
})();
|
1
src/js/starback.js
Normal file
1
src/js/starback.js
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user