From 0d1075773b9b2e5b3d67e1d8741e24314ee72d0e Mon Sep 17 00:00:00 2001 From: Lokwei Hezron <122450611+bugzorc@users.noreply.github.com> Date: Mon, 13 May 2024 00:51:47 +0300 Subject: [PATCH] Add files via upload --- archives.html | 68 ++++++++ blog.html | 58 +++++++ bloghub.html | 90 +++++++++++ index.html | 58 +++---- javascript/beatSync.js | 56 +++++++ javascript/blog.js | 31 ++++ javascript/bloghub.js | 32 ++++ javascript/index.js | 49 ++++++ javascript/music.js | 68 ++++++++ javascript/oneko-ie6.js | 242 ++++++++++++++++++++++++++++ javascript/oneko-webring.js | 306 ++++++++++++++++++++++++++++++++++++ javascript/oneko.js | 239 ++++++++++++++++++++++++++++ javascript/preloader.js | 6 + javascript/print.js | 15 ++ javascript/sparkles.js | 179 +++++++++++++++++++++ 15 files changed, 1469 insertions(+), 28 deletions(-) create mode 100644 archives.html create mode 100644 blog.html create mode 100644 bloghub.html create mode 100644 javascript/beatSync.js create mode 100644 javascript/blog.js create mode 100644 javascript/bloghub.js create mode 100644 javascript/index.js create mode 100644 javascript/music.js create mode 100644 javascript/oneko-ie6.js create mode 100644 javascript/oneko-webring.js create mode 100644 javascript/oneko.js create mode 100644 javascript/preloader.js create mode 100644 javascript/print.js create mode 100644 javascript/sparkles.js diff --git a/archives.html b/archives.html new file mode 100644 index 0000000..cfa543e --- /dev/null +++ b/archives.html @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + +
+
+ + + + + +
+
+ + \ No newline at end of file diff --git a/blog.html b/blog.html new file mode 100644 index 0000000..beffc38 --- /dev/null +++ b/blog.html @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+ + \ No newline at end of file diff --git a/bloghub.html b/bloghub.html new file mode 100644 index 0000000..11d3438 --- /dev/null +++ b/bloghub.html @@ -0,0 +1,90 @@ + + + + BLOG HUB + + + + + + + +
+
+ + + +
+
+
+
+
+
+
+
ALL
+
+
+
+
LOW LEVEL STUFF
+
+
+
+
OPERATING SYSTEMS
+
+
+
+
+
+
NETWORKS
+
+
+
+
PROGRAMMING
+
+
+
+
CHALLENGES
+
+
+
+
+ +
+ +
+
+ + \ No newline at end of file diff --git a/index.html b/index.html index 897b6b9..7b404a6 100644 --- a/index.html +++ b/index.html @@ -8,21 +8,24 @@ BUGZORC - - - - - + + + + + + + +
- - - - - - - +
@@ -97,7 +93,7 @@ - diff --git a/javascript/beatSync.js b/javascript/beatSync.js new file mode 100644 index 0000000..d950297 --- /dev/null +++ b/javascript/beatSync.js @@ -0,0 +1,56 @@ +document.addEventListener("DOMContentLoaded", function() { + const audioElement = document.getElementById('musicPlayer'); + let audioContext; // Define audioContext outside of event listener + + // Function to create AudioContext after user gesture + function initializeAudioContext() { + audioContext = new (window.AudioContext || window.webkitAudioContext)(); + const analyser = audioContext.createAnalyser(); + + // Check if the audioElement is valid + if (audioElement instanceof HTMLMediaElement) { + const source = audioContext.createMediaElementSource(audioElement); + source.connect(analyser); + analyser.connect(audioContext.destination); + + const bufferLength = analyser.frequencyBinCount; + const dataArray = new Uint8Array(bufferLength); + + // Function to update background size based on bass frequency range + function updateBackgroundSize() { + analyser.getByteFrequencyData(dataArray); + + // Extract bass frequencies (20Hz - 200Hz) + const bassArray = dataArray.slice(0, Math.floor(bufferLength * (50 / analyser.frequencyBinCount))); + + // Calculate the average bass amplitude + let total = 0; + for (let i = 0; i < bassArray.length; i++) { + total += bassArray[i]; + } + const averageBassAmplitude = total / bassArray.length; + + // Set background size based on the average bass amplitude + const newSize = 130 + averageBassAmplitude / 10; // Adjust multiplier to control sensitivity + document.body.style.backgroundSize = `${Math.max(newSize, 100)}%`; // Ensure minimum size of 100% + } + + // Start updating background size on audio play + audioElement.addEventListener('play', () => { + setInterval(updateBackgroundSize, 50); // Adjust interval as needed + }); + } else { + console.error("The 'audioElement' is not a valid HTMLMediaElement."); + } + } + + // Event listener for user gesture (e.g., click event) + document.addEventListener('click', function() { + // Check if AudioContext is already created or resumed + if (!audioContext) { + initializeAudioContext(); // Create AudioContext + } else if (audioContext.state === 'suspended') { + audioContext.resume(); // Resume AudioContext if it's suspended + } + }); +}); diff --git a/javascript/blog.js b/javascript/blog.js new file mode 100644 index 0000000..36f327a --- /dev/null +++ b/javascript/blog.js @@ -0,0 +1,31 @@ +// Get the value of the 'file' parameter from the URL +const urlParams = new URLSearchParams(window.location.search); +const fileParam = urlParams.get('file'); + +if (fileParam) { + // Set the title of the page to correspond with the 'file' parameter + document.title = `💾/${fileParam}`; +} + +// If the 'file' parameter is present +if (fileParam) { + // Construct the URL to fetch the corresponding HTML file + const fileURL = `blogs/${fileParam}.html`; + + // Fetch the HTML content of the file + fetch(fileURL) + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.text(); + }) + .then(htmlContent => { + // Insert the fetched HTML content into the div with class 'blogContent' + const blogContentDiv = document.querySelector('.blogContent'); + blogContentDiv.innerHTML = htmlContent; + }) + .catch(error => { + console.error('There was a problem fetching the blog content:', error); + }); +} diff --git a/javascript/bloghub.js b/javascript/bloghub.js new file mode 100644 index 0000000..faa93e6 --- /dev/null +++ b/javascript/bloghub.js @@ -0,0 +1,32 @@ +// Wait for the DOM content to be fully loaded before adding event listeners +document.addEventListener("DOMContentLoaded", function() { + // Function to show all blogs + function showAllBlogs() { + var blogs = document.querySelectorAll('.blog'); + blogs.forEach(function(blog) { + blog.style.display = 'flex'; + }); + } + + // Function to show blogs belonging to a specific category + function showCategory(category) { + var blogs = document.querySelectorAll('.blog'); + blogs.forEach(function(blog) { + var blogCategory = blog.getAttribute('data-category'); + if (blogCategory === category || category === 'ALL') { + blog.style.display = 'flex'; + } else { + blog.style.display = 'none'; + } + }); + } + + // Event listener for navigation items + var navItems = document.querySelectorAll('.blogNav'); + navItems.forEach(function(navItem) { + navItem.addEventListener("click", function() { + var category = this.querySelector('.blogNavText').textContent.trim(); + showCategory(category); + }); + }); +}); diff --git a/javascript/index.js b/javascript/index.js new file mode 100644 index 0000000..bfbf2b5 --- /dev/null +++ b/javascript/index.js @@ -0,0 +1,49 @@ +document.addEventListener("DOMContentLoaded", () => { + const whoamiSpan = document.getElementById("whoami"); + const cursorSpan = document.getElementById("cursor"); + + const jobs = [ + "Malware Analyst", + "Unreal Engine Spc", + "C++ Developer", + "1 Thessalonians 5:11" + ]; + + let i = 0; + let j = 0; + let isDeleting = false; + let speed = 100; + + function type() { + const job = jobs[i % jobs.length]; + + if (!isDeleting) { + whoamiSpan.textContent = "$ whoami: " + job.substring(0, j); + cursorSpan.style.display = "inline-block"; + } else { + whoamiSpan.textContent = "$ whoami: " + job.substring(0, j) + "_"; + cursorSpan.style.display = "none"; + } + + if (!isDeleting && j === job.length) { + setTimeout(() => { + isDeleting = true; + speed = 25; + }, 2500); // wait for 2.5 seconds before deleting + } else if (isDeleting && j === 0) { + isDeleting = false; + i++; + speed = 100; + setTimeout(() => { + speed = 100; + }, 500); // wait for half a second before typing again + } + + j += isDeleting ? -1 : 1; + + setTimeout(type, speed); + } + + type(); + }); + \ No newline at end of file diff --git a/javascript/music.js b/javascript/music.js new file mode 100644 index 0000000..b051685 --- /dev/null +++ b/javascript/music.js @@ -0,0 +1,68 @@ +const musicButton = document.getElementById('musicButton'); +const musicPlayer = document.getElementById('musicPlayer'); + +let isPlaying = false; +let currentSongIndex = 0; +let playbackPosition = 0; // Variable to store the playback position +const songs = [ + "../../storage/music/song1.mp3", + "../../storage/music/song2.mp3", + "../../storage/music/song3.mp3", + "../../storage/music/song4.mp3", + "../../storage/music/song5.mp3", + "../../storage/music/song6.mp3", + "../../storage/music/song7.mp3", + "../../storage/music/song8.mp3", + "../../storage/music/song9.mp3", + "../../storage/music/song10.mp3", + "../../storage/music/song11.mp3", + "../../storage/music/song12.mp3", + "../../storage/music/song13.mp3", + "../../storage/music/song14.mp3" + // Add more songs as needed +]; + +function toggleMusic() { + if (isPlaying) { + playbackPosition = musicPlayer.currentTime; // Store the current playback position + musicPlayer.pause(); + } else { + playCurrentSong(); + } + isPlaying = !isPlaying; + updateButton(); // Update button appearance after toggling playback +} + +function playCurrentSong() { + musicPlayer.src = songs[currentSongIndex]; + musicPlayer.currentTime = playbackPosition; // Set the playback position + musicPlayer.load(); // Ensure the audio is loaded before playing + const playPromise = musicPlayer.play(); + if (playPromise !== undefined) { + playPromise.then(_ => { + // Playback started successfully + console.log('Audio playback started.'); + }).catch(error => { + // Auto-play prevented, handle accordingly + console.error('Auto-play prevented:', error); + }); + } +} + +function playNextSong() { + currentSongIndex = (currentSongIndex + 1) % songs.length; + playbackPosition = 0; // Reset playback position when playing the next song + playCurrentSong(); +} + +function updateButton() { + musicButton.src = isPlaying ? "../../icons/pause.png" : "../../icons/play.png"; +} + +musicButton.addEventListener('click', () => { + toggleMusic(); +}); + +musicPlayer.addEventListener('ended', () => { + playNextSong(); +}); diff --git a/javascript/oneko-ie6.js b/javascript/oneko-ie6.js new file mode 100644 index 0000000..a96d586 --- /dev/null +++ b/javascript/oneko-ie6.js @@ -0,0 +1,242 @@ +function neko() { + 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 direction; + + var IE = document.all ? true : false; + + 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 = "absolute"; + nekoEl.style.pointerEvents = "none"; + nekoEl.style.backgroundImage = "url('oneko.gif')"; + nekoEl.style.imageRendering = "pixelated"; + nekoEl.style.left = nekoPosX - 16 + "px"; + nekoEl.style.top = nekoPosY - 16 + "px"; + nekoEl.style.zIndex = Number.MAX_VALUE; + + document.body.appendChild(nekoEl); + function mousePos(event) { + if (IE) { + event = window.event; + } + mousePosX = event.clientX; + mousePosY = event.clientY - 16; + } + document.onmousemove = mousePos; + window.onekoInterval = setInterval(frame, 100); + } + + function setSprite(name, frame) { + var length = spriteSets[name].length; + if (IE) { + length = 0; + // Internet explorer is really fucking dumb + while (length < spriteSets[name].length) { + if (spriteSets[name][length] != null) { + length = length + 1; + continue; + } + break; + } + } + var sprite = spriteSets[name][frame % length]; + nekoEl.style.backgroundPosition = + sprite["0"] * 32 + "px " + sprite["1"] * 32 + "px"; + } + + function resetIdleAnimation() { + idleAnimation = null; + idleAnimationFrame = 0; + } + + function idle() { + idleTime = 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 = idleAnimationFrame + 1; + } + + function frame() { + frameCount = 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 = idleTime - 1; + return; + } + + direction = ""; + if (diffY / distance > 0.5) { + direction = "N"; + } else if (diffY / distance < -0.5) { + direction = "S"; + } + if (diffX / distance > 0.5) { + direction = direction + "W"; + } else if (diffX / distance < -0.5) { + direction = direction + "E"; + } + setSprite(direction, frameCount); + + if (distance > nekoSpeed) { + nekoPosX = nekoPosX - (diffX / distance) * nekoSpeed; + nekoPosY = nekoPosY - (diffY / distance) * nekoSpeed; + } else { + nekoPosX = mousePosX; + nekoPosY = mousePosY; + } + + nekoPosX = Math.min( + Math.max(16, nekoPosX), + document.getElementsByTagName("body")[0].clientWidth - 16 + ); + nekoPosY = Math.min( + Math.max(16, nekoPosY), + document.getElementsByTagName("body")[0].clientHeight - 16 + ); + + nekoEl.style.left = nekoPosX - 16 + "px"; + nekoEl.style.top = nekoPosY - 16 + "px"; + } + init(); +} +neko(); diff --git a/javascript/oneko-webring.js b/javascript/oneko-webring.js new file mode 100644 index 0000000..9bc7fda --- /dev/null +++ b/javascript/oneko-webring.js @@ -0,0 +1,306 @@ +// oneko.js: https://github.com/adryd325/oneko.js (webring variant) + +(function oneko() { + const isReducedMotion = + window.matchMedia(`(prefers-reduced-motion: reduce)`) === true || + window.matchMedia(`(prefers-reduced-motion: reduce)`).matches === true; + + if (isReducedMotion) return; + + const nekoEl = document.createElement("div"); + + let nekoPosX = 32; + let nekoPosY = 32; + + let mousePosX = 0; + let mousePosY = 0; + + const nekoSites = [ + "adryd.com", + "localhost", + "c7.pm", + "fade.nya.rest", + "fleepy.tv", + "maia.crimew.gay", + "spookyghost.zone", + "noelle.df1.dev", + "www.kibty.town", + "kibty.town", + "avasilver.dev", + "tris.fyi", + "breq.dev" + ]; + + try { + const searchParams = location.search + .replace("?", "") + .split("&") + .map((keyvaluepair) => keyvaluepair.split("=")); + + function posFind(string) { + const result = searchParams.find((a) => a[0] == string); + if (result && result[1]) return parseInt(result[1]); + } + + nekoPosX = posFind("catx") || 32; + nekoPosY = posFind("caty") || 32; + mousePosX = posFind("catdx") || 0; + mousePosY = posFind("catdy") || 0; + } catch (e) { + console.error("oneko.js: failed to parse query params."); + console.error(e); + } + + function onClick(event) { + let target; + if (event.target.tagName === "A" && event.target.getAttribute("href")) { + target = event.target; + } else if ( + event.target.tagName == "IMG" && + event.target.parentElement.tagName === "A" && + event.target.parentElement.getAttribute("href") + ) { + target = event.target.parentElement; + } else { + return; + } + let newLocation; + try { + newLocation = new URL(target.href); + } catch (e) {; + return; + } + if (!nekoSites.includes(newLocation.host) || newLocation.pathname != "/") + return; + newLocation.searchParams.append("catx", Math.floor(nekoPosX)); + newLocation.searchParams.append("caty", Math.floor(nekoPosY)); + newLocation.searchParams.append("catdx", Math.floor(mousePosX)); + newLocation.searchParams.append("catdy", Math.floor(mousePosY)); + event.preventDefault(); + window.location.href = newLocation.toString(); + } + document.addEventListener("click", onClick); + + 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"; + nekoEl.style.imageRendering = "pixelated"; + nekoEl.style.left = `${nekoPosX - 16}px`; + nekoEl.style.top = `${nekoPosY - 16}px`; + nekoEl.style.zIndex = Number.MAX_VALUE; + + let nekoFile = "./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"]; + 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; + 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(); +})(); diff --git a/javascript/oneko.js b/javascript/oneko.js new file mode 100644 index 0000000..bb990af --- /dev/null +++ b/javascript/oneko.js @@ -0,0 +1,239 @@ +// oneko.js: https://github.com/adryd325/oneko.js + +(function oneko() { + const isReducedMotion = + window.matchMedia(`(prefers-reduced-motion: reduce)`) === true || + window.matchMedia(`(prefers-reduced-motion: reduce)`).matches === true; + + if (isReducedMotion) return; + + 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 = 12; + 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"; + nekoEl.style.imageRendering = "pixelated"; + nekoEl.style.left = `${nekoPosX - 16}px`; + nekoEl.style.top = `${nekoPosY - 16}px`; + nekoEl.style.zIndex = -1; + + let nekoFile = "../images/gifs/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"]; + 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; + 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(); +})(); diff --git a/javascript/preloader.js b/javascript/preloader.js new file mode 100644 index 0000000..2d9be07 --- /dev/null +++ b/javascript/preloader.js @@ -0,0 +1,6 @@ +window.addEventListener('load', function() { + var preloader = document.getElementById('preloader'); + var content = document.getElementById('content'); + + preloader.style.display = 'none'; // Hide the preloader +}); diff --git a/javascript/print.js b/javascript/print.js new file mode 100644 index 0000000..6eba8db --- /dev/null +++ b/javascript/print.js @@ -0,0 +1,15 @@ +function printBlog() { + var blogContent = document.getElementsByClassName('blogContent'); + if (blogContent.length > 0) { + var contentToPrint = ''; + for (var i = 0; i < blogContent.length; i++) { + contentToPrint += blogContent[i].innerHTML; + } + var originalContent = document.body.innerHTML; + document.body.innerHTML = contentToPrint; + window.print(); + document.body.innerHTML = originalContent; + } else { + console.error('No elements found with the class "blog"'); + } + } \ No newline at end of file diff --git a/javascript/sparkles.js b/javascript/sparkles.js new file mode 100644 index 0000000..3b65e20 --- /dev/null +++ b/javascript/sparkles.js @@ -0,0 +1,179 @@ + +var colour="random"; +var sparkles=50; +var x=ox=400; +var y=oy=300; +var swide=800; +var shigh=600; +var sleft=sdown=0; +var tiny=new Array(); +var star=new Array(); +var starv=new Array(); +var starx=new Array(); +var stary=new Array(); +var tinyx=new Array(); +var tinyy=new Array(); +var tinyv=new Array(); +window.onload=function() { if (document.getElementById) { + var i, rats, rlef, rdow; + for (var i=0; i1 || Math.abs(y-oy)>1) { + ox=x; + oy=y; + for (c=0; c0) sw_min=document.documentElement.clientWidth; + if (document.documentElement.clientHeight>0) sh_min=document.documentElement.clientHeight; + } + if (typeof(self.innerWidth)=='number' && self.innerWidth) { + if (self.innerWidth>0 && self.innerWidth0 && self.innerHeight0 && document.body.clientWidth0 && document.body.clientHeight