feat!: inserted new site

This commit is contained in:
Ward Truyen
2025-07-27 14:10:59 +02:00
parent 90cdef8909
commit 651dd34bf5
26 changed files with 852 additions and 0 deletions

6
src/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

150
src/css/style.css Normal file
View File

@@ -0,0 +1,150 @@
.navbar{
background-color: #000b;
/* background: linear-gradient(0deg,rgba(35, 43, 62, 200) 0%, rgba(0, 0, 0, 200) 100%); */
border-bottom: 1px solid grey;
}
.divider {
height: 3rem;
background-color: rgba(0, 0, 0, .1);
border: solid rgba(0, 0, 0, .15);
border-width: 1px 0;
box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
}
.my-picture{
width: 8em;
aspect-ratio: 1;
border-radius: 5px;
float: right;
}
.img-icon {
width: 4em;
aspect-ratio: 1;
margin: .5em .5em;
padding: 3px;
transition: all .2s;
border-radius: 5px;
}
.img-icon:hover {
width: 5em;
margin: 0;
border: 1px solid white;
box-shadow: 0 0 15px rgba(255, 255, 255, .8);
background-color: #FFFFFF88;
}
.card {
width: 40rem;
padding: 10px;
border: 1px solid black;
background-color: #aaaaaadd;
border-radius: 0.5em;
box-shadow: .5em .5em 1.5em rgba(0, 0, 0, .3);
margin: 1em 0.5em;
display: inline-block;
box-shadow: inset 0 0 3px black;
}
.card iframe {
width: 100%;
aspect-ratio: 16/9;
}
.card a {
color: #0000FF;
}
a {
color: #8888FF;
}
.carousel {
max-width: 80vh;
}
.carousel-control-next,
.carousel-control-prev {
filter: brightness(.5) drop-shadow(0px 0px 1px #FFFFFF);
}
.carousel-caption>h5 {
color: #aaaaffdd;
}
.carousel-indicators [data-bs-target] {
background-color: #aaaaffdd;
}
.attention {
font-size: 1.6em;
}
.rowlines-short li:not(:last-of-type)::after {
content: "";
width: 52%;
margin: 0 4rem;
border-bottom: 1px solid #66666688;
}
.rowlines li:not(:last-of-type)::after {
content: "";
width: 78%;
margin: 0 5rem;
border-bottom: 1px solid #66666688;
}
.rowlines-short li,
.rowlines li {
transition: all .2s;
}
.rowlines li:hover {
/* background-color: #8888; */
box-shadow: inset 0 0 3px white;
text-decoration: underline;
}
.rowlines-short li:hover {
text-decoration: underline;
}
canvas {
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
z-index: -2;
}
body {
overflow-x: hidden;
}
#canvas {
position: fixed;
top: 0px;
height: 100%;
width: 100%;
}
.note {
background: #00000032;
border: 2px solid #888888;
border-radius: 0.5em;
box-shadow: .5em .5em 1.5em rgba(0, 0, 0, .3);
padding: 1em;
margin: 1em auto;
width: 50%;
}
@media (max-width: 800px) {
.note {
width: 80%;
}
.card {
width: 32rem;
}
}

Binary file not shown.

BIN
src/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
src/img/arch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
src/img/docker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
src/img/gitea.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
src/img/lua.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
src/img/me.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
src/img/mountain2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
src/img/neovim.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
src/img/nginx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
src/img/oneko.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
src/img/tds1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
src/img/tds2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
src/img/tds3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
src/img/tds4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

BIN
src/img/traefik.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
src/img/tux.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
src/img/windows.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
src/img/wterminal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

329
src/index.html Normal file
View File

