858 lines
26 KiB
HTML
858 lines
26 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>noctura.dev</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;500;600;700;800&family=DM+Mono:ital,wght@0,300;0,400;1,300&display=swap" rel="stylesheet" />
|
|
<style>
|
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
|
|
:root {
|
|
--bg: #07080f;
|
|
--bg2: #0d0f1c;
|
|
--bg3: #111428;
|
|
--bg4: #171a31;
|
|
--surface: rgba(255,255,255,0.04);
|
|
--border: rgba(255,255,255,0.07);
|
|
--border-hover: rgba(255,255,255,0.14);
|
|
--text: #e8eaf2;
|
|
--muted: #8d93ad;
|
|
--accent: #7c6dfa;
|
|
--accent2: #4fd1c5;
|
|
--accent3: #f7886a;
|
|
--glow: rgba(124,109,250,0.12);
|
|
--font: 'Syne', sans-serif;
|
|
--mono: 'DM Mono', monospace;
|
|
}
|
|
|
|
html { scroll-behavior: smooth; }
|
|
|
|
body {
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
font-family: var(--font);
|
|
line-height: 1.6;
|
|
min-height: 100vh;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
/* --- STAR FIELD --- */
|
|
#stars {
|
|
position: fixed;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
}
|
|
|
|
/* --- NEBULA GLOW --- */
|
|
.nebula {
|
|
position: fixed;
|
|
border-radius: 50%;
|
|
filter: blur(120px);
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
}
|
|
.nebula-1 { width: 600px; height: 600px; background: radial-gradient(circle, rgba(124,109,250,0.08) 0%, transparent 70%); top: -100px; left: -100px; }
|
|
.nebula-2 { width: 500px; height: 500px; background: radial-gradient(circle, rgba(79,209,197,0.06) 0%, transparent 70%); bottom: 200px; right: -50px; }
|
|
.nebula-3 { width: 400px; height: 400px; background: radial-gradient(circle, rgba(247,136,106,0.05) 0%, transparent 70%); top: 50%; left: 40%; }
|
|
|
|
/* --- LAYOUT --- */
|
|
.wrapper {
|
|
position: relative;
|
|
z-index: 1;
|
|
max-width: 900px;
|
|
margin: 0 auto;
|
|
padding: 0 2rem;
|
|
}
|
|
|
|
/* --- NAV --- */
|
|
nav {
|
|
position: fixed;
|
|
top: 0; left: 0; right: 0;
|
|
z-index: 100;
|
|
padding: 1.25rem 0;
|
|
backdrop-filter: blur(20px);
|
|
border-bottom: 1px solid var(--border);
|
|
background: rgba(7,8,15,0.6);
|
|
}
|
|
.nav-inner {
|
|
max-width: 900px;
|
|
margin: 0 auto;
|
|
padding: 0 2rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
.nav-logo {
|
|
font-size: 1rem;
|
|
font-weight: 700;
|
|
letter-spacing: 0.05em;
|
|
color: var(--text);
|
|
text-decoration: none;
|
|
}
|
|
.nav-logo span { color: var(--accent); }
|
|
.nav-links { display: flex; gap: 2rem; list-style: none; }
|
|
.nav-links a {
|
|
font-size: 0.8rem;
|
|
font-weight: 500;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
color: var(--muted);
|
|
text-decoration: none;
|
|
transition: color 0.2s;
|
|
}
|
|
.nav-links a:hover { color: var(--text); }
|
|
|
|
/* --- HERO --- */
|
|
.hero {
|
|
padding: 176px 0 110px;
|
|
position: relative;
|
|
}
|
|
.hero-tag {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-family: var(--mono);
|
|
font-size: 0.75rem;
|
|
color: var(--accent2);
|
|
letter-spacing: 0.06em;
|
|
margin-bottom: 1.1rem;
|
|
opacity: 0;
|
|
animation: fadeUp 0.6s ease forwards 0.2s;
|
|
}
|
|
.hero-tag::before {
|
|
content: '';
|
|
display: inline-block;
|
|
width: 6px; height: 6px;
|
|
border-radius: 50%;
|
|
background: var(--accent2);
|
|
box-shadow: 0 0 8px var(--accent2);
|
|
animation: pulse 2s ease-in-out infinite;
|
|
}
|
|
@keyframes pulse { 0%,100%{opacity:1;transform:scale(1)} 50%{opacity:0.6;transform:scale(0.8)} }
|
|
|
|
.hero h1 {
|
|
max-width: 780px;
|
|
font-size: clamp(3.1rem, 8vw, 4.4rem);
|
|
font-weight: 800;
|
|
line-height: 0.96;
|
|
letter-spacing: -0.045em;
|
|
margin-bottom: 1.25rem;
|
|
opacity: 0;
|
|
animation: fadeUp 0.6s ease forwards 0.35s;
|
|
}
|
|
.hero h1 .line2 {
|
|
display: block;
|
|
color: #ffffff;
|
|
}
|
|
.hero h1 .line3 {
|
|
display: block;
|
|
color: var(--accent);
|
|
}
|
|
|
|
.hero-desc {
|
|
max-width: 640px;
|
|
font-size: 1rem;
|
|
color: var(--muted);
|
|
line-height: 1.75;
|
|
margin-bottom: 2rem;
|
|
opacity: 0;
|
|
animation: fadeUp 0.6s ease forwards 0.5s;
|
|
}
|
|
.hero-desc strong {
|
|
color: var(--text);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.hero-actions {
|
|
display: flex;
|
|
gap: 1rem;
|
|
flex-wrap: wrap;
|
|
margin-bottom: 2.5rem;
|
|
opacity: 0;
|
|
animation: fadeUp 0.6s ease forwards 0.65s;
|
|
}
|
|
.btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 0.7rem 1.4rem;
|
|
border-radius: 8px;
|
|
font-family: var(--font);
|
|
font-size: 0.85rem;
|
|
font-weight: 600;
|
|
text-decoration: none;
|
|
transition: all 0.2s;
|
|
cursor: pointer;
|
|
border: none;
|
|
}
|
|
.btn-primary {
|
|
background: var(--accent);
|
|
color: #fff;
|
|
}
|
|
.btn-primary:hover { background: #9284fc; transform: translateY(-1px); }
|
|
.btn-outline {
|
|
background: transparent;
|
|
color: var(--text);
|
|
border: 1px solid var(--border-hover);
|
|
}
|
|
.btn-outline:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-1px); }
|
|
|
|
.hero-strip {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
gap: 0.9rem;
|
|
max-width: 860px;
|
|
opacity: 0;
|
|
animation: fadeUp 0.6s ease forwards 0.8s;
|
|
}
|
|
.hero-metric {
|
|
padding: 1rem 1.1rem;
|
|
background: rgba(255,255,255,0.03);
|
|
border: 1px solid var(--border);
|
|
border-radius: 14px;
|
|
backdrop-filter: blur(12px);
|
|
}
|
|
.hero-metric-label {
|
|
font-family: var(--mono);
|
|
font-size: 0.62rem;
|
|
letter-spacing: 0.14em;
|
|
text-transform: uppercase;
|
|
color: var(--accent2);
|
|
margin-bottom: 0.45rem;
|
|
}
|
|
.hero-metric-value {
|
|
font-size: 1rem;
|
|
font-weight: 700;
|
|
letter-spacing: -0.02em;
|
|
margin-bottom: 0.2rem;
|
|
}
|
|
.hero-metric-copy {
|
|
font-size: 0.78rem;
|
|
color: var(--muted);
|
|
line-height: 1.55;
|
|
}
|
|
|
|
.intro-panel {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1.1fr) minmax(260px, 0.9fr);
|
|
gap: 1rem;
|
|
align-items: stretch;
|
|
}
|
|
.intro-copy,
|
|
.intro-notes {
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: 18px;
|
|
padding: 1.6rem;
|
|
}
|
|
.intro-copy p {
|
|
color: var(--muted);
|
|
margin-bottom: 1rem;
|
|
}
|
|
.intro-copy p:last-child { margin-bottom: 0; }
|
|
.intro-notes {
|
|
background: linear-gradient(180deg, rgba(23,26,49,0.92), rgba(10,11,20,0.9));
|
|
}
|
|
.note-list {
|
|
display: grid;
|
|
gap: 0.85rem;
|
|
list-style: none;
|
|
}
|
|
.note-list li {
|
|
padding-left: 1rem;
|
|
position: relative;
|
|
color: var(--muted);
|
|
font-size: 0.88rem;
|
|
}
|
|
.note-list li::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0.6rem;
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
background: var(--accent3);
|
|
box-shadow: 0 0 10px rgba(247,136,106,0.5);
|
|
}
|
|
|
|
/* --- SECTION --- */
|
|
section { padding: 80px 0; }
|
|
.section-label {
|
|
font-family: var(--mono);
|
|
font-size: 0.7rem;
|
|
letter-spacing: 0.15em;
|
|
text-transform: uppercase;
|
|
color: var(--accent2);
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
.section-title {
|
|
font-size: clamp(1.6rem, 3vw, 2.2rem);
|
|
font-weight: 700;
|
|
letter-spacing: -0.02em;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
.section-subtitle {
|
|
color: var(--muted);
|
|
font-size: 0.95rem;
|
|
margin-bottom: 3rem;
|
|
}
|
|
.section-divider {
|
|
height: 1px;
|
|
background: linear-gradient(90deg, transparent, var(--border) 20%, var(--border) 80%, transparent);
|
|
margin-bottom: 80px;
|
|
}
|
|
|
|
/* --- SKILLS --- */
|
|
.skills-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
|
gap: 1px;
|
|
background: var(--border);
|
|
border: 1px solid var(--border);
|
|
border-radius: 16px;
|
|
overflow: hidden;
|
|
}
|
|
.skill-card {
|
|
background: var(--bg);
|
|
padding: 2rem;
|
|
transition: background 0.25s;
|
|
position: relative;
|
|
}
|
|
.skill-card:hover { background: var(--bg3); }
|
|
.skill-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0; left: 0; right: 0;
|
|
height: 2px;
|
|
opacity: 0;
|
|
transition: opacity 0.3s;
|
|
}
|
|
.skill-card:hover::before { opacity: 1; }
|
|
.skill-card.purple::before { background: linear-gradient(90deg, var(--accent), transparent); }
|
|
.skill-card.teal::before { background: linear-gradient(90deg, var(--accent2), transparent); }
|
|
.skill-card.orange::before { background: linear-gradient(90deg, var(--accent3), transparent); }
|
|
|
|
.skill-icon {
|
|
font-size: 1.6rem;
|
|
margin-bottom: 1rem;
|
|
display: block;
|
|
}
|
|
.skill-name {
|
|
font-size: 1rem;
|
|
font-weight: 700;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
.skill-desc {
|
|
font-size: 0.82rem;
|
|
color: var(--muted);
|
|
line-height: 1.6;
|
|
margin-bottom: 1.25rem;
|
|
}
|
|
.skill-tags {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 6px;
|
|
}
|
|
.tag {
|
|
font-family: var(--mono);
|
|
font-size: 0.67rem;
|
|
padding: 3px 8px;
|
|
border-radius: 4px;
|
|
border: 1px solid var(--border);
|
|
color: var(--muted);
|
|
letter-spacing: 0.03em;
|
|
}
|
|
.tag.purple { border-color: rgba(124,109,250,0.3); color: rgba(124,109,250,0.8); background: rgba(124,109,250,0.06); }
|
|
.tag.teal { border-color: rgba(79,209,197,0.3); color: rgba(79,209,197,0.8); background: rgba(79,209,197,0.06); }
|
|
.tag.orange { border-color: rgba(247,136,106,0.3); color: rgba(247,136,106,0.8); background: rgba(247,136,106,0.06); }
|
|
|
|
/* --- PROJECTS --- */
|
|
.projects-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
|
gap: 16px;
|
|
}
|
|
.project-card {
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: 14px;
|
|
padding: 1.5rem;
|
|
transition: border-color 0.25s, transform 0.2s;
|
|
text-decoration: none;
|
|
color: var(--text);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.75rem;
|
|
cursor: pointer;
|
|
}
|
|
.project-card:hover {
|
|
border-color: var(--border-hover);
|
|
transform: translateY(-2px);
|
|
}
|
|
.project-header {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
}
|
|
.project-icon {
|
|
font-size: 1.4rem;
|
|
line-height: 1;
|
|
}
|
|
.project-arrow {
|
|
color: var(--muted);
|
|
font-size: 0.9rem;
|
|
transition: color 0.2s, transform 0.2s;
|
|
flex-shrink: 0;
|
|
}
|
|
.project-card:hover .project-arrow {
|
|
color: var(--accent);
|
|
transform: translate(2px,-2px);
|
|
}
|
|
.project-eyebrow {
|
|
font-family: var(--mono);
|
|
font-size: 0.66rem;
|
|
color: var(--accent2);
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
}
|
|
.project-name {
|
|
font-size: 0.95rem;
|
|
font-weight: 700;
|
|
letter-spacing: -0.01em;
|
|
}
|
|
.project-desc {
|
|
font-size: 0.8rem;
|
|
color: var(--muted);
|
|
line-height: 1.55;
|
|
flex: 1;
|
|
}
|
|
.project-status {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
font-family: var(--mono);
|
|
font-size: 0.65rem;
|
|
letter-spacing: 0.04em;
|
|
}
|
|
.status-dot {
|
|
width: 5px; height: 5px;
|
|
border-radius: 50%;
|
|
flex-shrink: 0;
|
|
}
|
|
.status-live { background: #4ade80; box-shadow: 0 0 6px #4ade80; }
|
|
.status-wip { background: #facc15; box-shadow: 0 0 6px #facc15; }
|
|
.status-planned{ background: var(--muted); }
|
|
|
|
/* --- SNAPSHOT --- */
|
|
.snapshot-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
gap: 12px;
|
|
}
|
|
.snapshot-card {
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: 10px;
|
|
padding: 1.1rem 1.25rem;
|
|
min-height: 148px;
|
|
transition: border-color 0.2s, background 0.2s, transform 0.2s;
|
|
}
|
|
.snapshot-card:hover {
|
|
border-color: var(--border-hover);
|
|
background: rgba(255,255,255,0.06);
|
|
transform: translateY(-2px);
|
|
}
|
|
.snapshot-kicker {
|
|
font-family: var(--mono);
|
|
font-size: 0.66rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.12em;
|
|
color: var(--accent2);
|
|
margin-bottom: 0.65rem;
|
|
}
|
|
.snapshot-value {
|
|
font-size: 1.4rem;
|
|
font-weight: 700;
|
|
letter-spacing: -0.03em;
|
|
margin-bottom: 0.4rem;
|
|
}
|
|
.snapshot-desc {
|
|
font-size: 0.82rem;
|
|
color: var(--muted);
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* --- CONTACT --- */
|
|
.contact-box {
|
|
background: linear-gradient(180deg, rgba(17,20,40,0.95), rgba(10,12,24,0.92));
|
|
border: 1px solid var(--border);
|
|
border-radius: 20px;
|
|
padding: 3rem;
|
|
text-align: center;
|
|
}
|
|
.contact-box h2 { font-size: 2rem; font-weight: 800; margin-bottom: 0.5rem; }
|
|
.contact-box p { color: var(--muted); margin-bottom: 2rem; }
|
|
|
|
/* --- FOOTER --- */
|
|
footer {
|
|
border-top: 1px solid var(--border);
|
|
padding: 2rem 0;
|
|
font-family: var(--mono);
|
|
font-size: 0.7rem;
|
|
color: var(--muted);
|
|
}
|
|
.footer-inner {
|
|
max-width: 900px;
|
|
margin: 0 auto;
|
|
padding: 0 2rem;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 1rem;
|
|
}
|
|
|
|
/* --- ANIMATIONS --- */
|
|
@keyframes fadeUp {
|
|
from { opacity: 0; transform: translateY(20px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
.reveal {
|
|
opacity: 0;
|
|
transform: translateY(24px);
|
|
transition: opacity 0.6s ease, transform 0.6s ease;
|
|
}
|
|
.reveal.visible {
|
|
opacity: 1;
|
|
transform: none;
|
|
}
|
|
|
|
@media (max-width: 600px) {
|
|
.nav-links { display: none; }
|
|
.hero { padding: 120px 0 60px; }
|
|
.contact-box { padding: 2rem 1.5rem; }
|
|
}
|
|
|
|
@media (max-width: 860px) {
|
|
.hero-strip,
|
|
.intro-panel {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<!-- Stars -->
|
|
<canvas id="stars"></canvas>
|
|
|
|
<!-- Nebula glows -->
|
|
<div class="nebula nebula-1"></div>
|
|
<div class="nebula nebula-2"></div>
|
|
<div class="nebula nebula-3"></div>
|
|
|
|
<!-- Nav -->
|
|
<nav>
|
|
<div class="nav-inner">
|
|
<a href="#" class="nav-logo">noctura<span>.dev</span></a>
|
|
<ul class="nav-links">
|
|
<li><a href="#about">Über mich</a></li>
|
|
<li><a href="#skills">Skills</a></li>
|
|
<li><a href="#projects">Projekte</a></li>
|
|
<li><a href="#snapshot">Profil</a></li>
|
|
<li><a href="#contact">Kontakt</a></li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Hero -->
|
|
<div class="wrapper">
|
|
<section class="hero">
|
|
<div class="hero-tag">Persönliches Portfolio / Web & Infrastruktur</div>
|
|
<h1>
|
|
Web entwickeln.
|
|
<span class="line2">Systeme verstehen.</span>
|
|
<span class="line3">Sauber bauen.</span>
|
|
</h1>
|
|
<p class="hero-desc">
|
|
Ich arbeite an Projekten, die nicht nur gut aussehen, sondern auch technisch nachvollziehbar aufgebaut sind.
|
|
Frontend, Backend, Linux und Hosting gehören für mich zusammen.
|
|
</p>
|
|
<div class="hero-actions">
|
|
<a href="#projects" class="btn btn-primary">Projekte ansehen</a>
|
|
<a href="#contact" class="btn btn-outline">Kontakt</a>
|
|
</div>
|
|
<div class="hero-strip">
|
|
<div class="hero-metric">
|
|
<div class="hero-metric-label">Fokus</div>
|
|
<div class="hero-metric-value">Frontend bis Deployment</div>
|
|
<p class="hero-metric-copy">Ich denke nicht nur in Screens, sondern in vollständigen Umsetzungen.</p>
|
|
</div>
|
|
<div class="hero-metric">
|
|
<div class="hero-metric-label">Arbeitsweise</div>
|
|
<div class="hero-metric-value">Direkt und praktisch</div>
|
|
<p class="hero-metric-copy">Lieber echte Projekte und klare Entscheidungen als Buzzwords und leere Claims.</p>
|
|
</div>
|
|
<div class="hero-metric">
|
|
<div class="hero-metric-label">Stack</div>
|
|
<div class="hero-metric-value">HTML, CSS, JS, Linux, Docker</div>
|
|
<p class="hero-metric-copy">Genug Breite, um Interfaces, Services und Betrieb zusammen zu denken.</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="section-divider"></div>
|
|
|
|
<section id="about">
|
|
<div class="reveal">
|
|
<div class="section-label">// Über mich</div>
|
|
<p class="section-subtitle">Genau so sollte sich ein Portfolio für Bewerbungen lesen.</p>
|
|
</div>
|
|
<div class="intro-panel reveal">
|
|
<div class="intro-copy">
|
|
<p>
|
|
Ich entwickle nicht nur Oberflächen, sondern kümmere mich auch darum, wie Anwendungen betrieben,
|
|
abgesichert und langfristig verständlich gehalten werden.
|
|
</p>
|
|
<p>
|
|
Gerade deshalb passt zu mir eher ein Portfolio mit Persönlichkeit: Projekte, Entscheidungen,
|
|
Infrastruktur und Lernweg sichtbar machen, statt wie eine kleine IT-Firma aufzutreten.
|
|
</p>
|
|
</div>
|
|
<div class="intro-notes">
|
|
<div class="hero-card-label">Was Recruiter hier schnell sehen sollen</div>
|
|
<ul class="note-list">
|
|
<li>Ich kann gestalten, bauen und deployen.</li>
|
|
<li>Ich arbeite eigenständig und technisch neugierig.</li>
|
|
<li>Meine Projekte sind nicht nur Demos, sondern echte Systeme.</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="section-divider"></div>
|
|
|
|
<!-- Skills -->
|
|
<section id="skills">
|
|
<div class="reveal">
|
|
<div class="section-label">// Fähigkeiten</div>
|
|
<h2 class="section-title">Was ich kann</h2>
|
|
<p class="section-subtitle">Breit genug für komplette Projekte, fokussiert genug für gute Details.</p>
|
|
</div>
|
|
<div class="skills-grid reveal">
|
|
<div class="skill-card purple">
|
|
<span class="skill-icon">⟨/⟩</span>
|
|
<div class="skill-name">Frontend & Interfaces</div>
|
|
<p class="skill-desc">Responsive Oberflächen, klares UI und saubere Struktur. Ich mag Seiten, die Charakter haben und trotzdem verständlich bleiben.</p>
|
|
<div class="skill-tags">
|
|
<span class="tag purple">HTML / CSS</span>
|
|
<span class="tag purple">JavaScript</span>
|
|
<span class="tag purple">UI Design</span>
|
|
<span class="tag purple">Responsive Layouts</span>
|
|
</div>
|
|
</div>
|
|
<div class="skill-card teal">
|
|
<span class="skill-icon">⬡</span>
|
|
<div class="skill-name">Backend & Infrastruktur</div>
|
|
<p class="skill-desc">Services selbst aufsetzen, verbinden und betreiben. Nicht nur deployen, sondern verstehen, was dahinter läuft.</p>
|
|
<div class="skill-tags">
|
|
<span class="tag teal">Docker</span>
|
|
<span class="tag teal">Caddy</span>
|
|
<span class="tag teal">Node.js</span>
|
|
<span class="tag teal">Forgejo</span>
|
|
<span class="tag teal">REST APIs</span>
|
|
</div>
|
|
</div>
|
|
<div class="skill-card orange">
|
|
<span class="skill-icon">$_</span>
|
|
<div class="skill-name">Linux & Betrieb</div>
|
|
<p class="skill-desc">Server einrichten, absichern und dauerhaft sinnvoll betreiben. Besonders spannend finde ich alles rund um Self-hosting und Wartbarkeit.</p>
|
|
<div class="skill-tags">
|
|
<span class="tag orange">Debian Linux</span>
|
|
<span class="tag orange">SSH</span>
|
|
<span class="tag orange">systemd</span>
|
|
<span class="tag orange">ufw / fail2ban</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="section-divider"></div>
|
|
|
|
<!-- Projects -->
|
|
<section id="projects">
|
|
<div class="reveal">
|
|
<div class="section-label">// Portfolio</div>
|
|
<h2 class="section-title">Ausgewählte Arbeiten</h2>
|
|
<p class="section-subtitle">Nicht als Produktkatalog, sondern als Ausschnitt meiner Denkweise.</p>
|
|
</div>
|
|
<div class="projects-grid reveal">
|
|
|
|
<div class="project-card">
|
|
<div class="project-header">
|
|
<div>
|
|
<div class="project-eyebrow">Tooling</div>
|
|
<div class="project-name">Developer Utilities</div>
|
|
</div>
|
|
<span class="project-arrow">↗</span>
|
|
</div>
|
|
<p class="project-desc">Sammlung kleiner Web-Tools, bei denen UX und Geschwindigkeit wichtiger sind als Marketing. Gut geeignet, um Pragmatismus und Produktgefühl zu zeigen.</p>
|
|
<div class="project-status">
|
|
<span class="status-dot status-wip"></span>
|
|
<span style="color: var(--muted);">In Entwicklung</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="project-card">
|
|
<div class="project-header">
|
|
<div>
|
|
<div class="project-eyebrow">Backend</div>
|
|
<div class="project-name">Custom Backend API</div>
|
|
</div>
|
|
<span class="project-arrow">↗</span>
|
|
</div>
|
|
<p class="project-desc">Eigene API-Struktur für persönliche Projekte. Der Reiz liegt für mich darin, Datenmodelle, Routing und Hosting selbst sauber zu kontrollieren.</p>
|
|
<div class="project-status">
|
|
<span class="status-dot status-wip"></span>
|
|
<span style="color: var(--muted);">In Entwicklung</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="project-card">
|
|
<div class="project-header">
|
|
<div>
|
|
<div class="project-eyebrow">Experiment</div>
|
|
<div class="project-name">Lab / Playground</div>
|
|
</div>
|
|
<span class="project-arrow">↗</span>
|
|
</div>
|
|
<p class="project-desc">Platz für Prototypen, Designideen und technische Versuche. Gerade dieser Bereich macht sichtbar, wie ich lerne und neue Themen erschließe.</p>
|
|
<div class="project-status">
|
|
<span class="status-dot status-planned"></span>
|
|
<span style="color: var(--muted);">Geplant</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="project-card">
|
|
<div class="project-header">
|
|
<div>
|
|
<div class="project-eyebrow">Infrastruktur</div>
|
|
<div class="project-name">noctura.dev Infrastruktur</div>
|
|
</div>
|
|
<span class="project-arrow">↗</span>
|
|
</div>
|
|
<p class="project-desc">Mein stärkstes Portfolio-Stück im Hintergrund: ein selbst verwalteter VPS mit echten Services, nicht nur eine statische Visitenkarte.</p>
|
|
<div class="project-status">
|
|
<span class="status-dot status-live"></span>
|
|
<span style="color: var(--muted);">Live</span>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</section>
|
|
|
|
<div class="section-divider"></div>
|
|
|
|
<section id="snapshot">
|
|
<div class="reveal">
|
|
<div class="section-label">// Profil</div>
|
|
<h2 class="section-title">Was hängen bleibt</h2>
|
|
<p class="section-subtitle">Die kurze Zusammenfassung für Bewerbungen und schnelle Erstgespräche.</p>
|
|
</div>
|
|
<div class="snapshot-grid reveal">
|
|
<div class="snapshot-card">
|
|
<div class="snapshot-kicker">Arbeitsweise</div>
|
|
<div class="snapshot-value">Praktisch</div>
|
|
<p class="snapshot-desc">Ich lerne am liebsten über echte Umsetzungen, nicht nur über Theorie oder Tutorial-Nachbau.</p>
|
|
</div>
|
|
<div class="snapshot-card">
|
|
<div class="snapshot-kicker">Stärke</div>
|
|
<div class="snapshot-value">Full stack denken</div>
|
|
<p class="snapshot-desc">Vom Interface bis zum Server kann ich Entscheidungen zusammenhängend betrachten und umsetzen.</p>
|
|
</div>
|
|
<div class="snapshot-card">
|
|
<div class="snapshot-kicker">Motivation</div>
|
|
<div class="snapshot-value">Eigene Systeme verstehen</div>
|
|
<p class="snapshot-desc">Mich reizt Technik dann besonders, wenn ich sie selbst aufbauen, betreiben und verbessern kann.</p>
|
|
</div>
|
|
<div class="snapshot-card">
|
|
<div class="snapshot-kicker">Eindruck</div>
|
|
<div class="snapshot-value">Kein Buzzword-Profil</div>
|
|
<p class="snapshot-desc">Die Seite soll zeigen, wie ich denke und arbeite, nicht nur welche Begriffe ich aufzählen kann.</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="section-divider"></div>
|
|
|
|
<!-- Contact -->
|
|
<section id="contact">
|
|
<div class="contact-box reveal">
|
|
<h2>Kontakt für Bewerbungen oder Projekte</h2>
|
|
<p>Wenn du einen Entwickler suchst, der nicht nur UI klickt, sondern Systeme wirklich verstehen will, schreib mir.</p>
|
|
<a href="mailto:kontakt@noctura.dev" class="btn btn-primary">kontakt@noctura.dev</a>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<footer>
|
|
<div class="footer-inner">
|
|
<span>noctura.dev - persönliches Portfolio mit eigener Infrastruktur</span>
|
|
<span>HTML · CSS · JavaScript · Debian 12</span>
|
|
</div>
|
|
</footer>
|
|
|
|
<script>
|
|
// Star field
|
|
const canvas = document.getElementById('stars');
|
|
const ctx = canvas.getContext('2d');
|
|
let stars = [];
|
|
function resize() {
|
|
canvas.width = window.innerWidth;
|
|
canvas.height = window.innerHeight;
|
|
stars = Array.from({length: 180}, () => ({
|
|
x: Math.random() * canvas.width,
|
|
y: Math.random() * canvas.height,
|
|
r: Math.random() * 1.2 + 0.2,
|
|
o: Math.random() * 0.6 + 0.1,
|
|
s: Math.random() * 0.4 + 0.1,
|
|
t: Math.random() * Math.PI * 2
|
|
}));
|
|
}
|
|
function drawStars(ts) {
|
|
ctx.clearRect(0,0,canvas.width,canvas.height);
|
|
stars.forEach(s => {
|
|
s.t += 0.008 * s.s;
|
|
const o = s.o * (0.6 + 0.4 * Math.sin(s.t));
|
|
ctx.beginPath();
|
|
ctx.arc(s.x, s.y, s.r, 0, Math.PI*2);
|
|
ctx.fillStyle = `rgba(200,210,255,${o})`;
|
|
ctx.fill();
|
|
});
|
|
requestAnimationFrame(drawStars);
|
|
}
|
|
window.addEventListener('resize', resize);
|
|
resize();
|
|
requestAnimationFrame(drawStars);
|
|
|
|
// Scroll reveal
|
|
const reveals = document.querySelectorAll('.reveal');
|
|
const io = new IntersectionObserver(entries => {
|
|
entries.forEach((e,i) => {
|
|
if (e.isIntersecting) {
|
|
setTimeout(() => e.target.classList.add('visible'), i * 80);
|
|
io.unobserve(e.target);
|
|
}
|
|
});
|
|
}, { threshold: 0.12 });
|
|
reveals.forEach(el => io.observe(el));
|
|
</script>
|
|
</body>
|
|
</html>
|