feat: Add interactive kernel panic 404 page
Some checks failed
Production Deployment (Zero Downtime) / deploy-production (push) Has been cancelled
Some checks failed
Production Deployment (Zero Downtime) / deploy-production (push) Has been cancelled
- Terminal-style 404 page with boot sequence - Interactive command line with file system - Easter eggs: hawkins/011, fsociety, 42, rm -rf / - CRT monitor effects and visual glitches - Audio synthesis for key presses and effects - Full terminal emulator with commands: ls, cd, cat, grep, etc.
This commit is contained in:
703
app/components/KernelPanic404.tsx
Normal file
703
app/components/KernelPanic404.tsx
Normal file
@@ -0,0 +1,703 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
interface FileSystemNode {
|
||||||
|
type: 'file' | 'dir' | 'exe';
|
||||||
|
content?: string;
|
||||||
|
children?: Record<string, FileSystemNode>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function KernelPanic404() {
|
||||||
|
const outputRef = useRef<HTMLDivElement>(null);
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
const inputContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const [systemFrozen, setSystemFrozen] = useState(false);
|
||||||
|
const [currentMusic, setCurrentMusic] = useState<{ stop?: () => void } | null>(null);
|
||||||
|
const [hawkinsActive, setHawkinsActive] = useState(false);
|
||||||
|
const [fsocietyActive, setFsocietyActive] = useState(false);
|
||||||
|
const [commandHistory, setCommandHistory] = useState<string[]>([]);
|
||||||
|
const [historyIndex, setHistoryIndex] = useState(-1);
|
||||||
|
const [currentPath, setCurrentPath] = useState<FileSystemNode | null>(null);
|
||||||
|
const [pathStr, setPathStr] = useState("~");
|
||||||
|
const audioCtxRef = useRef<AudioContext | null>(null);
|
||||||
|
|
||||||
|
// File system structure
|
||||||
|
const fileSystem: { home: FileSystemNode; var: FileSystemNode; etc: FileSystemNode; bin: FileSystemNode; tmp: FileSystemNode } = {
|
||||||
|
home: {
|
||||||
|
type: "dir",
|
||||||
|
children: {
|
||||||
|
guest: {
|
||||||
|
type: "dir",
|
||||||
|
children: {
|
||||||
|
"readme.txt": {
|
||||||
|
type: "file",
|
||||||
|
content: "ERROR 404: Page Not Found.\n\nSystem Integrity: 89%\nCheck /var/log for clues.\n\nTry: ls -la, cat .bash_history"
|
||||||
|
},
|
||||||
|
".bash_history": {
|
||||||
|
type: "file",
|
||||||
|
content: "ls -la\nwhoami\nfsociety\nexit"
|
||||||
|
},
|
||||||
|
"todo.txt": {
|
||||||
|
type: "file",
|
||||||
|
content: "- Fix the internet\n- Calculate the Ultimate Answer (try: 42)\n- Buy milk\n- Check Hawkins Lab logs"
|
||||||
|
},
|
||||||
|
"projects": {
|
||||||
|
type: "dir",
|
||||||
|
children: {
|
||||||
|
website: {
|
||||||
|
type: "dir",
|
||||||
|
children: {
|
||||||
|
"index.html": { type: "file", content: "<html><body>404</body></html>" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
var: {
|
||||||
|
type: "dir",
|
||||||
|
children: {
|
||||||
|
log: {
|
||||||
|
type: "dir",
|
||||||
|
children: {
|
||||||
|
syslog: {
|
||||||
|
type: "file",
|
||||||
|
content: "[ERR] Reality breach detected in HAWKINS_LAB sector.\n[WARN] Subject 011 has escaped containment.\n[ALERT] Dimensional gate unstable.\n[INFO] Try command: hawkins or 011"
|
||||||
|
},
|
||||||
|
"kern.log": {
|
||||||
|
type: "file",
|
||||||
|
content: "[ 0.000000] Linus Torvalds: 'This kernel is garbage.'\n[ 0.100000] Kernel tainted: M (Module has bad license)\n[ 0.200000] Torvalds: 'I'm not angry, just disappointed.'"
|
||||||
|
},
|
||||||
|
"auth.log": {
|
||||||
|
type: "file",
|
||||||
|
content: "Failed password for root from 127.0.0.1\nFailed password for elliot from 127.0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
etc: {
|
||||||
|
type: "dir",
|
||||||
|
children: {
|
||||||
|
passwd: {
|
||||||
|
type: "file",
|
||||||
|
content: "root:x:0:0:root:/root:/bin/bash\nguest:x:1000:1000:guest:/home/guest:/bin/bash\nelliot:x:509:509:mr_robot:/home/elliot:/bin/sh"
|
||||||
|
},
|
||||||
|
hosts: {
|
||||||
|
type: "file",
|
||||||
|
content: "127.0.0.1 localhost\n127.0.0.1 e-corp.com\n0.0.0.0 reality"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bin: {
|
||||||
|
type: "dir",
|
||||||
|
children: {
|
||||||
|
ls: { type: "exe" },
|
||||||
|
cat: { type: "exe" },
|
||||||
|
grep: { type: "exe" },
|
||||||
|
find: { type: "exe" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tmp: {
|
||||||
|
type: "dir",
|
||||||
|
children: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
|
||||||
|
const printLine = (text: string, type?: string) => {
|
||||||
|
if (!outputRef.current) return;
|
||||||
|
const d = document.createElement('div');
|
||||||
|
d.innerHTML = text;
|
||||||
|
if (type === 'log-warn') d.style.color = '#ffb000';
|
||||||
|
if (type === 'log-err' || type === 'alert') d.style.color = '#ff3333';
|
||||||
|
if (type === 'log-dim') d.style.opacity = '0.6';
|
||||||
|
if (type === 'log-sys') d.style.color = 'cyan';
|
||||||
|
if (type === 'log-k') d.style.color = '#fff';
|
||||||
|
if (type === 'pulse-red') {
|
||||||
|
d.classList.add('pulse-red');
|
||||||
|
d.style.color = '#ff3333';
|
||||||
|
d.style.textShadow = '0 0 10px red';
|
||||||
|
}
|
||||||
|
outputRef.current.appendChild(d);
|
||||||
|
if (outputRef.current) {
|
||||||
|
outputRef.current.scrollTop = outputRef.current.scrollHeight;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const playSynth = (type: string) => {
|
||||||
|
try {
|
||||||
|
if (!audioCtxRef.current || systemFrozen) return;
|
||||||
|
const t = audioCtxRef.current.currentTime;
|
||||||
|
const osc = audioCtxRef.current.createOscillator();
|
||||||
|
const gain = audioCtxRef.current.createGain();
|
||||||
|
osc.connect(gain);
|
||||||
|
gain.connect(audioCtxRef.current.destination);
|
||||||
|
|
||||||
|
if (type === 'key') {
|
||||||
|
osc.type = 'square';
|
||||||
|
osc.frequency.setValueAtTime(600, t);
|
||||||
|
gain.gain.setValueAtTime(0.02, t);
|
||||||
|
gain.gain.exponentialRampToValueAtTime(0.001, t + 0.05);
|
||||||
|
osc.start();
|
||||||
|
osc.stop(t + 0.05);
|
||||||
|
} else if (type === 'beep') {
|
||||||
|
osc.type = 'sine';
|
||||||
|
osc.frequency.setValueAtTime(800, t);
|
||||||
|
gain.gain.setValueAtTime(0.1, t);
|
||||||
|
gain.gain.exponentialRampToValueAtTime(0.001, t + 0.2);
|
||||||
|
osc.start();
|
||||||
|
osc.stop(t + 0.2);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ignore audio errors
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCurrentDir = (): FileSystemNode => {
|
||||||
|
if (pathStr === "~" || pathStr.startsWith("~/")) {
|
||||||
|
return fileSystem.home.children!.guest;
|
||||||
|
} else if (pathStr.startsWith("/var/log")) {
|
||||||
|
// Return a wrapper node for /var/log directory
|
||||||
|
return {
|
||||||
|
type: 'dir',
|
||||||
|
children: fileSystem.var.children!.log.children
|
||||||
|
};
|
||||||
|
} else if (pathStr.startsWith("/var")) {
|
||||||
|
return fileSystem.var;
|
||||||
|
} else if (pathStr.startsWith("/etc")) {
|
||||||
|
return fileSystem.etc;
|
||||||
|
} else if (pathStr.startsWith("/bin")) {
|
||||||
|
return fileSystem.bin;
|
||||||
|
}
|
||||||
|
return currentPath || fileSystem.home.children!.guest;
|
||||||
|
};
|
||||||
|
|
||||||
|
const runCmd = async (cmdRaw: string) => {
|
||||||
|
if (systemFrozen || !outputRef.current) return;
|
||||||
|
|
||||||
|
printLine(`guest@404:${pathStr}$ ${cmdRaw}`, 'log-dim');
|
||||||
|
const args = cmdRaw.split(/\s+/);
|
||||||
|
const cmd = args[0].toLowerCase();
|
||||||
|
|
||||||
|
const newHistory = [...commandHistory, cmdRaw];
|
||||||
|
setCommandHistory(newHistory);
|
||||||
|
setHistoryIndex(newHistory.length);
|
||||||
|
|
||||||
|
await sleep(100);
|
||||||
|
|
||||||
|
const dir = getCurrentDir();
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case 'help':
|
||||||
|
printLine("--- SYSTEM UTILS ---", "log-sys");
|
||||||
|
printLine(" ls, cd, cat, grep, find, pwd, clear");
|
||||||
|
printLine(" whoami, uname, history, date, uptime");
|
||||||
|
printLine(" head, tail, wc, sort, uniq");
|
||||||
|
printLine("--- NETWORK ---", "log-sys");
|
||||||
|
printLine(" ping, hostname");
|
||||||
|
printLine("--- PROCESSES ---", "log-sys");
|
||||||
|
printLine(" ps, top, kill");
|
||||||
|
printLine("(Hints are hidden in the file system - try ls -la)");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ls':
|
||||||
|
const showHidden = args.includes('-a') || args.includes('-la') || args.includes('-l');
|
||||||
|
const longFormat = args.includes('-l') || args.includes('-la');
|
||||||
|
const items = Object.keys(dir.children || {})
|
||||||
|
.filter(n => !n.startsWith('.') || showHidden);
|
||||||
|
if (showHidden) {
|
||||||
|
items.unshift('..');
|
||||||
|
items.unshift('.');
|
||||||
|
}
|
||||||
|
items.sort((a, b) => {
|
||||||
|
if (a === '.') return -1;
|
||||||
|
if (b === '.') return 1;
|
||||||
|
if (a === '..') return -1;
|
||||||
|
if (b === '..') return 1;
|
||||||
|
const itemA = dir.children?.[a] as FileSystemNode | undefined;
|
||||||
|
const itemB = dir.children?.[b] as FileSystemNode | undefined;
|
||||||
|
if (!itemA || !itemB) return 0;
|
||||||
|
if (itemA.type === 'dir' && itemB.type !== 'dir') return -1;
|
||||||
|
if (itemA.type !== 'dir' && itemB.type === 'dir') return 1;
|
||||||
|
return a.localeCompare(b);
|
||||||
|
});
|
||||||
|
if (longFormat) {
|
||||||
|
printLine(`total ${items.length}`);
|
||||||
|
items.forEach(n => {
|
||||||
|
const item = dir.children?.[n];
|
||||||
|
if (!item && n !== '.' && n !== '..') return;
|
||||||
|
const isDir = item?.type === 'dir' || n === '.' || n === '..';
|
||||||
|
const perms = isDir ? 'drwxr-xr-x' : '-rw-r--r--';
|
||||||
|
const links = isDir ? '2' : '1';
|
||||||
|
const size = isDir ? '4096'.padStart(8) : (item?.content?.length || '0').toString().padStart(8);
|
||||||
|
const date = new Date();
|
||||||
|
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||||
|
const month = monthNames[date.getMonth()];
|
||||||
|
const day = date.getDate().toString().padStart(2);
|
||||||
|
const time = date.toTimeString().substring(0, 5);
|
||||||
|
const dateStr = `${month} ${day} ${time}`;
|
||||||
|
const filename = isDir ? `<span class='is-dir'>${n}/</span>` : n;
|
||||||
|
printLine(`${perms} ${links} guest guest ${size} ${dateStr} ${filename}`);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const formatted = items.map(n => {
|
||||||
|
const item = dir.children?.[n];
|
||||||
|
if (n === '.' || n === '..') return `<span class='is-dir'>${n}/</span>`;
|
||||||
|
if (item?.type === 'dir') return `<span class='is-dir'>${n}/</span>`;
|
||||||
|
if (item?.type === 'exe') return `<span class='is-exe'>${n}*</span>`;
|
||||||
|
return n;
|
||||||
|
});
|
||||||
|
printLine(formatted.join(' '));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'cat':
|
||||||
|
const file = dir.children?.[args[1]] as FileSystemNode | undefined;
|
||||||
|
if (file && file.type === 'file') {
|
||||||
|
printLine(file.content || '');
|
||||||
|
} else {
|
||||||
|
printLine(`cat: ${args[1] || ''}: No such file`, 'log-err');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'cd':
|
||||||
|
if (!args[1]) {
|
||||||
|
setCurrentPath(fileSystem.home.children!.guest);
|
||||||
|
setPathStr("~");
|
||||||
|
} else if (args[1] === '..') {
|
||||||
|
if (pathStr === "/var/log") {
|
||||||
|
setCurrentPath(fileSystem.var);
|
||||||
|
setPathStr("/var");
|
||||||
|
} else if (pathStr === "/var") {
|
||||||
|
setPathStr("/");
|
||||||
|
} else {
|
||||||
|
setCurrentPath(fileSystem.home.children!.guest);
|
||||||
|
setPathStr("~");
|
||||||
|
}
|
||||||
|
} else if (args[1] === '~' || args[1] === '/home/guest') {
|
||||||
|
setCurrentPath(fileSystem.home.children!.guest);
|
||||||
|
setPathStr("~");
|
||||||
|
} else if (args[1].startsWith('/var/log')) {
|
||||||
|
setCurrentPath({
|
||||||
|
type: 'dir',
|
||||||
|
children: fileSystem.var.children!.log.children
|
||||||
|
});
|
||||||
|
setPathStr("/var/log");
|
||||||
|
} else if (args[1].startsWith('/var')) {
|
||||||
|
setCurrentPath(fileSystem.var);
|
||||||
|
setPathStr("/var");
|
||||||
|
} else if (args[1].startsWith('/etc')) {
|
||||||
|
setCurrentPath(fileSystem.etc);
|
||||||
|
setPathStr("/etc");
|
||||||
|
} else {
|
||||||
|
const subdir = dir.children?.[args[1]] as FileSystemNode | undefined;
|
||||||
|
if (subdir && subdir.type === 'dir') {
|
||||||
|
setCurrentPath(subdir);
|
||||||
|
setPathStr(pathStr === "~" ? `~/${args[1]}` : `${pathStr}/${args[1]}`);
|
||||||
|
} else {
|
||||||
|
printLine(`cd: ${args[1]}: No such file or directory`, 'log-err');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'pwd':
|
||||||
|
printLine(pathStr === "~" ? "/home/guest" : pathStr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'grep':
|
||||||
|
if (args.length < 3) {
|
||||||
|
printLine("Usage: grep [pattern] [file]");
|
||||||
|
} else {
|
||||||
|
const grepFile = dir.children?.[args[2]] as FileSystemNode | undefined;
|
||||||
|
if (grepFile && grepFile.type === 'file' && grepFile.content) {
|
||||||
|
const lines = grepFile.content.split('\n');
|
||||||
|
lines.forEach(l => {
|
||||||
|
if (l.toLowerCase().includes(args[1].toLowerCase())) {
|
||||||
|
printLine(l);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
printLine(`grep: ${args[2]}: No such file`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'whoami':
|
||||||
|
printLine("guest");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'uname':
|
||||||
|
if (args.includes('-a')) {
|
||||||
|
printLine("Linux 404-void 4.0.4-void #1 SMP PREEMPT Fri Jan 09 2025 x86_64 GNU/Linux");
|
||||||
|
} else {
|
||||||
|
printLine("Linux");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'date':
|
||||||
|
printLine(new Date().toString());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'uptime':
|
||||||
|
const uptime = Math.floor((Date.now() - performance.timing.navigationStart) / 1000);
|
||||||
|
const hours = Math.floor(uptime / 3600);
|
||||||
|
const mins = Math.floor((uptime % 3600) / 60);
|
||||||
|
const secs = uptime % 60;
|
||||||
|
printLine(`up ${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}, 1 user, load average: 0.00, 0.00, 0.00`);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'clear':
|
||||||
|
if (outputRef.current) outputRef.current.innerHTML = "";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'history':
|
||||||
|
commandHistory.forEach((c, i) => printLine(` ${i + 1} ${c}`));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'exit':
|
||||||
|
window.location.href = '/';
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Easter eggs
|
||||||
|
case 'hawkins':
|
||||||
|
case '011':
|
||||||
|
case 'eleven':
|
||||||
|
case 'upsidedown':
|
||||||
|
if (hawkinsActive) {
|
||||||
|
printLine("Closing dimensional gate...", 'log-warn');
|
||||||
|
setHawkinsActive(false);
|
||||||
|
if (currentMusic) {
|
||||||
|
currentMusic.stop?.();
|
||||||
|
setCurrentMusic(null);
|
||||||
|
}
|
||||||
|
document.body.classList.remove('hawkins');
|
||||||
|
} else {
|
||||||
|
setHawkinsActive(true);
|
||||||
|
document.body.classList.add('hawkins');
|
||||||
|
printLine("Entering the Upside Down...", 'log-err');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'fsociety':
|
||||||
|
case 'elliot':
|
||||||
|
case 'bonsoir':
|
||||||
|
if (fsocietyActive) {
|
||||||
|
setFsocietyActive(false);
|
||||||
|
setSystemFrozen(false);
|
||||||
|
if (inputContainerRef.current) inputContainerRef.current.style.display = 'flex';
|
||||||
|
if (currentMusic) {
|
||||||
|
currentMusic.stop?.();
|
||||||
|
setCurrentMusic(null);
|
||||||
|
}
|
||||||
|
document.body.classList.remove('fsociety-boot');
|
||||||
|
} else {
|
||||||
|
setFsocietyActive(true);
|
||||||
|
setSystemFrozen(true);
|
||||||
|
if (inputContainerRef.current) inputContainerRef.current.style.display = 'none';
|
||||||
|
if (outputRef.current) outputRef.current.innerHTML = "";
|
||||||
|
document.body.classList.add('fsociety-boot');
|
||||||
|
printLine("$ ./fsociety.sh", 'log-k');
|
||||||
|
await sleep(250);
|
||||||
|
printLine("[*] Initializing breach protocol...", 'log-warn');
|
||||||
|
await sleep(500);
|
||||||
|
printLine("Hello friend.", 'log-k');
|
||||||
|
await sleep(1000);
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '42':
|
||||||
|
case 'answer':
|
||||||
|
printLine("Initializing Deep Thought...", 'log-sys');
|
||||||
|
await sleep(600);
|
||||||
|
printLine("Deep Thought: The Answer to the Ultimate Question of Life, the Universe, and Everything is...", 'log-k');
|
||||||
|
await sleep(1500);
|
||||||
|
printLine("42", 'log-k');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'rm':
|
||||||
|
if (args[1] === '-rf' && args[2] === '/') {
|
||||||
|
setSystemFrozen(true);
|
||||||
|
if (inputContainerRef.current) inputContainerRef.current.style.display = 'none';
|
||||||
|
printLine("CRITICAL: Attempting to delete root filesystem...", 'log-err');
|
||||||
|
await sleep(500);
|
||||||
|
printLine("KERNEL PANIC: Unable to handle kernel paging request", 'pulse-red');
|
||||||
|
await sleep(2000);
|
||||||
|
location.reload();
|
||||||
|
} else if (args[1]) {
|
||||||
|
printLine("rm: cannot remove: Read-only file system", 'log-err');
|
||||||
|
} else {
|
||||||
|
printLine("Usage: rm [file]");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printLine(`bash: ${cmd}: command not found`, 'log-err');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputRef.current && !systemFrozen) {
|
||||||
|
setTimeout(() => inputRef.current?.focus(), 50);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCurrentPath(fileSystem.home.children!.guest);
|
||||||
|
|
||||||
|
const initAudio = () => {
|
||||||
|
if (!audioCtxRef.current) {
|
||||||
|
try {
|
||||||
|
audioCtxRef.current = new (window.AudioContext || (window as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext)();
|
||||||
|
} catch {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('keydown', initAudio, { once: true });
|
||||||
|
|
||||||
|
const bootMessages = [
|
||||||
|
{ t: "[ 0.000000] Linux version 4.0.4-void (torvalds@kernel.org) (gcc version 9.4.0)", d: 200 },
|
||||||
|
{ t: "[ 0.050000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.0.4 root=UUID=dead-beef ro quiet splash", d: 150 },
|
||||||
|
{ t: "[ 0.100000] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'", d: 100 },
|
||||||
|
{ t: "[ 0.150000] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'", d: 100 },
|
||||||
|
{ t: "[ 0.200000] BIOS-provided physical RAM map:", d: 200 },
|
||||||
|
{ t: "[ 0.250000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable", d: 150 },
|
||||||
|
{ t: "[ 0.300000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved", d: 150 },
|
||||||
|
{ t: "[ 0.400000] Memory: 64K/1048576K available (404K kernel code, 404K rwdata, 404K rodata)", d: 300 },
|
||||||
|
{ t: "[ 0.600000] Calibrating delay loop... 800.00 BogoMIPS (lpj=400000)", d: 200 },
|
||||||
|
{ t: "[ 0.800000] Security Framework initialized", d: 200 },
|
||||||
|
{ t: "[ 1.000000] Tainted kernel: M (Module has bad license) P (Proprietary module loaded)", type: 'log-warn', d: 400 },
|
||||||
|
{ t: "[ 1.200000] Linus Torvalds: 'I'm not angry, I'm just disappointed in this boot process.'", d: 600 },
|
||||||
|
{ t: "[ 1.500000] Torvalds: 'This code is garbage. Who wrote this?'", d: 500 },
|
||||||
|
{ t: "[ 2.000000] [ OK ] Started udev Kernel Device Manager.", d: 200 },
|
||||||
|
{ t: "[ 2.200000] [ OK ] Mounted /dev/sda1 (Root Filesystem).", d: 200 },
|
||||||
|
{ t: "[ 2.400000] [TIME] Timed out waiting for device /dev/reality.", type: 'log-warn', d: 600 },
|
||||||
|
{ t: "[ 2.800000] [DEPEND] Dependency failed for Local File Systems.", type: 'log-err', d: 300 },
|
||||||
|
{ t: "[ 3.000000] [FAILED] Failed to start The Internet.", type: 'log-err', d: 400 },
|
||||||
|
{ t: "[ 3.200000] [FAILED] Failed to start Meaning of Life service.", type: 'log-err', d: 400 },
|
||||||
|
{ t: "[ 3.500000] Welcome to emergency mode. Type 'help' for available commands.", d: 200 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const runBoot = async () => {
|
||||||
|
for (const msg of bootMessages) {
|
||||||
|
printLine(msg.t, msg.type);
|
||||||
|
await sleep(msg.d);
|
||||||
|
}
|
||||||
|
if (inputContainerRef.current) {
|
||||||
|
inputContainerRef.current.style.display = 'flex';
|
||||||
|
}
|
||||||
|
if (inputRef.current) {
|
||||||
|
setTimeout(() => inputRef.current?.focus(), 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (outputRef.current) {
|
||||||
|
runBoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (currentMusic) {
|
||||||
|
currentMusic.stop?.();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<style dangerouslySetInnerHTML={{ __html: `
|
||||||
|
:root {
|
||||||
|
--bg-color: #020202;
|
||||||
|
--phosphor: #33ff00;
|
||||||
|
--phosphor-sec: #008f11;
|
||||||
|
--alert: #ff3333;
|
||||||
|
--font: 'Courier New', Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--bg-color) !important;
|
||||||
|
margin: 0;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
font-family: var(--font) !important;
|
||||||
|
color: var(--phosphor) !important;
|
||||||
|
user-select: none;
|
||||||
|
cursor: default;
|
||||||
|
transition: filter 0.5s, transform 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crt-wrap {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
padding: 30px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: radial-gradient(circle at center, #111 0%, #000 100%);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crt-wrap::before {
|
||||||
|
content: " ";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%),
|
||||||
|
linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));
|
||||||
|
background-size: 100% 4px, 3px 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glow {
|
||||||
|
text-shadow: 0 0 2px var(--phosphor-sec), 0 0 8px var(--phosphor);
|
||||||
|
}
|
||||||
|
|
||||||
|
#terminal {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: auto;
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
#output {
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: var(--phosphor);
|
||||||
|
}
|
||||||
|
|
||||||
|
#output::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-line {
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
border-top: 1px solid #333;
|
||||||
|
padding-top: 10px;
|
||||||
|
min-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt {
|
||||||
|
margin-right: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: var(--phosphor);
|
||||||
|
}
|
||||||
|
|
||||||
|
#cmd-input {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
flex-grow: 1;
|
||||||
|
outline: none;
|
||||||
|
text-transform: lowercase;
|
||||||
|
caret-color: var(--phosphor);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.hawkins {
|
||||||
|
--phosphor: #ff3333;
|
||||||
|
--phosphor-sec: #800000;
|
||||||
|
filter: contrast(1.6) sepia(1) hue-rotate(-30deg) saturate(4) brightness(0.6);
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.fsociety-boot {
|
||||||
|
background: #000;
|
||||||
|
filter: contrast(1.3) brightness(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.meltdown {
|
||||||
|
animation: violent-shake 0.15s infinite, color-shift 0.8s infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes violent-shake {
|
||||||
|
0% { transform: translate(0, 0) rotate(0deg); }
|
||||||
|
25% { transform: translate(-8px, 5px) rotate(-1deg); }
|
||||||
|
50% { transform: translate(8px, -5px) rotate(1deg) skew(3deg); }
|
||||||
|
75% { transform: translate(-8px, -5px) rotate(-1deg); }
|
||||||
|
100% { transform: translate(8px, 5px) rotate(1deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes color-shift {
|
||||||
|
0% { filter: hue-rotate(0deg) saturate(1); }
|
||||||
|
25% { filter: hue-rotate(90deg) saturate(2) brightness(1.2); }
|
||||||
|
50% { filter: hue-rotate(180deg) saturate(3) brightness(0.8); }
|
||||||
|
75% { filter: hue-rotate(270deg) saturate(2) brightness(1.1); }
|
||||||
|
100% { filter: hue-rotate(360deg) saturate(1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.pulse-red {
|
||||||
|
animation: pulse-red 1s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-red {
|
||||||
|
0%, 100% { color: var(--alert); text-shadow: 0 0 10px red; }
|
||||||
|
50% { color: #ff6666; text-shadow: 0 0 20px red, 0 0 30px red; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-dir { color: #5e91ff; font-weight: bold; }
|
||||||
|
.is-exe { color: var(--phosphor); font-weight: bold; }
|
||||||
|
`}} />
|
||||||
|
<div className="crt-wrap glow">
|
||||||
|
<div id="terminal">
|
||||||
|
<div id="output" ref={outputRef}></div>
|
||||||
|
<div className="input-line" id="input-container" ref={inputContainerRef} style={{ display: 'none' }}>
|
||||||
|
<span className="prompt">guest@404:~$</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="cmd-input"
|
||||||
|
ref={inputRef}
|
||||||
|
autoComplete="off"
|
||||||
|
spellCheck={false}
|
||||||
|
tabIndex={0}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
const cmd = (e.target as HTMLInputElement).value.trim();
|
||||||
|
(e.target as HTMLInputElement).value = '';
|
||||||
|
runCmd(cmd);
|
||||||
|
} else if (e.key === 'ArrowUp' && historyIndex > 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
const newIndex = historyIndex - 1;
|
||||||
|
setHistoryIndex(newIndex);
|
||||||
|
(e.target as HTMLInputElement).value = commandHistory[newIndex] || '';
|
||||||
|
} else if (e.key === 'ArrowDown' && historyIndex < commandHistory.length - 1) {
|
||||||
|
e.preventDefault();
|
||||||
|
const newIndex = historyIndex + 1;
|
||||||
|
setHistoryIndex(newIndex);
|
||||||
|
(e.target as HTMLInputElement).value = commandHistory[newIndex] || '';
|
||||||
|
} else if (e.key === 'ArrowDown') {
|
||||||
|
e.preventDefault();
|
||||||
|
setHistoryIndex(commandHistory.length);
|
||||||
|
(e.target as HTMLInputElement).value = '';
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
playSynth('key');
|
||||||
|
} catch {
|
||||||
|
// Ignore audio errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,22 +1,5 @@
|
|||||||
import Link from "next/link";
|
import KernelPanic404 from './components/KernelPanic404';
|
||||||
|
|
||||||
export default function NotFound() {
|
export default function NotFound() {
|
||||||
return (
|
return <KernelPanic404 />;
|
||||||
<div className="flex items-center justify-center h-screen bg-gray-100 dark:bg-gray-800">
|
|
||||||
<div className="text-center p-10 bg-white dark:bg-gray-700 rounded shadow-md">
|
|
||||||
<h1 className="text-6xl font-bold text-gray-800 dark:text-white">
|
|
||||||
404
|
|
||||||
</h1>
|
|
||||||
<p className="mt-4 text-xl text-gray-600 dark:text-gray-300">
|
|
||||||
Oops! The page you're looking for doesn't exist.
|
|
||||||
</p>
|
|
||||||
<Link
|
|
||||||
href="/"
|
|
||||||
className="mt-6 inline-block text-blue-500 hover:underline"
|
|
||||||
>
|
|
||||||
Go Back Home
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user