new animations

This commit is contained in:
samantha42
2026-05-24 21:35:04 +02:00
parent 81c47d56b4
commit 05d8732e85
4 changed files with 397 additions and 84 deletions
+88 -67
View File
@@ -128,23 +128,23 @@
<div class="section-head"><h2>education</h2></div> <div class="section-head"><h2>education</h2></div>
<div class="edu-grid"> <div class="edu-grid">
<div class="edu-card"> <div class="edu-card">
<div class="edu-year">2025 —<br>present</div> <div class="edu-year">2025 — present</div>
<div> <div>
<div class="edu-degree">Bachelor of Economics &amp; Business Administration (HA)</div> <div class="edu-degree">Bachelor of Economics &amp; Business Administration (HA)</div>
<div class="edu-inst">Aalborg University · Expected 2028</div> <div class="edu-inst">Aalborg University · Expected 2028</div>
</div> </div>
</div> </div>
<div class="edu-card"> <div class="edu-card">
<div class="edu-year">2024 — 2025</div> <div class="edu-year">2024 — 2025 <br> <span class="edu-tag tag-dropped">discontinued</span> </div>
<div class="edu-body"> <div class="edu-body">
<div class="edu-degree">Mathematics-Technology (BSc)</div> <div class="edu-degree">Mathematics-Technology (BSc)</div>
<div class="edu-inst">Aalborg University · 1 semester</div> <div class="edu-inst">Aalborg University · 1 semester</div>
<span class="edu-tag tag-dropped">discontinued</span>
</div> </div>
</div> </div>
<div class="edu-card"> <div class="edu-card">
<div class="edu-year">2020 —<br>2023</div> <div class="edu-year">2020 — 2023</div>
<div> <div>
<div class="edu-degree">HTX Technical Upper Secondary Education</div> <div class="edu-degree">HTX Technical Upper Secondary Education</div>
<div class="edu-inst">Viden Gymnasier</div> <div class="edu-inst">Viden Gymnasier</div>
@@ -163,9 +163,9 @@
</div> </div>
</section> </section>
<section> <section id="interestlist" >
<div class="section-head"><h2>interests</h2></div> <div class="section-head"><h2>interests</h2></div>
<div class="interests-row"> <div class="interestssection-row">
<span class="interest-chip">cinema</span> <span class="interest-chip">cinema</span>
<span class="interest-chip">tv shows</span> <span class="interest-chip">tv shows</span>
<span class="interest-chip">Economics</span> <span class="interest-chip">Economics</span>
@@ -214,73 +214,82 @@
</section> </section>
<br> <br>
<div class="page-header"> <section id="interests" >
<h2 class="page-title" id="interest">interests</h2> <div class="page-header">
<span class="page-sub" id="interest-sub">Fav lists</span> <h2 class="page-title" id="interest">interests</h2>
</div> <span class="page-sub" id="interest-sub">Fav lists</span>
<div class="section-head"><h2>Movie/Show Top list</h2></div> <span class="matrix-hidden" id="matrix-hidden">
<div class="toplist-group"> Boy: Do not try and bend the spoon. That's impossible. Instead... only try to realize the truth.
<h3>Top 5 Movies</h3> <br>
<div class="toplist-body" > Neo: What truth?
<div class="poster-grid"> <br>
<div class="poster-item posterhover" onclick="bladerunnerClick()"> Boy: There is no spoon.
<img src="/static/posters/bladerunner2049.jpg" alt="Blade Runner 2049"> </span>
<p>Blade Runner 2049</p> </div>
</div> <div class="section-head"><h2>Movie/Show Top list</h2></div>
<div class="poster-item"> <div class="toplist-group">
<img src="/static/posters/AcureForWellness.jpg" alt="A Cure of Wellness"> <h3>Top 5 Movies</h3>
<p>A Cure of Wellness</p> <div class="toplist-body" >
</div> <div class="poster-grid">
<div class="poster-item posterhover" onclick="matrixClick()"> <div class="poster-item posterhover" onclick="bladerunnerClick()">
<img src="/static/posters/matrix.jpg" alt="matrix"> <img src="/static/posters/bladerunner2049.jpg" alt="Blade Runner 2049">
<p>The Matrix</p> <p>Blade Runner 2049</p>
</div> </div>
<div class="poster-item posterhover" onclick="draculaClick()"> <div class="poster-item posterhover" onclick="cureClick()">
<img src="/static/posters/Dracula.webp" alt="Dracula: A Love Tale"> <img src="/static/posters/AcureForWellness.jpg" alt="A Cure of Wellness">
<p>Dracula: A Love Tale</p> <p>A Cure of Wellness</p>
</div> </div>
<div class="poster-item posterhover" onclick="dragonClick()"> <div class="poster-item posterhover" onclick="matrixClick()">
<img src="/static/posters/TheGirlwiththeDragonTattoo.webp" alt="Girl with a Dragon Tattoos"> <img src="/static/posters/matrix.jpg" alt="matrix">
<p>Girl with a Dragon Tattoo</p> <p>The Matrix</p>
</div>
<div class="poster-item posterhover" onclick="draculaClick()">
<img src="/static/posters/Dracula.webp" alt="Dracula: A Love Tale">
<p>Dracula: A Love Tale</p>
</div>
<div class="poster-item posterhover" onclick="dragonClick()">
<img src="/static/posters/TheGirlwiththeDragonTattoo.webp" alt="Girl with a Dragon Tattoos">
<p>Girl with a Dragon Tattoo</p>
</div>
</div> </div>
</div> </div>
</div>
<div class="toplist-group"> <div class="toplist-group">
<h3>Top 5 Shows</h3> <h3>Top 5 Shows</h3>
<div class="toplist-body"> <div class="toplist-body">
<div class="poster-grid"> <div class="poster-grid">
<div class="poster-item"> <div class="poster-item">
<img src="/static/posters/Succession.webp" alt="Succession"> <img src="/static/posters/Succession.webp" alt="Succession">
<p>Succession</p> <p>Succession</p>
</div> </div>
<div class="poster-item"> <div class="poster-item">
<img src="/static/posters/Chernobyl.webp" alt="Chernobyl"> <img src="/static/posters/Chernobyl.webp" alt="Chernobyl">
<p>Chernobyl</p> <p>Chernobyl</p>
</div> </div>
<div class="poster-item"> <div class="poster-item">
<img src="/static/posters/Breaking Bad.webp" alt="Breaking Bad"> <img src="/static/posters/Breaking Bad.webp" alt="Breaking Bad">
<p>Breaking Bad</p> <p>Breaking Bad</p>
</div> </div>
<div class="poster-item"> <div class="poster-item">
<img src="/static/posters/Avatar.webp" alt="Avatar: The Last Airbender"> <img src="/static/posters/Avatar.webp" alt="Avatar: The Last Airbender">
<p>Avatar: The Last Airbender</p> <p>Avatar: The Last Airbender</p>
</div> </div>
<div class="poster-item"> <div class="poster-item">
<img src="/static/posters/Adolescence.webp" alt="Adolescence"> <img src="/static/posters/Adolescence.webp" alt="Adolescence">
<p>Adolescence</p> <p>Adolescence</p>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> <div class="section-head"><h2>Lunix rice</h2></div>
<div class="section-head"><h2>Lunix rice</h2></div> <div>
<div> <div style="padding-left: 10%;"><img src="/static/images/rice.png" width="80%" style="align-self: center;"></div>
<div style="padding-left: 10%;"><img src="/static/images/rice.png" width="80%" style="align-self: center;"></div> <p class="exp-body">I love my custom Linux setup. I use Hyprland, which automatically arranges app windows on my screen so everything stays organized without dragging things around. I also use Quickshell, which lets me customize menus, shortcuts, and system controls to work exactly how I want.
<p class="exp-body">I love my custom Linux setup. I use Hyprland, which automatically arranges app windows on my screen so everything stays organized without dragging things around. I also use Quickshell, which lets me customize menus, shortcuts, and system controls to work exactly how I want. My system is based on Arch Linux or Manjaro Linux, which are versions of Linux that give you more control and customization than a typical computer setup. The result is a clean, fast, and super efficient desktop thats hard to go back from.
My system is based on Arch Linux or Manjaro Linux, which are versions of Linux that give you more control and customization than a typical computer setup. The result is a clean, fast, and super efficient desktop thats hard to go back from. <a class="outlink" href="https://git.samantha42.xyz/samantha/dotfiles" >Git repo</a>
<a class="outlink" href="https://git.samantha42.xyz/samantha/dotfiles" >Git repo</a> </p>
</p> </div>
</div> </section>
<section style="display: none;" id="alice" class="play" > <section style="display: none;" id="alice" class="play" >
<br> <br>
<div class="section-head"><h2>Want to play a game Alice?!</h2></div> <div class="section-head"><h2>Want to play a game Alice?!</h2></div>
@@ -294,6 +303,18 @@
<h2>This game is</h2> <h2>This game is</h2>
</section> </section>
<section id="secret" class="Hitchhiker">
<div class="number">42</div>
<div class="divider"></div>
<p class="quote">So long, and thanks for all the fish.</p>
<p class="attribution">Douglas Adams &nbsp;·&nbsp; The Hitchhiker's Guide to the Galaxy</p>
<div class="secret-hint">
<p>shhh. i have a secret to share &mdash; <a href="/secret">follow me</a></p>
</div>
</section>
<script src="/static/scripts/tetris.js"></script> <script src="/static/scripts/tetris.js"></script>
</div> </div>
+289 -12
View File
@@ -40,27 +40,270 @@
// just some fun. // just some fun.
console.log("%c👀 hi there!", "font-size:20px") console.log("%c👀 hi there!", "font-size:20px")
function cureClick() {
if (document.getElementById('cure-canvas')) return;
const el = document.getElementById('interest');
el.textContent = "Actually... I'm feeling much better now!"
startWater();
isDay = false;
applyState();
setTimeout(() => {
el.textContent = 'interest';
stopWater();
}, 10000);
}
function draculaClick() { let cureCanvas, cureCtx, cureAnimFrame;
const el = document.getElementById('interest');
if (!el) return; // el is a DOM node, never a string
el.textContent = '🦇 interest 🦇';
setTimeout(() => { function startWater() {
el.textContent = "interest"; cureCanvas = document.createElement('canvas');
}, 5000); cureCanvas.id = 'cure-canvas';
cureCanvas.width = window.innerWidth;
cureCanvas.height = window.innerHeight;
Object.assign(cureCanvas.style, {
position: 'fixed',
top: 0,
left: 0,
pointerEvents: 'none',
zIndex: -1, // behind everything
opacity: '0',
transition: 'opacity 1.4s ease'
});
document.body.appendChild(cureCanvas);
cureCtx = cureCanvas.getContext('2d');
requestAnimationFrame(() => { cureCanvas.style.opacity = '1'; });
const W = cureCanvas.width;
const H = cureCanvas.height;
// waterline sits at 38% from the top
const waterlineY = H * 0.38;
// floating particles below the surface
const particles = Array.from({ length: 55 }, () => ({
x: Math.random() * W,
y: waterlineY + 20 + Math.random() * (H - waterlineY - 20),
r: 1 + Math.random() * 2.5,
speedX: (Math.random() - 0.5) * 0.3,
speedY: -0.08 - Math.random() * 0.18, // slow upward drift
opacity: 0.08 + Math.random() * 0.18
}));
function drawFrame(ts) {
cureCtx.clearRect(0, 0, W, H);
// ── sky above waterline (very subtle, mostly transparent) ──────────
const sky = cureCtx.createLinearGradient(0, 0, 0, waterlineY);
sky.addColorStop(0, 'rgba(190, 230, 255, 0.06)');
sky.addColorStop(1, 'rgba(190, 230, 255, 0.01)');
cureCtx.fillStyle = sky;
cureCtx.fillRect(0, 0, W, waterlineY);
// ── water body below waterline ─────────────────────────────────────
const water = cureCtx.createLinearGradient(0, waterlineY, 0, H);
water.addColorStop(0, 'rgba(80, 190, 220, 0.28)');
water.addColorStop(0.35, 'rgba(40, 140, 190, 0.22)');
water.addColorStop(0.7, 'rgba(20, 90, 150, 0.20)');
water.addColorStop(1, 'rgba(10, 50, 110, 0.22)');
cureCtx.fillStyle = water;
cureCtx.fillRect(0, waterlineY, W, H - waterlineY);
// ── caustic shimmer streaks ────────────────────────────────────────
const numStreaks = 10;
for (let i = 0; i < numStreaks; i++) {
const phase = (ts * 0.0004 + i * 0.63) % 1;
const x = (i / numStreaks) * W + Math.sin(ts * 0.0008 + i) * 60;
const yTop = waterlineY + 10 + Math.sin(ts * 0.001 + i * 1.3) * 18;
const yBot = yTop + 40 + Math.sin(ts * 0.0007 + i * 0.9) * 30;
const streak = cureCtx.createLinearGradient(x, yTop, x + 6, yBot);
streak.addColorStop(0, 'rgba(200, 245, 255, 0)');
streak.addColorStop(0.4, `rgba(200, 245, 255, ${0.05 + 0.06 * Math.sin(ts * 0.002 + i)})`);
streak.addColorStop(1, 'rgba(200, 245, 255, 0)');
cureCtx.fillStyle = streak;
cureCtx.fillRect(x, yTop, 5, yBot - yTop);
}
// ── floating particles ─────────────────────────────────────────────
particles.forEach(p => {
p.x += p.speedX;
p.y += p.speedY;
// reset when reaching the surface
if (p.y < waterlineY + 5) {
p.y = H - 10;
p.x = Math.random() * W;
}
if (p.x < 0) p.x = W;
if (p.x > W) p.x = 0;
const depth = (p.y - waterlineY) / (H - waterlineY); // 0 = surface, 1 = bottom
cureCtx.beginPath();
cureCtx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
cureCtx.fillStyle = `rgba(180, 240, 255, ${p.opacity * (0.4 + 0.6 * (1 - depth))})`;
cureCtx.fill();
});
// ── animated surface waves (2 layers, different speeds & amplitudes) ─
function drawWaveLine(amp, freq, speed, lineW, alpha) {
cureCtx.beginPath();
for (let x = 0; x <= W; x += 3) {
const y = waterlineY
+ Math.sin(x * freq + ts * speed) * amp
+ Math.sin(x * freq * 1.7 + ts * speed * 0.6) * (amp * 0.4);
x === 0 ? cureCtx.moveTo(x, y) : cureCtx.lineTo(x, y);
}
cureCtx.strokeStyle = `rgba(210, 245, 255, ${alpha})`;
cureCtx.lineWidth = lineW;
cureCtx.stroke();
}
// primary wave
drawWaveLine(7, 0.012, 0.0018, 2.0, 0.70);
// secondary wave (slightly offset phase)
drawWaveLine(4, 0.018, 0.0024, 1.2, 0.40);
// micro ripple
drawWaveLine(2, 0.030, 0.0032, 0.7, 0.25);
// ── foam/highlight on the crest ────────────────────────────────────
cureCtx.beginPath();
for (let x = 0; x <= W; x += 3) {
const y = waterlineY
+ Math.sin(x * 0.012 + ts * 0.0018) * 7
+ Math.sin(x * 0.020 + ts * 0.0024) * 3;
x === 0 ? cureCtx.moveTo(x, y - 1) : cureCtx.lineTo(x, y - 1);
}
cureCtx.strokeStyle = 'rgba(255, 255, 255, 0.18)';
cureCtx.lineWidth = 1;
cureCtx.stroke();
if (cureCanvas) cureAnimFrame = requestAnimationFrame(drawFrame);
} }
cureAnimFrame = requestAnimationFrame(drawFrame);
}
function stopWater() {
if (!cureCanvas) return;
cureCanvas.style.opacity = '0';
cancelAnimationFrame(cureAnimFrame);
setTimeout(() => {
cureCanvas.remove();
cureCanvas = null;
}, 1400);
}
function draculaClick() {
if (document.getElementById('lightning-canvas')) return;
const el = document.getElementById('interest');
el.textContent = 'children of the night';
startLightning();
isDay = false;
applyState();
setTimeout(() => {
el.textContent = 'interest';
stopLightning();
}, 10000);
}
let lightningCanvas, lightningCtx, lightningInterval, lightningFlashTimeout;
function startLightning() {
lightningCanvas = document.createElement('canvas');
lightningCanvas.id = 'lightning-canvas';
lightningCanvas.width = window.innerWidth;
lightningCanvas.height = window.innerHeight;
Object.assign(lightningCanvas.style, {
position: 'fixed', top: 0, left: 0,
pointerEvents: 'none', zIndex: 9999,
opacity: '0', transition: 'opacity 0.3s ease'
});
document.body.appendChild(lightningCanvas);
lightningCtx = lightningCanvas.getContext('2d');
requestAnimationFrame(() => { lightningCanvas.style.opacity = '1'; });
function drawBolt(x1, y1, x2, y2, roughness, depth) {
if (depth === 0) {
lightningCtx.beginPath();
lightningCtx.moveTo(x1, y1);
lightningCtx.lineTo(x2, y2);
lightningCtx.stroke();
return;
}
const mx = (x1 + x2) / 2 + (Math.random() - 0.5) * roughness;
const my = (y1 + y2) / 2 + (Math.random() - 0.5) * roughness;
drawBolt(x1, y1, mx, my, roughness / 2, depth - 1);
drawBolt(mx, my, x2, y2, roughness / 2, depth - 1);
// random fork branch
if (depth > 2 && Math.random() < 0.4) {
const fx = mx + (Math.random() - 0.3) * roughness * 2;
const fy = my + Math.random() * roughness * 2;
lightningCtx.save();
lightningCtx.globalAlpha *= 0.5;
drawBolt(mx, my, fx, fy, roughness / 2, depth - 2);
lightningCtx.restore();
}
}
function flashStrike() {
lightningCtx.clearRect(0, 0, lightningCanvas.width, lightningCanvas.height);
const numBolts = 1 + Math.floor(Math.random() * 3);
for (let i = 0; i < numBolts; i++) {
const startX = lightningCanvas.width * (0.1 + Math.random() * 0.8);
const endX = startX + (Math.random() - 0.5) * 300;
const color = Math.random() < 0.6
? `rgba(220, 180, 255, ${0.6 + Math.random() * 0.4})` // purple
: `rgba(255, 255, 255, ${0.7 + Math.random() * 0.3})`; // white
lightningCtx.strokeStyle = color;
lightningCtx.lineWidth = 0.5 + Math.random() * 2;
lightningCtx.shadowColor = color;
lightningCtx.shadowBlur = 18 + Math.random() * 30;
lightningCtx.globalAlpha = 1;
drawBolt(startX, 0, endX, lightningCanvas.height * (0.4 + Math.random() * 0.5), 120, 7);
}
// ambient flash on the body
document.body.style.transition = 'background 0.05s';
document.body.style.background = `rgba(80, 0, 120, 0.08)`;
setTimeout(() => { document.body.style.background = ''; }, 80);
// fade the bolt out
lightningFlashTimeout = setTimeout(() => {
lightningCtx.clearRect(0, 0, lightningCanvas.width, lightningCanvas.height);
}, 80 + Math.random() * 120);
}
// irregular strike cadence — like real lightning
function scheduleStrike() {
flashStrike();
const delay = 600 + Math.random() * 2200;
lightningInterval = setTimeout(scheduleStrike, delay);
}
scheduleStrike();
}
function stopLightning() {
if (!lightningCanvas) return;
lightningCanvas.style.opacity = '0';
clearTimeout(lightningInterval);
clearTimeout(lightningFlashTimeout);
setTimeout(() => {
lightningCanvas.remove();
lightningCanvas = null;
}, 800);
}
function matrixClick() { function matrixClick() {
const sub = document.getElementById('interest-sub'); const sub = document.getElementById('interest-sub');
const col = sub.color sub.style.display = "none"
sub.textContent = `Do not try and bend the spoon. That's impossible. Instead... only try to realize the truth.` const matrixsub = document.getElementById('matrix-hidden');
matrixsub.style.display = "block"
sub.style.color = "green"
setTimeout(() => { setTimeout(() => {
sub.textContent = "Fav lists" matrixsub.style.display = "none"
sub.style.color = "#6b6560" sub.style.display = "block"
}, 15000); }, 15000);
} }
@@ -73,6 +316,9 @@
startRain(); startRain();
isDay = false
applyState();
setTimeout(() => { setTimeout(() => {
el.textContent = "interest"; el.textContent = "interest";
stopRain(); stopRain();
@@ -182,3 +428,34 @@ function dragonClick() {
}, 300); }, 300);
}; };
} }
function unhide42() {
const alicegameSection = document.getElementById('alice');
const tetrisSection = document.getElementById('tetris');
const experiencesection = document.getElementById('experience');
const educationsection = document.getElementById('education');
const automationsection = document.getElementById('automation');
const interestssection = document.getElementById('interests');
const opinionsection = document.getElementById('opinion');
const interestlistsection = document.getElementById('interestlist');
const hiddenssection = document.getElementById('secret');
if (hiddenssection.style.display == 'none') {
hiddenssection.style.display = 'block';
} else {
hiddenssection.style.display = 'none';
}
alicegameSection.style.display = 'none';
tetrisSection.style.display = 'none';
experiencesection.style.display = 'none';
educationsection.style.display = 'none';
automationsection.style.display = 'none';
interestssection.style.display = 'none';
opinionsection.style.display = 'none';
interestlistsection.style.display = 'none';
}
+2 -2
View File
@@ -1156,10 +1156,10 @@ nav .section-label {
display: inline-block; display: inline-block;
margin-top: 8px; margin-top: 8px;
font-family: 'DM Mono', monospace; font-family: 'DM Mono', monospace;
font-size: 10px; font-size: 8px;
letter-spacing: 0.1em; letter-spacing: 0.1em;
text-transform: uppercase; text-transform: uppercase;
padding: 3px 8px; padding: 3px 5px;
border-radius: 3px; border-radius: 3px;
} }
+17 -2
View File
@@ -262,10 +262,10 @@ footer{
display: inline-block; display: inline-block;
margin-top: 8px; margin-top: 8px;
font-family: 'DM Mono', monospace; font-family: 'DM Mono', monospace;
font-size: 10px; font-size: 9px;
letter-spacing: 0.1em; letter-spacing: 0.1em;
text-transform: uppercase; text-transform: uppercase;
padding: 3px 8px; padding: 3px 5px;
border-radius: 3px; border-radius: 3px;
} }
@@ -576,3 +576,18 @@ a{
color: var(--color-text-secondary); color: var(--color-text-secondary);
} }
.copy-btn:hover { background: var(--color-background-secondary); } .copy-btn:hover { background: var(--color-background-secondary); }
.Hitchhiker {
max-width: 480px;
width: 100%;
text-align: center;
display: none;
}
.matrix-hidden {
display: none;
color: green;
font-family: var(--ff-mono);
font-size: 0.72rem;
letter-spacing: 0.08em;
padding-left: 1.1rem;
}