summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--static/404.html15
-rw-r--r--static/js/oneko.js165
-rw-r--r--static/oneko.gifbin0 -> 3316 bytes
3 files changed, 172 insertions, 8 deletions
diff --git a/static/404.html b/static/404.html
index c9cbca36..f3de5a77 100644
--- a/static/404.html
+++ b/static/404.html
@@ -2,22 +2,20 @@
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
- <title>Page not found | GrapheneOS</title>
+ <title>Page not found | Hakurei</title>
<meta name="description" content="The requested page does not exist."/>
<meta name="theme-color" content="#212121"/>
<meta name="color-scheme" content="dark light"/>
<meta name="msapplication-TileColor" content="#ffffff"/>
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
- <meta name="twitter:site" content="@GrapheneOS"/>
- <meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="Page not found"/>
<meta property="og:description" content="The requested page does not exist."/>
<meta property="og:type" content="website"/>
- <meta property="og:image" content="https://grapheneos.org/opengraph.png"/>
+ <meta property="og:image" content="https://hakurei.app/opengraph.png"/>
<meta property="og:image:width" content="512"/>
<meta property="og:image:height" content="512"/>
- <meta property="og:image:alt" content="GrapheneOS logo"/>
- <meta property="og:site_name" content="GrapheneOS"/>
+ <meta property="og:image:alt" content="Hakurei logo"/>
+ <meta property="og:site_name" content="Hakurei"/>
<link rel="icon" href="/favicon.ico"/>
<link rel="icon" sizes="any" type="image/svg+xml" href="/favicon.svg"/>
<link rel="mask-icon" href="[[path|/mask-icon.svg]]" color="#1a1a1a"/>
@@ -25,7 +23,8 @@
[[css|/main.css]]
<link rel="manifest" href="/manifest.webmanifest"/>
<link rel="license" href="/LICENSE.txt"/>
- <link rel="me" href="https://grapheneos.social/@GrapheneOS"/>
+ <link rel="me" href="https://port.mk/@hakurei"/>
+ [[js|/js/oneko.js]]
</head>
<body>
{% include "header.html" %}
@@ -33,7 +32,7 @@
<h1><a href="#page-not-found">Page not found</a></h1>
<p>The requested page does not exist. If you think this is a mistake, please
- <a href="https://github.com/GrapheneOS/grapheneos.org/issues">report an issue</a>.</p>
+ <a href="https://git.gensokyo.uk/security/hakurei.app/issues">report an issue</a>.</p>
</main>
{% include "footer.html" %}
</body>
diff --git a/static/js/oneko.js b/static/js/oneko.js
new file mode 100644
index 00000000..2f01bbcf
--- /dev/null
+++ b/static/js/oneko.js
@@ -0,0 +1,165 @@
+(function 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]],
+ scratch: [
+ [-5, 0],
+ [-6, 0],
+ [-7, 0],
+ ],
+ 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 create() {
+ nekoEl.id = "oneko";
+ nekoEl.style.width = "32px";
+ nekoEl.style.height = "32px";
+ nekoEl.style.position = "fixed";
+ nekoEl.style.pointerEvents = "none";
+ nekoEl.style.backgroundImage = "url('/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;
+ };
+
+ window.onekoInterval = setInterval(frame, 100);
+ }
+
+ 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
+ ) {
+ idleAnimation = ["sleeping", "scratch"][
+ Math.floor(Math.random() * 2)
+ ];
+ }
+
+ switch (idleAnimation) {
+ case "sleeping":
+ if (idleAnimationFrame < 8) {
+ setSprite("tired", 0);
+ break;
+ }
+ setSprite("sleeping", Math.floor(idleAnimationFrame / 4));
+ if (idleAnimationFrame > 192) {
+ resetIdleAnimation();
+ }
+ break;
+ case "scratch":
+ setSprite("scratch", 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 = 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;
+
+ nekoEl.style.left = `${nekoPosX - 16}px`;
+ nekoEl.style.top = `${nekoPosY - 16}px`;
+ }
+
+ create();
+})();
diff --git a/static/oneko.gif b/static/oneko.gif
new file mode 100644
index 00000000..a009c2cc
--- /dev/null
+++ b/static/oneko.gif
Binary files differ