Files
pivoine.art/layouts/404.html
Sebastian Krüger 133046eebe feat: add custom 404 error page
- Create stylish 404 page with glitch animation and CRT scanline effects
- Update nginx to serve custom 404 instead of falling back to index.html
- Page inherits site layout with WebGL background and audio player

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 19:55:17 +01:00

148 lines
3.4 KiB
HTML

{{ define "main" }}
<style>
/* Glitch animation for 404 text */
.glitch {
position: relative;
font-size: clamp(8rem, 20vw, 16rem);
font-weight: 700;
line-height: 1;
color: #fff;
letter-spacing: 0.02em;
animation: glitch-skew 4s infinite linear alternate-reverse;
}
.glitch::before,
.glitch::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.glitch::before {
color: #ff00ff;
animation: glitch-1 2s infinite linear alternate-reverse;
clip-path: polygon(0 0, 100% 0, 100% 35%, 0 35%);
}
.glitch::after {
color: #00ffff;
animation: glitch-2 3s infinite linear alternate-reverse;
clip-path: polygon(0 65%, 100% 65%, 100% 100%, 0 100%);
}
@keyframes glitch-1 {
0%, 100% { transform: translate(0); }
20% { transform: translate(-3px, 3px); }
40% { transform: translate(-3px, -3px); }
60% { transform: translate(3px, 3px); }
80% { transform: translate(3px, -3px); }
}
@keyframes glitch-2 {
0%, 100% { transform: translate(0); }
20% { transform: translate(3px, -3px); }
40% { transform: translate(3px, 3px); }
60% { transform: translate(-3px, -3px); }
80% { transform: translate(-3px, 3px); }
}
@keyframes glitch-skew {
0%, 100% { transform: skew(0deg); }
30% { transform: skew(0.5deg); }
60% { transform: skew(-0.5deg); }
}
/* Scanline overlay */
.scanlines {
position: fixed;
inset: 0;
pointer-events: none;
z-index: 10;
background: repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0.1) 0px,
rgba(0, 0, 0, 0.1) 1px,
transparent 1px,
transparent 2px
);
animation: scanline-flicker 0.1s infinite;
}
@keyframes scanline-flicker {
0%, 100% { opacity: 0.8; }
50% { opacity: 0.85; }
}
/* CRT vignette effect */
.vignette {
position: fixed;
inset: 0;
pointer-events: none;
z-index: 9;
background: radial-gradient(
ellipse at center,
transparent 0%,
transparent 60%,
rgba(0, 0, 0, 0.4) 100%
);
}
/* Button hover effect */
.return-btn {
position: relative;
overflow: hidden;
transition: all 0.3s ease;
}
.return-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.1),
transparent
);
transition: left 0.5s ease;
}
.return-btn:hover::before {
left: 100%;
}
.return-btn:hover {
transform: translateY(-2px);
box-shadow: 0 0 20px rgba(255, 255, 255, 0.1);
}
</style>
<div class="scanlines"></div>
<div class="vignette"></div>
<section class="min-h-screen flex flex-col items-center justify-center px-4 relative z-20">
<div class="text-center">
<h1 class="glitch font-mono" data-text="404">404</h1>
<p class="mt-8 text-xl md:text-2xl text-text-secondary font-mono tracking-widest uppercase">
Signal Lost
</p>
<div class="mt-12">
<a
href="/"
class="return-btn inline-block px-8 py-4 border border-text-secondary/30 text-text-primary font-mono text-sm tracking-wider uppercase hover:border-text-primary/50 focus:outline-none focus:ring-2 focus:ring-text-primary/30 focus:ring-offset-2 focus:ring-offset-bg-primary"
>
Return Home
</a>
</div>
</div>
</section>
{{ end }}