feat: add playSudoEasterEgg terminal simulation and hook into command palette

This commit is contained in:
Chneemann 2026-07-28 09:07:42 +02:00
parent 1d15fb28c3
commit f56a30ee02
2 changed files with 127 additions and 11 deletions

View file

@ -1,3 +1,5 @@
import { playSudoEasterEgg } from "./playSudoEasterEgg";
/** /**
* Command item structure for the Cmd+K palette * Command item structure for the Cmd+K palette
*/ */
@ -18,7 +20,7 @@ export const getCommands = (
): CommandItem[] => [ ): CommandItem[] => [
{ {
id: "copy-email", id: "copy-email",
label: copied ? "Email Copied!" : "Copy Email (dev@andre-kempf.com)", label: copied ? "Email Copied!" : "Copy Email (dev@andre-kempf.com)",
category: "Quick Actions", category: "Quick Actions",
icon: copied ? "✓" : "✉️", icon: copied ? "✓" : "✉️",
action: () => { action: () => {
@ -29,15 +31,15 @@ export const getCommands = (
}, },
{ {
id: "download-cv", id: "download-cv",
label: "Download Resume / CV (PDF)", label: "Download CV (PDF)",
category: "Quick Actions", category: "Quick Actions",
icon: "📄", icon: "📄",
action: () => { action: () => {
const link = document.createElement("a"); window.open(
link.href = "/assets/downloads/Andre_Kempf_Lebenslauf.pdf",
"https://andre-kempf.com/assets/downloads/Andre_Kempf_Lebenslauf_2025.pdf"; "_blank",
link.download = "Andre_Kempf_Lebenslauf.pdf"; "noopener,noreferrer",
link.click(); );
}, },
}, },
{ {
@ -55,7 +57,11 @@ export const getCommands = (
category: "Social / Links", category: "Social / Links",
icon: "🏔️", icon: "🏔️",
action: () => { action: () => {
window.open("https://codeberg.org/Chneemann", "_blank"); window.open(
"https://codeberg.org/Chneemann",
"_blank",
"noopener,noreferrer",
);
}, },
}, },
{ {
@ -64,7 +70,11 @@ export const getCommands = (
category: "Social / Links", category: "Social / Links",
icon: "🐙", icon: "🐙",
action: () => { action: () => {
window.open("https://github.com/andre-kempf", "_blank"); window.open(
"https://github.com/andre-kempf",
"_blank",
"noopener,noreferrer",
);
}, },
}, },
{ {
@ -73,7 +83,11 @@ export const getCommands = (
category: "Social / Links", category: "Social / Links",
icon: "💼", icon: "💼",
action: () => { action: () => {
window.open("https://linkedin.com/in/andre-kempf", "_blank"); window.open(
"https://linkedin.com/in/andre-kempf",
"_blank",
"noopener,noreferrer",
);
}, },
}, },
{ {
@ -82,7 +96,18 @@ export const getCommands = (
category: "Social / Links", category: "Social / Links",
icon: "💻", icon: "💻",
action: () => { action: () => {
window.open("https://codeberg.org/Chneemann/portfolio", "_blank"); window.open(
"https://codeberg.org/Chneemann/portfolio",
"_blank",
"noopener,noreferrer",
);
}, },
}, },
{
id: "sudo-egg",
label: "sudo rm -rf --no-preserve-root /",
category: "System & Info",
icon: "💀",
action: playSudoEasterEgg,
},
]; ];

View file

@ -0,0 +1,91 @@
/**
* Triggers a simulated terminal kernel panic overlay ("sudo rm -rf").
* Appends a full-screen DOM overlay, streams logs with delayed timeouts, and cleans up automatically.
*/
export function playSudoEasterEgg() {
// Create full-screen terminal overlay element
const flashOverlay = document.createElement("div");
flashOverlay.className =
"fixed inset-0 z-[99999] bg-black text-xs font-mono flex flex-col justify-between p-6 md:p-12 selection:bg-red-500 selection:text-white select-none backdrop-blur-xl animate-in fade-in duration-75 overflow-hidden";
flashOverlay.innerHTML = `
<div id="terminal-logs" class="max-w-3xl space-y-1.5 text-slate-300"></div>
<div id="terminal-footer" class="flex justify-between items-center text-[10px] text-red-500 font-bold border-t border-red-900/60 pt-3 opacity-0 transition-opacity duration-300">
<span class="animate-pulse">CRITICAL_SYSTEM_FAILURE // NO_OPERATING_SYSTEM_FOUND</span>
<span>RECOVERING SNAPSHOT...</span>
</div>
`;
document.body.appendChild(flashOverlay);
const logsContainer = flashOverlay.querySelector("#terminal-logs");
const footer = flashOverlay.querySelector("#terminal-footer");
// Helper to append formatted log HTML strings to the container
const appendLog = (htmlString: string) => {
if (!logsContainer) return;
const temp = document.createElement("div");
temp.innerHTML = htmlString.trim();
if (temp.firstElementChild)
logsContainer.appendChild(temp.firstElementChild);
};
// Timed output lines simulating system destruction and resolution
const lines = [
{
html: `<p class="text-slate-500">[ 0.000000] Linux kernel init sequence started...</p>`,
delay: 100,
},
{
html: `<p class="text-red-500 font-bold pt-2">root@andre-kempf-portfolio:~# sudo rm -rf --no-preserve-root /</p>`,
delay: 400,
},
{
html: `<p class="text-red-400 font-mono">rm: unlinking '/etc/shadow'...</p>`,
delay: 700,
},
{
html: `<p class="text-red-400 font-mono">rm: unlinking '/boot/vmlinuz-6.8.0-generic'...</p>`,
delay: 900,
},
{
html: `<p class="text-red-400 font-mono">rm: unlinking '/var/www/portfolio/index.html'...</p>`,
delay: 1100,
},
{
html: `<p class="text-red-600 font-bold bg-red-950/80 px-2 py-1 rounded my-1 border border-red-800">Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000009</p>`,
delay: 1500,
},
{
html: `
<div class="p-4 rounded bg-red-950/90 border border-red-600 text-red-200 space-y-2 my-4 shadow-2xl animate-pulse">
<p class="font-bold text-sm text-red-400 flex items-center gap-2">
<span>🚨</span> CRITICAL SECURITY ALERT: HARD DRIVE WIPED
</p>
<p class="text-xs leading-relaxed text-red-300/90">
Wiping process executed on <code class="bg-red-900/60 px-1 rounded text-white">/dev/nvme0n1</code>. All system files, database records, and site assets have been purged.
</p>
<p class="text-[10px] text-red-400/80 border-t border-red-900/80 pt-2 font-mono">
[Incident logged. IP & Session details sent to administrator.]
</p>
</div>`,
delay: 2000,
},
{
html: `<p class="text-emerald-400 font-bold pt-2 animate-bounce">✓ ...Just kidding! System is write-protected. Relax!</p>`,
delay: 5200,
},
];
// Stream terminal lines sequentially
lines.forEach(({ html, delay }) => setTimeout(() => appendLog(html), delay));
// Show footer warning message
setTimeout(() => footer?.classList.remove("opacity-0"), 2200);
// Fade out and remove overlay element from DOM
setTimeout(() => {
flashOverlay.classList.add("animate-out", "fade-out", "duration-500");
setTimeout(() => flashOverlay.remove(), 500);
}, 7500);
}