nestler-dev / script.js
Basti1110's picture
🐳 08/06 - 02:00 - Do a UNIQUE Design and UX!
335e4fa verified
Raw
History Blame Contribute Delete
14.8 kB
document.addEventListener('DOMContentLoaded', () => {
// =============================================
// 🧠 NEURAL PARTICLE NETWORK β€” Living Background
// =============================================
const canvas = document.getElementById('particle-canvas');
const ctx = canvas.getContext('2d');
let particles = [];
const PARTICLE_COUNT = window.innerWidth < 768 ? 40 : 75;
const CONNECTION_DIST = 150;
let mouseX = window.innerWidth / 2;
let mouseY = window.innerHeight / 2;
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
class Particle {
constructor() {
this.reset();
}
reset() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.vx = (Math.random() - 0.5) * 0.6;
this.vy = (Math.random() - 0.5) * 0.6;
this.size = Math.random() * 2.5 + 1;
this.opacity = Math.random() * 0.6 + 0.2;
}
update() {
// Gentle mouse repulsion
const dx = this.x - mouseX;
const dy = this.y - mouseY;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 180) {
const force = (180 - dist) / 180 * 0.3;
this.vx += (dx / dist) * force * 0.1;
this.vy += (dy / dist) * force * 0.1;
}
// Damping
this.vx *= 0.998;
this.vy *= 0.998;
this.x += this.vx;
this.y += this.vy;
// Wrap edges
if (this.x < -20) this.x = canvas.width + 20;
if (this.x > canvas.width + 20) this.x = -20;
if (this.y < -20) this.y = canvas.height + 20;
if (this.y > canvas.height + 20) this.y = -20;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fillStyle = `rgba(0, 242, 254, ${this.opacity})`;
ctx.fill();
}
}
// Initialize particles
for (let i = 0; i < PARTICLE_COUNT; i++) {
particles.push(new Particle());
}
function animateParticles() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Update & draw particles
particles.forEach(p => { p.update(); p.draw(); });
// Draw connections
for (let i = 0; i < particles.length; i++) {
for (let j = i + 1; j < particles.length; j++) {
const dx = particles[i].x - particles[j].x;
const dy = particles[i].y - particles[j].y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < CONNECTION_DIST) {
const alpha = (1 - dist / CONNECTION_DIST) * 0.2;
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[j].x, particles[j].y);
ctx.strokeStyle = `rgba(0, 220, 255, ${alpha})`;
ctx.lineWidth = 0.5;
ctx.stroke();
}
}
}
requestAnimationFrame(animateParticles);
}
animateParticles();
// --- Update mouse for particles ---
document.addEventListener('mousemove', (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
document.documentElement.style.setProperty('--cursor-x', e.clientX / window.innerWidth);
document.documentElement.style.setProperty('--cursor-y', e.clientY / window.innerHeight);
});
// =============================================
// πŸ“œ SCROLL PROGRESS BAR
// =============================================
const scrollProgress = document.getElementById('scroll-progress');
window.addEventListener('scroll', () => {
const scrollTop = window.scrollY;
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
const progress = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0;
scrollProgress.style.width = progress + '%';
});
// =============================================
// 🎯 3D TILT EFFECT FOR CARDS
// =============================================
const tiltCards = document.querySelectorAll('.tilt-card');
tiltCards.forEach(card => {
card.addEventListener('mousemove', (e) => {
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const centerX = rect.width / 2;
const centerY = rect.height / 2;
const rotateX = ((y - centerY) / centerY) * -6;
const rotateY = ((x - centerX) / centerX) * 6;
const glareX = (x / rect.width) * 100;
const glareY = (y / rect.height) * 100;
card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale3d(1.02, 1.02, 1.02)`;
card.style.setProperty('--glare-x', glareX + '%');
card.style.setProperty('--glare-y', glareY + '%');
});
card.addEventListener('mouseleave', () => {
card.style.transform = 'perspective(1000px) rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1)';
card.style.setProperty('--glare-x', '50%');
card.style.setProperty('--glare-y', '50%');
});
});
// =============================================
// 🧲 MAGNETIC BUTTONS
// =============================================
const magneticBtns = document.querySelectorAll('.magnetic-btn');
magneticBtns.forEach(btn => {
btn.addEventListener('mousemove', (e) => {
const rect = btn.getBoundingClientRect();
const x = e.clientX - rect.left - rect.width / 2;
const y = e.clientY - rect.top - rect.height / 2;
const dist = Math.sqrt(x * x + y * y);
const maxDist = 120;
if (dist < maxDist) {
const strength = (1 - dist / maxDist) * 10;
btn.style.transform = `translate(${x * strength * 0.06}px, ${y * strength * 0.06}px) scale(1.05)`;
}
});
btn.addEventListener('mouseleave', () => {
btn.style.transform = 'translate(0px, 0px) scale(1)';
});
});
// =============================================
// 🌈 SCROLL-DRIVEN COLOR MORPHING
// =============================================
window.addEventListener('scroll', () => {
const scrollTop = window.scrollY;
const maxScroll = document.documentElement.scrollHeight - window.innerHeight;
const scrollFraction = maxScroll > 0 ? scrollTop / maxScroll : 0;
// Hue shifts from 188 (cyan) β†’ 200 (blue) β†’ 270 (violet)
const hue = 188 + scrollFraction * 82;
document.documentElement.style.setProperty('--accent-hue', hue);
});
// =============================================
// πŸ‘οΈ FADE-IN OBSERVER FOR TIMELINE
// =============================================
const timelineItems = document.querySelectorAll('.timeline-item');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('revealed');
}
});
}, { threshold: 0.2 });
timelineItems.forEach(item => observer.observe(item));
// =============================================
// πŸ”„ MODE TOGGLE: Bento Grid <-> Terminal
// =============================================
const toggleBtn = document.getElementById('mode-toggle');
const mainContent = document.getElementById('main-content');
const terminalMode = document.getElementById('terminal-mode');
const terminalOutput = document.getElementById('terminal-output');
const terminalInput = document.getElementById('terminal-input');
const toggleText = document.getElementById('toggle-text');
let isTerminal = false;
toggleBtn.addEventListener('click', () => {
if (!isTerminal) {
if (document.startViewTransition) {
document.startViewTransition(() => {
mainContent.classList.add('hidden');
terminalMode.classList.remove('hidden');
});
} else {
mainContent.classList.add('hidden');
terminalMode.classList.remove('hidden');
}
toggleText.textContent = '🏠 GUI';
printTerminal("SYSTEM > Terminal Mode Activated.", 'cyan');
printTerminal("Type 'help' for a list of commands.", 'dim');
isTerminal = true;
terminalInput.focus();
} else {
if (document.startViewTransition) {
document.startViewTransition(() => {
terminalMode.classList.add('hidden');
mainContent.classList.remove('hidden');
});
} else {
terminalMode.classList.add('hidden');
mainContent.classList.remove('hidden');
}
toggleText.textContent = '>_ TERMINAL';
isTerminal = false;
}
});
// =============================================
// πŸ’» ENHANCED TERMINAL LOGIC
// =============================================
const commands = {
help: {
desc: "Shows this help message",
action: () => {
let output = "Available Commands:\n";
for (let cmd in commands) {
output += ` ${cmd.padEnd(14)} - ${commands[cmd].desc}\n`;
}
return output;
}
},
whoami: {
desc: "Display current user",
action: () => "πŸ›‘οΈ Sebastian F. Nestler | TryHackMe Top 7% | Annaberg-Buchholz, DE"
},
skills: {
desc: "List core competencies",
action: () => "⚑ Python | JavaScript | C | SQL | Logfile Analysis | Incident Response | Applied AI & Automation"
},
contact: {
desc: "Show contact info",
action: () => "πŸ“§ snestler110@gmail.com | 🌐 nestler.dev | πŸ… credly.com/users/sebastian-nestler"
},
experience: {
desc: "Show career timeline",
action: () => {
return `πŸ“‹ CAREER TIMELINE:
[2022-2023] 3rd Level Support Engineer @ GK Software SE
[2022] Ethical Hacking Trainee @ T-Systems
[2016] Dispatcher & Medical Assistant @ KV Brandenburg
[2010-2014] Independent Entrepreneur @ Rio de Janeiro
[2001-2015] Paramedic / Medical Assistant @ Multiple Orgs`;
}
},
education: {
desc: "Show educational background",
action: () => {
return `πŸŽ“ EDUCATION:
β€’ Medical Studies (1st State Exam) β€” Friedrich Schiller Univ. Jena
β€’ Certified Pharmaceutical Consultant (IHK) β€” Pharmaakademie Leipzig
β€’ Paramedic Training β€” Landesschule Sachsen Rotes Kreuz`;
}
},
languages: {
desc: "Show spoken languages",
action: () => "πŸ—£οΈ German (Native) | English (Fluent) | Portuguese (Fluent - Brazilian)"
},
clear: {
desc: "Clear the terminal",
action: () => {
terminalOutput.innerHTML = '';
return '';
}
},
matrix: {
desc: "Fun easter egg",
action: () => {
let rain = '';
const chars = '01をむウエγ‚ͺγ‚«γ‚­γ‚―γ‚±γ‚³γ‚΅γ‚·γ‚Ήγ‚»γ‚½γ‚Ώγƒγƒ„γƒ†γƒˆ';
for (let i = 0; i < 15; i++) {
let line = '';
for (let j = 0; j < 50; j++) {
line += chars[Math.floor(Math.random() * chars.length)];
}
rain += line + '\n';
}
return rain;
}
}
};
function printTerminal(text, color = 'green') {
const span = document.createElement('span');
span.textContent = text + '\n';
if (color === 'dim') span.style.opacity = '0.5';
if (color === 'cyan') span.style.color = '#00F2FE';
if (color === 'red') span.style.color = '#ff4444';
if (color === 'white') span.style.color = '#e0ffe0';
terminalOutput.appendChild(span);
terminalOutput.scrollTop = terminalOutput.scrollHeight;
}
terminalInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
const input = terminalInput.value.trim().toLowerCase();
terminalInput.value = '';
if (commands[input]) {
const result = commands[input].action();
printTerminal(`❯ ${input}`, 'white');
if (result) printTerminal(result, 'white');
} else if (input !== '') {
printTerminal(`❯ ${input}`, 'white');
printTerminal(`Command not found: ${input}. Type 'help' for options.`, 'red');
}
}
});
function initTerminal() {
const welcomeMsg = `
β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
β–ˆβ–ˆβ•”β•β•β•β•β•β•šβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—
β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β–ˆβ–ˆβ•”β–ˆβ–ˆβ–ˆβ–ˆβ•”β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘
β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ•”β• β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘
β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β•šβ•β• β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•
β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β•β•β•šβ•β• β•šβ•β• β•šβ•β• β•šβ•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•
`;
printTerminal(welcomeMsg, 'cyan');
printTerminal('⚑ CYBER-MEDICAL TERMINAL v2.0 β€” Sebastian F. Nestler', 'white');
printTerminal('πŸ›‘οΈ Cybersecurity | πŸ€– AI Applications | πŸ₯ Emergency Operations', 'dim');
printTerminal('\nType "help" to explore available commands.', 'dim');
}
initTerminal();
});