@@ -0,0 +1,329 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ward Truyen's CV</title>
<meta name="description" content="Op zoek naar een Java developer job.">
<!-- Facebook Meta Tags -->
<meta property="og:url" content="https://www.ward.truyen.network/">
<meta property="og:type" content="website">
<meta property="og:title" content="Ward Truyen's CV">
<meta property="og:description" content="Op zoek naar een Java developer job.">
<meta property="og:image" content="/img/me.jpg">
<!-- Twitter Meta Tags -->
<meta name="twitter:card" content="summary_large_image">
<meta property="twitter:domain" content="ward.truyen.network">
<meta property="twitter:url" content="https://www.ward.truyen.network/">
<meta name="twitter:title" content="Ward Truyen's CV">
<meta name="twitter:description" content="Op zoek naar een Java developer job.">
<meta name="twitter:image" content="/img/me.jpg">
<link rel="stylesheet" href="css/bootstrap.min.css" />
<link rel="stylesheet" href="css/style.css">
</head>
<body class="text-bg-dark bg-dark">
<header>
<nav class="navbar navbar-expand-md fixed-top navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">Ward Truyen</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown"
aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavDropdown">
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="#skills">Vaardigheden</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#werk">Werkervaring</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#studies">Studies</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#portfolio">Portfolio</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<main>
<h1 class="visually-hidden">Ward Truyen's CV</h1>
<section id="intro">
<div class="p-2 my-5">
<div class="note">
<h2 class="d-inline">Introductie</h2>
<img class="my-picture d-none d-md-block" src="/img/me.jpg" alt="[my picture]" />
<p>Ik ben een computer liefhebber met een gedreven, hulpvaardig karakter en een zeer technisch geinformeerde
achtergrond. Bijleren doe ik graag. Werk met structuur en orde. Ik ben geduldig,
zal met volle concentratie problemen aanpakken en streven naar afwerking. Je kan me vinden voor een
aangename babbel of een luisterend oor.</p>
<a href="docs/cv-wardtruyen-2025-Java.pdf" class="btn btn-primary" download>Download mijn CV</a>
</div>
</div>
</section>
<div id="skills" class="divider"></div>
<section>
<div class="px-4 py-4">
<h2>Vaardigheden</h2>
<div class="row">
<div class="col-4">
<h4>Back-end</h4>
<ul>
<li>Java EE</li>
<li>Spring &amp; REST</li>
<li>SQL &amp; Hibernate</li>
<li>Lombok</li>
<li>Maven &amp; Gradle</li>
<li>JSP</li>
<li>JUnit</li>
<li>Multithreading &amp; Concurrency</li>
</ul>
</div>
<div class="col-4">
<h4>Front-end</h4>
<ul>
<li>JavaScript</li>
<li>TypeScript</li>
<li>Angular</li>
<li>HTML &amp; CSS</li>
<li>NPM</li>
<li>JQuery</li>
<li>Bootstrap</li>
<li>async &amp; wait</li>
</ul>
</div>
<div class="col-4">
<h4>Tools</h4>
<ul>
<li>Git</li>
<li>Scrutm &amp; Agile</li>
<li>VS code &amp; IntelliJ &amp; vim</li>
<li>Docker &amp; Virtualisatie</li>
<li>CI/CD</li>
<li>Powershell &amp; bash</li>
<li>Terminal &amp; SSH</li>
</ul>
</div>
</div>
<div class="row justify-content-center">
<img class="img-icon" src="img/tux.png" alt="Linux" title="Tux, the linux mascot" />
<img class="img-icon" src="img/arch.png" alt="Arch linux" title="Arch linux" />
<img class="img-icon" src="img/windows.png" alt="Windows" title="MS Windows" />
<img class="img-icon" src="img/traefik.png" alt="Traefik" title="Traefik: a reverse proxy" />
<img class="img-icon" src="img/docker.png" alt="Docker" title="Docker" />
<img class="img-icon" src="img/lua.png" alt="Lua" title="Lua script" />
<img class="img-icon" src="img/neovim.png" alt="Neovim" title="Neovim editor" />
<img class="img-icon" src="img/nginx.png" alt="Nginx" title="Nginx a reverse proxy" />
</div>
</div>
</section>
<div id="werk" class="divider"></div>
<section>
<div class="px-4 py-4">
<h2>Werkervaring</h2>
<ul class="rowlines">
<li class="row attention">
<span class="col-5">Opleiding Java Enterprise</span>
<span class="col-4">/</span>
<span class="col-3">2025 - Nu</span>
</li>
<li class="row text-secondary">
<span class="col-5">Tijdelijke Interim jobs</span>
<span class="col-4">Verscheidene werkplaatsen</span>
<span class="col-3">2025 - Nu</span>
</li>
<li class="row">
<span class="col-5">Zelfstudie Angular en docker</span>
<span class="col-4">/</span>
<span class="col-3">2023 - 2025</span>
</li>
<li class="row">
<span class="col-5">Allround ICT-er</span>
<span class="col-4">Nelissen computers</span>
<span class="col-3">2022 - 2022</span>
</li>
<li class="row attention">
<span class="col-5">ICT Trainer Java</span>
<span class="col-4">Multimedi</span>
<span class="col-3">2018 - 2021</span>
</li>
<li class="row">
<span class="col-5">Zelfstudie Java en Linux</span>
<span class="col-4">/</span>
<span class="col-3">2016 - 2017</span>
</li>
<li class="row">
<span class="col-5">Helpdesk technische dienst</span>
<span class="col-4">KUL</span>
<span class="col-3">2015 - 2016</span>
</li>
<li class="row">
<span class="col-5">Vrijwillig programmeur</span>
<span class="col-4">KUL</span>
<span class="col-3">2013 - 2014</span>
</li>
<li class="row text-secondary">
<span class="col-5">Tijdelijke Interim jobs</span>
<span class="col-4">Verscheidene werkplaatsen</span>
<span class="col-3">2007 - 2013</span>
</li>
<li class="row attention">
<span class="col-5">Programmeur C++</span>
<span class="col-4">Zetes</span>
<span class="col-3">2007 - 2007</span>
</li>
<li class="row">
<span class="col-5">Computer dokter</span>
<span class="col-4">Compudoc</span>
<span class="col-3">2006 - 2007</span>
</li>
</ul>
</div>
</section>
<div id="studies" class="divider"></div>
<section>
<div class="px-4 py-4">
<h2>Studies</h2>
<ul class="rowlines-short">
<li class="row">
<span class="col-6">Multimedi Java Enterprise ontwikkelaar</span>
<span class="col-6">2025 - nu</span>
</li>
<li class="row">
<span class="col-6">Multimedi Systeembeheer</span>
<span class="col-6">2017 - 2018</span>
</li>
<li class="row">
<span class="col-6">Cevora Java Enterprise ontwikkelaar</span>
<span class="col-6">2008 - 2009</span>
</li>
<li class="row">
<span class="col-6">A2: Elektrische installatietechnieken</span>
<span class="col-6">1998 - 2004</span>
</li>
</ul>
</div>
</section>
<div id="portfolio" class="divider"></div>
<section>
<div class="px-4 py-4">
<h2>Portfolio</h2>
<h4>Huidig project:</h4>
<a target="_blank" href="https://tds.truyen.network">TDS Family website</a>
<p>Full stack Java &amp; Angular website.</p>
<div id="carouselExampleIndicators" class="carousel carousel-dark slide carousel-fade mx-auto">
<div class="carousel-indicators">
<button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="0" class="active"
aria-current="true" aria-label="Slide 1"></button>
<button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="1"
aria-label="Slide 2"></button>
<button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="2"
aria-label="Slide 3"></button>
<button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="3"
aria-label="Slide 4"></button>
</div>
<div class="carousel-inner">
<div class="carousel-item active">
<img src="img/tds1.png" class="d-block w-100" alt="Screenshot 1">
<div class="carousel-caption d-none d-md-block">
<h5>1</h5>
</div>
</div>
<div class="carousel-item">
<img src="img/tds2.png" class="d-block w-100" alt="Screenshot 2">
<div class="carousel-caption d-none d-md-block">
<h5>2</h5>
</div>
</div>
<div class="carousel-item">
<img src="img/tds3.png" class="d-block w-100" alt="Screenshot 3">
<div class="carousel-caption d-none d-md-block">
<h5>3</h5>
</div>
</div>
<div class="carousel-item">
<img src="img/tds4.png" class="d-block w-100" alt="Screenshot 4">
<div class="carousel-caption d-none d-md-block">
<h5>4</h5>
</div>
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleIndicators"
data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#carouselExampleIndicators"
data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
<h4>Websites:</h4>
<ul>
<li><a target="_blank" href="https://ward.truyen.network">Ward(this one)</a></li>
<li><a target="_blank" href="https://willem.truyen.network">Willem games</a></li>
<li><a target="_blank" href="https://git.truyen.network">Gitea</a></li>
<!-- <li><a target="_blank" href="https://wterminal.truyen.network">WTerminal</a></li> -->
</ul>
<br>
<h4>Oudere projecten:</h4>
<div class="row">
<div class="card">
<a target="_blank" href="https://wterminal.truyen.network">
<h3>WTerminal</h3>
</a>
<p>JavaScript 2023-2024<br>
Kan gebruikt worden in websites en als browser-addon</p>
<h5>Screenshot:</h5>
<img style="width: 100%" src="img/wterminal.png">
</img>
</div>
<div class="card">
<h3>Ronny</h3>
<p>VB.net 2004-2006<br>Game met Direct draw rendering</p>
<h5>Youtube video:</h5>
<iframe src="https://www.youtube.com/embed/m7tgDUc2jXs">
</iframe>
</div>
<div class="card">
<h3>Minesweeper</h3>
<p>C/C++ 2006-2013<br>Game met OpenGL rendering</p>
<h5>Youtube video:</h5>
<iframe src="https://www.youtube.com/embed/Rejp6cVRxfc">
</iframe>
</div>
</div>
</section>
<footer class="text-end">
<p class="text-secondary my-0 me-1">Life is a long lesson in humility.</p>
</footer>
</main>
<script src="js/bootstrap.min.js"></script>
<script src="js/starback.js"></script>
<canvas id="canvas"></canvas>
<script src="js/main.js"> </script>
<script src="js/oneko.js"> </script>
</body>
</html>

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
View 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
View 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

File diff suppressed because one or more lines are too long