1873 lines
56 KiB
TypeScript
1873 lines
56 KiB
TypeScript
"use client";
|
||
|
||
import { useEffect, useRef } from "react";
|
||
|
||
export default function KernelPanic404() {
|
||
const outputRef = useRef<HTMLDivElement>(null);
|
||
const inputRef = useRef<HTMLInputElement>(null);
|
||
const inputContainerRef = useRef<HTMLDivElement>(null);
|
||
const overlayRef = useRef<HTMLDivElement>(null);
|
||
const bodyRef = useRef<HTMLDivElement>(null); // We'll use a wrapper div instead of document.body for some effects if possible, but strict effects might need body.
|
||
|
||
useEffect(() => {
|
||
/* --- SYSTEM CORE --- */
|
||
const output = outputRef.current;
|
||
const input = inputRef.current;
|
||
const inputContainer = inputContainerRef.current;
|
||
const overlay = overlayRef.current;
|
||
|
||
// We need to access the actual body for some full-screen effects
|
||
const body = document.body;
|
||
|
||
if (!output || !input || !inputContainer || !overlay) return;
|
||
|
||
let audioCtx: AudioContext | null = null;
|
||
let systemFrozen = false;
|
||
let currentMusic: any = null;
|
||
let hawkinsActive = false;
|
||
let fsocietyActive = false;
|
||
|
||
// Timers storage to clear on unmount
|
||
const timers: (NodeJS.Timeout | number)[] = [];
|
||
const interval = (fn: Function, ms: number) => {
|
||
const id = setInterval(fn, ms);
|
||
timers.push(id);
|
||
return id;
|
||
};
|
||
const timeout = (fn: Function, ms: number) => {
|
||
const id = setTimeout(fn, ms);
|
||
timers.push(id);
|
||
return id;
|
||
};
|
||
|
||
// Initialize Audio on first interaction
|
||
function initAudio() {
|
||
if (!audioCtx) {
|
||
const AudioContextClass =
|
||
window.AudioContext || (window as any).webkitAudioContext;
|
||
if (AudioContextClass) {
|
||
audioCtx = new AudioContextClass();
|
||
}
|
||
}
|
||
}
|
||
window.addEventListener("keydown", initAudio, { once: true });
|
||
window.addEventListener("click", initAudio, { once: true });
|
||
|
||
/* --- MUSIC SYNTHESIS ENGINE --- */
|
||
|
||
function makeDistortionCurve(amount: number) {
|
||
const samples = 44100;
|
||
const curve = new Float32Array(samples);
|
||
const deg = Math.PI / 180;
|
||
for (let i = 0; i < samples; i++) {
|
||
const x = (i * 2) / samples - 1;
|
||
curve[i] =
|
||
((3 + amount) * x * 20 * deg) / (Math.PI + amount * Math.abs(x));
|
||
}
|
||
return curve;
|
||
}
|
||
|
||
function playStrangerThingsTheme() {
|
||
if (!audioCtx) return null;
|
||
const masterGain = audioCtx.createGain();
|
||
masterGain.gain.value = 0.4;
|
||
|
||
const distortion = audioCtx.createWaveShaper();
|
||
distortion.curve = makeDistortionCurve(6);
|
||
distortion.oversample = "4x";
|
||
masterGain.connect(distortion);
|
||
distortion.connect(audioCtx.destination);
|
||
|
||
function playNote(
|
||
freq: number,
|
||
startTime: number,
|
||
duration: number,
|
||
type: OscillatorType = "sawtooth",
|
||
volume = 0.4,
|
||
) {
|
||
if (!audioCtx) return;
|
||
const osc = audioCtx.createOscillator();
|
||
const gain = audioCtx.createGain();
|
||
osc.type = type;
|
||
osc.frequency.setValueAtTime(freq, audioCtx.currentTime + startTime);
|
||
gain.gain.setValueAtTime(0, audioCtx.currentTime + startTime);
|
||
gain.gain.linearRampToValueAtTime(
|
||
volume,
|
||
audioCtx.currentTime + startTime + 0.05,
|
||
);
|
||
gain.gain.exponentialRampToValueAtTime(
|
||
0.01,
|
||
audioCtx.currentTime + startTime + duration,
|
||
);
|
||
osc.connect(gain);
|
||
gain.connect(masterGain);
|
||
osc.start(audioCtx.currentTime + startTime);
|
||
osc.stop(audioCtx.currentTime + startTime + duration);
|
||
}
|
||
|
||
function playMelody(startTime: number) {
|
||
const t = startTime;
|
||
const notes = [
|
||
{ f: 196.0, t: 0.0, d: 0.45 }, // G
|
||
{ f: 233.08, t: 0.5, d: 0.45 }, // Bb
|
||
{ f: 174.61, t: 1.0, d: 0.45 }, // F
|
||
{ f: 233.08, t: 1.5, d: 0.45 }, // Bb
|
||
];
|
||
notes.forEach((n) => {
|
||
playNote(n.f, t + n.t, n.d, "sawtooth", 0.5);
|
||
});
|
||
}
|
||
|
||
function playBass(startTime: number) {
|
||
const t = startTime;
|
||
const notes = [
|
||
{ f: 98.0, t: 0.0, d: 1.9 }, // G (low)
|
||
{ f: 116.54, t: 2.0, d: 1.9 }, // Bb (low)
|
||
{ f: 77.78, t: 4.0, d: 1.9 }, // Eb (low)
|
||
{ f: 87.31, t: 6.0, d: 1.9 }, // F (low)
|
||
];
|
||
notes.forEach((n) => {
|
||
playNote(n.f, t + n.t, n.d, "square", 0.35);
|
||
});
|
||
}
|
||
|
||
function playBass2(startTime: number) {
|
||
const t = startTime;
|
||
const notes = [
|
||
{ f: 98.0, t: 0.0, d: 0.9 }, // G
|
||
{ f: 116.54, t: 1.0, d: 0.9 }, // Bb
|
||
{ f: 87.31, t: 2.0, d: 0.9 }, // F
|
||
{ f: 116.54, t: 3.0, d: 0.9 }, // Bb
|
||
];
|
||
notes.forEach((n) => {
|
||
playNote(n.f, t + n.t, n.d, "square", 0.3);
|
||
});
|
||
}
|
||
|
||
playMelody(0);
|
||
playBass(0);
|
||
|
||
timeout(() => {
|
||
playBass2(0);
|
||
}, 16500);
|
||
|
||
const melodyInterval = interval(() => {
|
||
playMelody(0);
|
||
}, 2000);
|
||
|
||
const bassInterval = interval(() => {
|
||
playBass(0);
|
||
}, 8000);
|
||
|
||
const bass2Interval = interval(() => {
|
||
playBass2(0);
|
||
}, 4000);
|
||
|
||
return {
|
||
stop: () => {
|
||
clearInterval(melodyInterval);
|
||
clearInterval(bassInterval);
|
||
clearInterval(bass2Interval);
|
||
masterGain.disconnect();
|
||
},
|
||
};
|
||
}
|
||
|
||
function playMrRobotTheme() {
|
||
if (!audioCtx) return null;
|
||
const masterGain = audioCtx.createGain();
|
||
masterGain.gain.value = 0.3;
|
||
|
||
const distortion = audioCtx.createWaveShaper();
|
||
distortion.curve = makeDistortionCurve(50);
|
||
distortion.oversample = "4x";
|
||
masterGain.connect(distortion);
|
||
distortion.connect(audioCtx.destination);
|
||
|
||
const bass1 = audioCtx.createOscillator();
|
||
const bass1Gain = audioCtx.createGain();
|
||
bass1.type = "sawtooth";
|
||
bass1.frequency.setValueAtTime(41.2, audioCtx.currentTime);
|
||
bass1Gain.gain.setValueAtTime(0.5, audioCtx.currentTime);
|
||
bass1.connect(bass1Gain);
|
||
bass1Gain.connect(masterGain);
|
||
bass1.start();
|
||
|
||
const bass2 = audioCtx.createOscillator();
|
||
const bass2Gain = audioCtx.createGain();
|
||
bass2.type = "square";
|
||
bass2.frequency.setValueAtTime(40.5, audioCtx.currentTime);
|
||
bass2Gain.gain.setValueAtTime(0.3, audioCtx.currentTime);
|
||
bass2.connect(bass2Gain);
|
||
bass2Gain.connect(masterGain);
|
||
bass2.start();
|
||
|
||
const deepPulseInterval = interval(() => {
|
||
if (!audioCtx) return;
|
||
const osc = audioCtx.createOscillator();
|
||
const gain = audioCtx.createGain();
|
||
osc.type = "sawtooth";
|
||
const deepNotes = [55, 65, 73, 82, 98];
|
||
osc.frequency.setValueAtTime(
|
||
deepNotes[Math.floor(Math.random() * deepNotes.length)],
|
||
audioCtx.currentTime,
|
||
);
|
||
gain.gain.setValueAtTime(0.2, audioCtx.currentTime);
|
||
gain.gain.exponentialRampToValueAtTime(
|
||
0.001,
|
||
audioCtx.currentTime + 0.2,
|
||
);
|
||
osc.connect(gain);
|
||
gain.connect(masterGain);
|
||
osc.start();
|
||
osc.stop(audioCtx.currentTime + 0.2);
|
||
}, 400);
|
||
|
||
const rumbleInterval = interval(() => {
|
||
if (!audioCtx) return;
|
||
const osc = audioCtx.createOscillator();
|
||
const gain = audioCtx.createGain();
|
||
osc.type = "sawtooth";
|
||
osc.frequency.setValueAtTime(
|
||
30 + Math.random() * 10,
|
||
audioCtx.currentTime,
|
||
);
|
||
gain.gain.setValueAtTime(0.2, audioCtx.currentTime);
|
||
gain.gain.exponentialRampToValueAtTime(
|
||
0.001,
|
||
audioCtx.currentTime + 0.3,
|
||
);
|
||
osc.connect(gain);
|
||
gain.connect(masterGain);
|
||
osc.start();
|
||
osc.stop(audioCtx.currentTime + 0.3);
|
||
}, 2000);
|
||
|
||
return {
|
||
stop: () => {
|
||
bass1.stop();
|
||
bass2.stop();
|
||
clearInterval(deepPulseInterval);
|
||
clearInterval(rumbleInterval);
|
||
masterGain.disconnect();
|
||
},
|
||
};
|
||
}
|
||
|
||
function playHitchhikersTheme() {
|
||
if (!audioCtx) return null;
|
||
const masterGain = audioCtx.createGain();
|
||
masterGain.gain.value = 0.35;
|
||
|
||
const delay = audioCtx.createDelay(0.5);
|
||
delay.delayTime.setValueAtTime(0.15, audioCtx.currentTime);
|
||
const delayGain = audioCtx.createGain();
|
||
delayGain.gain.value = 0.3;
|
||
masterGain.connect(delay);
|
||
delay.connect(delayGain);
|
||
delayGain.connect(masterGain);
|
||
masterGain.connect(audioCtx.destination);
|
||
|
||
function playNote(
|
||
freq: number,
|
||
startTime: number,
|
||
duration: number,
|
||
type: OscillatorType = "sine",
|
||
volume = 0.4,
|
||
) {
|
||
if (!audioCtx) return;
|
||
const osc = audioCtx.createOscillator();
|
||
const gain = audioCtx.createGain();
|
||
osc.type = type;
|
||
osc.frequency.setValueAtTime(freq, audioCtx.currentTime + startTime);
|
||
gain.gain.setValueAtTime(0, audioCtx.currentTime + startTime);
|
||
gain.gain.linearRampToValueAtTime(
|
||
volume,
|
||
audioCtx.currentTime + startTime + 0.08,
|
||
);
|
||
gain.gain.exponentialRampToValueAtTime(
|
||
0.01,
|
||
audioCtx.currentTime + startTime + duration,
|
||
);
|
||
osc.connect(gain);
|
||
gain.connect(masterGain);
|
||
osc.start(audioCtx.currentTime + startTime);
|
||
osc.stop(audioCtx.currentTime + startTime + duration);
|
||
}
|
||
|
||
function playMelody(startTime: number) {
|
||
const t = startTime;
|
||
const melody = [
|
||
{ f: 523.25, t: 0.0, d: 0.4 }, // C
|
||
{ f: 587.33, t: 0.4, d: 0.4 }, // D
|
||
{ f: 659.25, t: 0.8, d: 0.4 }, // E
|
||
{ f: 698.46, t: 1.2, d: 0.4 }, // F
|
||
{ f: 783.99, t: 1.6, d: 0.8 }, // G
|
||
{ f: 698.46, t: 2.4, d: 0.4 }, // F
|
||
{ f: 659.25, t: 2.8, d: 0.4 }, // E
|
||
{ f: 587.33, t: 3.2, d: 0.4 }, // D
|
||
{ f: 523.25, t: 3.6, d: 0.8 }, // C
|
||
];
|
||
melody.forEach((n) => playNote(n.f, t + n.t, n.d, "sine", 0.5));
|
||
}
|
||
|
||
function playHarmony(startTime: number) {
|
||
const t = startTime;
|
||
const harmony = [
|
||
{ f: 783.99, t: 0.0, d: 0.4 }, // G
|
||
{ f: 880.0, t: 0.4, d: 0.4 }, // A
|
||
{ f: 987.77, t: 0.8, d: 0.4 }, // B
|
||
{ f: 1046.5, t: 1.2, d: 0.4 }, // C
|
||
{ f: 1174.66, t: 1.6, d: 0.8 }, // D
|
||
{ f: 1046.5, t: 2.4, d: 0.4 }, // C
|
||
{ f: 987.77, t: 2.8, d: 0.4 }, // B
|
||
{ f: 880.0, t: 3.2, d: 0.4 }, // A
|
||
{ f: 783.99, t: 3.6, d: 0.8 }, // G
|
||
];
|
||
harmony.forEach((n) => playNote(n.f, t + n.t, n.d, "triangle", 0.25));
|
||
}
|
||
|
||
function playBass(startTime: number) {
|
||
const t = startTime;
|
||
const bass = [
|
||
{ f: 130.81, t: 0.0, d: 0.8 }, // C (low)
|
||
{ f: 146.83, t: 0.8, d: 0.8 }, // D
|
||
{ f: 164.81, t: 1.6, d: 0.8 }, // E
|
||
{ f: 146.83, t: 2.4, d: 0.8 }, // D
|
||
{ f: 130.81, t: 3.2, d: 1.2 }, // C
|
||
];
|
||
bass.forEach((n) => playNote(n.f, t + n.t, n.d, "square", 0.3));
|
||
}
|
||
|
||
function playPad(startTime: number) {
|
||
const t = startTime;
|
||
const padNotes = [
|
||
{ f: 261.63, t: 0.0, d: 4.4 }, // C (middle, held)
|
||
{ f: 329.63, t: 0.0, d: 4.4 }, // E (held)
|
||
{ f: 392.0, t: 0.0, d: 4.4 }, // G (held)
|
||
];
|
||
padNotes.forEach((n) => playNote(n.f, t + n.t, n.d, "sine", 0.15));
|
||
}
|
||
|
||
playMelody(0);
|
||
playHarmony(0);
|
||
playBass(0);
|
||
playPad(0);
|
||
|
||
const loopInterval = interval(() => {
|
||
playMelody(0);
|
||
playHarmony(0);
|
||
playBass(0);
|
||
playPad(0);
|
||
}, 4400);
|
||
|
||
return {
|
||
stop: () => {
|
||
clearInterval(loopInterval);
|
||
masterGain.disconnect();
|
||
},
|
||
};
|
||
}
|
||
|
||
function playSynth(type: string) {
|
||
try {
|
||
if (!audioCtx || systemFrozen) return;
|
||
const t = audioCtx.currentTime;
|
||
const osc = audioCtx.createOscillator();
|
||
const gain = audioCtx.createGain();
|
||
osc.connect(gain);
|
||
gain.connect(audioCtx.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 === "scare") {
|
||
osc.type = "sawtooth";
|
||
osc.frequency.setValueAtTime(40, t);
|
||
gain.gain.setValueAtTime(0.6, t);
|
||
gain.gain.exponentialRampToValueAtTime(0.01, t + 1.0);
|
||
|
||
const osc2 = audioCtx.createOscillator();
|
||
osc2.type = "sawtooth";
|
||
osc2.frequency.setValueAtTime(45, t);
|
||
const gain2 = audioCtx.createGain();
|
||
osc2.connect(gain2);
|
||
gain2.connect(audioCtx.destination);
|
||
gain2.gain.setValueAtTime(0.5, t);
|
||
gain2.gain.exponentialRampToValueAtTime(0.01, t + 1.0);
|
||
|
||
osc.start();
|
||
osc2.start();
|
||
osc.stop(t + 1.0);
|
||
osc2.stop(t + 1.0);
|
||
} else if (type === "melt") {
|
||
const bufferSize = audioCtx.sampleRate * 0.8;
|
||
const buffer = audioCtx.createBuffer(
|
||
1,
|
||
bufferSize,
|
||
audioCtx.sampleRate,
|
||
);
|
||
const data = buffer.getChannelData(0);
|
||
for (let i = 0; i < bufferSize; i++) {
|
||
data[i] = (Math.random() * 2 - 1) * 0.5;
|
||
}
|
||
const noise = audioCtx.createBufferSource();
|
||
noise.buffer = buffer;
|
||
const filter = audioCtx.createBiquadFilter();
|
||
filter.type = "bandpass";
|
||
filter.frequency.value = 2000;
|
||
noise.connect(filter);
|
||
filter.connect(gain);
|
||
gain.gain.setValueAtTime(0.3, t);
|
||
gain.gain.exponentialRampToValueAtTime(0.001, t + 0.8);
|
||
noise.start();
|
||
} 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 (err) {
|
||
console.log("Audio error (non-critical):", err);
|
||
}
|
||
}
|
||
|
||
/* --- FILE SYSTEM --- */
|
||
const fileSystem: any = {
|
||
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: {},
|
||
},
|
||
};
|
||
// Add root reference
|
||
fileSystem.root = {
|
||
type: "dir",
|
||
children: {
|
||
home: fileSystem.home,
|
||
var: fileSystem.var,
|
||
etc: fileSystem.etc,
|
||
bin: fileSystem.bin,
|
||
tmp: fileSystem.tmp,
|
||
},
|
||
};
|
||
|
||
let currentPath = fileSystem.home.children.guest;
|
||
let pathStr = "~";
|
||
let commandHistory: string[] = [];
|
||
let historyIndex = -1;
|
||
|
||
/* --- UTILS --- */
|
||
function printLine(text: string, type?: string) {
|
||
if (!output) 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 = "var(--alert)";
|
||
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");
|
||
if (type === "fsociety-mask") d.classList.add("fsociety-mask");
|
||
if (type === "memory-error") d.classList.add("memory-error");
|
||
if (type === "kernel-panic") d.classList.add("kernel-panic");
|
||
output.appendChild(d);
|
||
output.scrollTop = output.scrollHeight;
|
||
}
|
||
|
||
function sleep(ms: number) {
|
||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||
}
|
||
|
||
/* --- BOOT SEQUENCE --- */
|
||
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,
|
||
},
|
||
];
|
||
|
||
async function runBoot() {
|
||
// Clear initial output
|
||
output!.innerHTML = "";
|
||
|
||
for (let msg of bootMessages) {
|
||
printLine(msg.t, msg.type);
|
||
await sleep(msg.d);
|
||
}
|
||
|
||
if (inputContainer) inputContainer.style.display = "flex";
|
||
setTimeout(() => {
|
||
if (input) input.focus();
|
||
}, 100);
|
||
}
|
||
|
||
// Start boot sequence
|
||
runBoot();
|
||
|
||
/* --- AUTOCOMPLETE --- */
|
||
const commands = [
|
||
"help",
|
||
"ls",
|
||
"cd",
|
||
"cat",
|
||
"grep",
|
||
"find",
|
||
"pwd",
|
||
"clear",
|
||
"whoami",
|
||
"uname",
|
||
"history",
|
||
"date",
|
||
"uptime",
|
||
"head",
|
||
"tail",
|
||
"wc",
|
||
"hostname",
|
||
"ping",
|
||
"ps",
|
||
"top",
|
||
"kill",
|
||
"exit",
|
||
"hawkins",
|
||
"011",
|
||
"eleven",
|
||
"upsidedown",
|
||
"fsociety",
|
||
"elliot",
|
||
"bonsoir",
|
||
"42",
|
||
"answer",
|
||
"rm",
|
||
];
|
||
|
||
function getCurrentDir() {
|
||
if (pathStr === "~" || pathStr.startsWith("~/")) {
|
||
return fileSystem.home.children.guest;
|
||
} else if (pathStr.startsWith("/var/log")) {
|
||
return fileSystem.var.children.log;
|
||
} else if (pathStr.startsWith("/var")) {
|
||
return fileSystem.var;
|
||
} else if (pathStr.startsWith("/etc")) {
|
||
return fileSystem.etc;
|
||
} else if (pathStr.startsWith("/bin")) {
|
||
return fileSystem.bin;
|
||
} else if (pathStr === "/") {
|
||
return fileSystem.root;
|
||
}
|
||
return currentPath;
|
||
}
|
||
|
||
function getAutocompleteSuggestions(text: string) {
|
||
const parts = text.trim().split(/\s+/);
|
||
const cmd = parts[0].toLowerCase();
|
||
const arg = parts[parts.length - 1] || "";
|
||
|
||
// Command autocomplete
|
||
if (parts.length === 1 && text.trim().length > 0) {
|
||
return commands.filter((c) => c.startsWith(cmd));
|
||
}
|
||
|
||
// File/directory autocomplete
|
||
if (
|
||
parts.length > 1 &&
|
||
(cmd === "cat" ||
|
||
cmd === "cd" ||
|
||
cmd === "grep" ||
|
||
cmd === "head" ||
|
||
cmd === "tail" ||
|
||
cmd === "wc" ||
|
||
cmd === "find" ||
|
||
cmd === "rm")
|
||
) {
|
||
const dir = getCurrentDir();
|
||
const items = Object.keys(dir.children || {}).filter((name) =>
|
||
name.toLowerCase().startsWith(arg.toLowerCase()),
|
||
);
|
||
|
||
// Also check for path-based completion
|
||
if (arg.includes("/")) {
|
||
const pathParts = arg.split("/");
|
||
const lastPart = pathParts.pop() || "";
|
||
// Simple case
|
||
return items.filter((name) =>
|
||
name.toLowerCase().startsWith(lastPart.toLowerCase()),
|
||
);
|
||
}
|
||
|
||
return items;
|
||
}
|
||
|
||
return [];
|
||
}
|
||
|
||
function handleTabComplete() {
|
||
if (!input) return;
|
||
|
||
const text = input.value;
|
||
const cursorPos = input.selectionStart || 0;
|
||
const textBeforeCursor = text.substring(0, cursorPos);
|
||
const parts = textBeforeCursor.trim().split(/\s+/);
|
||
|
||
const suggestions = getAutocompleteSuggestions(textBeforeCursor);
|
||
|
||
if (suggestions.length === 0) {
|
||
try {
|
||
playSynth("beep");
|
||
} catch (e) {}
|
||
return;
|
||
}
|
||
|
||
if (suggestions.length === 1) {
|
||
// Single match - complete it
|
||
const partIndex = parts.length - 1;
|
||
|
||
if (partIndex === 0) {
|
||
// Completing command
|
||
input.value = suggestions[0] + (text.endsWith(" ") ? "" : " ");
|
||
} else {
|
||
// Completing argument
|
||
const beforeArg = parts.slice(0, -1).join(" ") + " ";
|
||
const completion = suggestions[0];
|
||
const dir = getCurrentDir();
|
||
const item = dir.children[completion];
|
||
const suffix = item && item.type === "dir" ? "/" : " ";
|
||
input.value = beforeArg + completion + suffix;
|
||
}
|
||
input.setSelectionRange(input.value.length, input.value.length);
|
||
try {
|
||
playSynth("beep");
|
||
} catch (e) {}
|
||
} else {
|
||
// Multiple matches
|
||
printLine(`Possible completions: ${suggestions.join(" ")}`, "log-dim");
|
||
try {
|
||
playSynth("beep");
|
||
} catch (e) {}
|
||
}
|
||
}
|
||
|
||
/* --- COMMAND PROCESSOR --- */
|
||
async function runCmd() {
|
||
if (systemFrozen || !input) {
|
||
try {
|
||
playSynth("beep");
|
||
} catch (e) {}
|
||
return;
|
||
}
|
||
|
||
const cmdRaw = input.value.trim();
|
||
input.value = "";
|
||
|
||
if (!cmdRaw) {
|
||
printLine(`guest@404:${pathStr}$ `, "log-dim");
|
||
return;
|
||
}
|
||
|
||
commandHistory.push(cmdRaw);
|
||
historyIndex = commandHistory.length;
|
||
|
||
printLine(`guest@404:${pathStr}$ ${cmdRaw}`, "log-dim");
|
||
const args = cmdRaw.split(/\s+/);
|
||
const cmd = args[0].toLowerCase();
|
||
|
||
await sleep(100);
|
||
|
||
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");
|
||
|
||
let items = Object.keys(currentPath.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 = currentPath.children[a];
|
||
const itemB = currentPath.children[b];
|
||
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) => {
|
||
if (n === "." || n === "..") {
|
||
const date = new Date();
|
||
const month = date.toLocaleString("default", {
|
||
month: "short",
|
||
});
|
||
const day = date.getDate().toString().padStart(2, "0");
|
||
const time = date.toTimeString().substring(0, 5);
|
||
const dateStr = `${month} ${day} ${time}`;
|
||
printLine(
|
||
`drwxr-xr-x 2 guest guest 4096 ${dateStr} <span class='is-dir'>${n}/</span>`,
|
||
);
|
||
return;
|
||
}
|
||
|
||
const item = currentPath.children[n];
|
||
if (!item) return;
|
||
const isDir = item.type === "dir";
|
||
const isExe = item.type === "exe";
|
||
const perms = isDir
|
||
? "drwxr-xr-x"
|
||
: isExe
|
||
? "-rwxr-xr-x"
|
||
: "-rw-r--r--";
|
||
const links = isDir ? "2" : "1";
|
||
let size = "0";
|
||
if (item.content) size = item.content.length.toString();
|
||
else if (isDir) size = "4096";
|
||
size = size.padStart(8);
|
||
|
||
const date = new Date();
|
||
const month = date.toLocaleString("default", { month: "short" });
|
||
const day = date.getDate().toString().padStart(2, "0");
|
||
const time = date.toTimeString().substring(0, 5);
|
||
const dateStr = `${month} ${day} ${time}`;
|
||
|
||
let filename = n;
|
||
if (isDir) filename = `<span class='is-dir'>${n}/</span>`;
|
||
else if (isExe) filename = `<span class='is-exe'>${n}*</span>`;
|
||
|
||
printLine(
|
||
`${perms} ${links} guest guest ${size} ${dateStr} ${filename}`,
|
||
);
|
||
});
|
||
} else {
|
||
const formatted = items.map((n) => {
|
||
if (n === "." || n === "..")
|
||
return `<span class='is-dir'>${n}/</span>`;
|
||
const item = currentPath.children[n];
|
||
if (!item) return n;
|
||
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":
|
||
if (args[1]) {
|
||
const file = currentPath.children[args[1]];
|
||
if (file && file.type === "file") {
|
||
printLine(file.content);
|
||
} else {
|
||
printLine(`cat: ${args[1]}: No such file`, "log-err");
|
||
}
|
||
}
|
||
break;
|
||
|
||
case "cd":
|
||
if (!args[1]) {
|
||
currentPath = fileSystem.home.children.guest;
|
||
pathStr = "~";
|
||
} else if (args[1] === "..") {
|
||
if (pathStr === "/var/log") {
|
||
currentPath = fileSystem.var;
|
||
pathStr = "/var";
|
||
} else if (pathStr === "/var") {
|
||
currentPath = fileSystem.root;
|
||
pathStr = "/";
|
||
} else {
|
||
currentPath = fileSystem.home.children.guest;
|
||
pathStr = "~";
|
||
}
|
||
} else if (args[1] === "~" || args[1] === "/home/guest") {
|
||
currentPath = fileSystem.home.children.guest;
|
||
pathStr = "~";
|
||
} else if (args[1].startsWith("/var/log")) {
|
||
currentPath = fileSystem.var.children.log;
|
||
pathStr = "/var/log";
|
||
} else if (args[1].startsWith("/var")) {
|
||
currentPath = fileSystem.var;
|
||
pathStr = "/var";
|
||
} else if (args[1].startsWith("/etc")) {
|
||
currentPath = fileSystem.etc;
|
||
pathStr = "/etc";
|
||
} else if (args[1] === "/") {
|
||
currentPath = fileSystem.root;
|
||
pathStr = "/";
|
||
} else {
|
||
const subdir = currentPath.children[args[1]];
|
||
if (subdir && subdir.type === "dir") {
|
||
currentPath = subdir;
|
||
pathStr =
|
||
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 = currentPath.children[args[2]];
|
||
if (grepFile && grepFile.content) {
|
||
const lines = grepFile.content.split("\n");
|
||
lines.forEach((l: string) => {
|
||
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 "clear":
|
||
if (output) output.innerHTML = "";
|
||
break;
|
||
|
||
case "exit":
|
||
window.location.href = "/";
|
||
break;
|
||
|
||
case "hawkins":
|
||
case "011":
|
||
case "eleven":
|
||
case "upsidedown":
|
||
await triggerHawkins();
|
||
break;
|
||
|
||
case "fsociety":
|
||
case "elliot":
|
||
case "bonsoir":
|
||
await triggerFsociety();
|
||
break;
|
||
|
||
case "42":
|
||
case "answer":
|
||
await triggerDeepThought();
|
||
break;
|
||
|
||
case "rm":
|
||
if (args[1] === "-rf" && args[2] === "/") {
|
||
await initiateMeltdown();
|
||
} 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 (output) output.scrollTop = output.scrollHeight;
|
||
if (
|
||
!systemFrozen &&
|
||
inputContainer &&
|
||
inputContainer.style.display === "flex"
|
||
) {
|
||
setTimeout(() => input.focus(), 50);
|
||
}
|
||
}
|
||
|
||
/* --- EASTER EGGS --- */
|
||
async function triggerHawkins() {
|
||
if (hawkinsActive) {
|
||
printLine("Closing dimensional gate...", "log-warn");
|
||
await sleep(500);
|
||
if (currentMusic) {
|
||
currentMusic.stop();
|
||
currentMusic = null;
|
||
}
|
||
body.classList.remove("hawkins");
|
||
hawkinsActive = false;
|
||
printLine("Returned to normal reality.", "log-sys");
|
||
return;
|
||
}
|
||
|
||
hawkinsActive = true;
|
||
printLine("WARNING: Anomalous readings detected...", "log-warn");
|
||
await sleep(600);
|
||
printLine("Dimensional instability increasing...", "log-err");
|
||
await sleep(500);
|
||
|
||
body.style.filter = "hue-rotate(180deg) contrast(1.5)";
|
||
await sleep(200);
|
||
body.style.filter = "";
|
||
await sleep(200);
|
||
body.style.filter = "hue-rotate(180deg) contrast(1.5)";
|
||
await sleep(150);
|
||
|
||
printLine("CRITICAL: Breach imminent!", "pulse-red");
|
||
await sleep(400);
|
||
printLine("Entering the Upside Down...", "log-err");
|
||
await sleep(300);
|
||
|
||
if (currentMusic) {
|
||
currentMusic.stop();
|
||
currentMusic = null;
|
||
}
|
||
playSynth("scare");
|
||
currentMusic = playStrangerThingsTheme();
|
||
body.classList.add("hawkins");
|
||
|
||
const vecnaArt = `
|
||
████████████████████████████████
|
||
██ ██
|
||
██ ████ ████ ██
|
||
██ ██ ████ ██ ██
|
||
██ ██ ██ ██
|
||
██ ██ ██ ██ ██ ██
|
||
██ ██ ██ ██ ██ ██
|
||
██ ██ ██ ██
|
||
██ ██████████ ██
|
||
██ ██
|
||
██ ████████████████ ██
|
||
██ ██ ██ ██
|
||
██ ██ ██ ██
|
||
██ ██████████████ ██
|
||
██ ██
|
||
████████████████████████████████
|
||
`;
|
||
|
||
if (!overlay) return;
|
||
|
||
for (let i = 0; i < 3; i++) {
|
||
overlay.innerHTML = `<div class="ascii-art pulse-red" style="font-size:${10 + i * 2}px; transform: scale(${1.0 + i * 0.3});">${vecnaArt}</div>`;
|
||
overlay.style.display = "flex";
|
||
overlay.style.background = `rgba(255, 0, 0, ${0.3 + i * 0.2})`;
|
||
await sleep(200);
|
||
overlay.style.display = "none";
|
||
await sleep(100);
|
||
}
|
||
|
||
overlay.innerHTML = `<div class="ascii-art pulse-red" style="font-size:14px; transform: scale(1.5);">${vecnaArt}</div>`;
|
||
overlay.style.display = "flex";
|
||
overlay.style.background = "rgba(255, 0, 0, 0.7)";
|
||
await sleep(400);
|
||
overlay.style.display = "none";
|
||
overlay.innerHTML = "";
|
||
|
||
const sporeInterval = interval(() => {
|
||
const spore = document.createElement("div");
|
||
spore.className = "spore";
|
||
spore.style.left = Math.random() * 100 + "%";
|
||
spore.style.top = Math.random() * 100 + "%";
|
||
spore.style.opacity = "0.6";
|
||
body.appendChild(spore);
|
||
setTimeout(() => spore.remove(), 3000);
|
||
}, 300);
|
||
|
||
const glitchInterval = interval(() => {
|
||
if (!hawkinsActive) return;
|
||
body.style.filter = "hue-rotate(180deg) contrast(1.3) brightness(0.9)";
|
||
setTimeout(
|
||
() => {
|
||
body.style.filter = "";
|
||
},
|
||
100 + Math.random() * 200,
|
||
);
|
||
}, 2000);
|
||
|
||
printLine("", "log-dim");
|
||
printLine("████████████████████████████████████████", "pulse-red");
|
||
printLine("█ YOU ARE NOW IN THE UPSIDE DOWN █", "pulse-red");
|
||
printLine("████████████████████████████████████████", "pulse-red");
|
||
printLine("", "log-dim");
|
||
|
||
timeout(() => {
|
||
if (hawkinsActive) {
|
||
printLine("", "log-dim");
|
||
printLine("Dimensional gate closing automatically...", "log-warn");
|
||
triggerHawkins();
|
||
}
|
||
}, 30000);
|
||
}
|
||
|
||
async function triggerFsociety() {
|
||
if (fsocietyActive) {
|
||
printLine("Disconnecting from fsociety network...", "log-warn");
|
||
await sleep(500);
|
||
if (currentMusic) {
|
||
currentMusic.stop();
|
||
currentMusic = null;
|
||
}
|
||
body.classList.remove("fsociety-boot");
|
||
fsocietyActive = false;
|
||
systemFrozen = false;
|
||
if (inputContainer) inputContainer.style.display = "flex";
|
||
printLine("Connection terminated.", "log-sys");
|
||
return;
|
||
}
|
||
|
||
fsocietyActive = true;
|
||
systemFrozen = true;
|
||
if (inputContainer) inputContainer.style.display = "none";
|
||
if (output) output.innerHTML = "";
|
||
body.classList.add("fsociety-boot");
|
||
|
||
if (currentMusic) {
|
||
currentMusic.stop();
|
||
currentMusic = null;
|
||
}
|
||
currentMusic = playMrRobotTheme();
|
||
|
||
printLine("$ ./fsociety.sh", "log-k");
|
||
await sleep(250);
|
||
printLine("[*] Initializing breach protocol...", "log-warn");
|
||
await sleep(180);
|
||
printLine("[*] Scanning target: E-Corp mainframe", "log-warn");
|
||
await sleep(200);
|
||
printLine(
|
||
"[*] Exploiting CVE-2024-1337... 0x" +
|
||
Array.from({ length: 8 }, () =>
|
||
Math.floor(Math.random() * 16)
|
||
.toString(16)
|
||
.toUpperCase(),
|
||
).join(""),
|
||
"log-dim",
|
||
);
|
||
await sleep(180);
|
||
printLine("[*] Bypassing firewall...", "log-warn");
|
||
await sleep(180);
|
||
printLine("[*] Escalating privileges... root access granted", "log-warn");
|
||
await sleep(200);
|
||
printLine("[*] Injecting payload... success", "log-warn");
|
||
await sleep(180);
|
||
printLine("[*] Establishing backdoor...", "log-warn");
|
||
await sleep(200);
|
||
printLine("", "log-dim");
|
||
printLine(" ██ ██", "fsociety-mask");
|
||
printLine(" ██ ██ ██ ██", "fsociety-mask");
|
||
printLine(" ██ ████ ██", "fsociety-mask");
|
||
printLine(" ██ ██", "fsociety-mask");
|
||
printLine(" ██ ██ ██ ██", "fsociety-mask");
|
||
printLine(" ██ ██ ██ ██", "fsociety-mask");
|
||
printLine(" ██ ██████ ██", "fsociety-mask");
|
||
printLine(" ██ ██", "fsociety-mask");
|
||
printLine(" ██████████████", "fsociety-mask");
|
||
await sleep(400);
|
||
printLine("", "log-dim");
|
||
printLine("Hello friend.", "log-k");
|
||
await sleep(350);
|
||
printLine("Control is an illusion.", "log-k");
|
||
await sleep(350);
|
||
printLine("We are fsociety.", "log-k");
|
||
await sleep(350);
|
||
printLine("", "log-dim");
|
||
printLine(
|
||
">>> Accessing E-Corp database... [████████████] 100%",
|
||
"log-warn",
|
||
);
|
||
await sleep(280);
|
||
printLine(">>> Encrypting files... [████████████] 100%", "log-warn");
|
||
await sleep(280);
|
||
printLine(">>> Deleting debt records... [████████████] 100%", "log-warn");
|
||
await sleep(280);
|
||
printLine("", "log-dim");
|
||
printLine("Mission accomplished. The world is watching.", "log-k");
|
||
await sleep(400);
|
||
|
||
printLine("", "log-dim");
|
||
printLine(
|
||
"System compromised. Initiating emergency reboot...",
|
||
"log-err",
|
||
);
|
||
await sleep(1500);
|
||
|
||
if (currentMusic) {
|
||
currentMusic.stop();
|
||
currentMusic = null;
|
||
}
|
||
body.classList.remove("fsociety-boot");
|
||
fsocietyActive = false;
|
||
systemFrozen = false;
|
||
if (output) output.innerHTML = "";
|
||
await sleep(500);
|
||
printLine("Rebooting system...", "log-warn");
|
||
await sleep(800);
|
||
location.reload();
|
||
}
|
||
|
||
async function triggerDeepThought() {
|
||
printLine("Initializing Deep Thought...", "log-sys");
|
||
await sleep(600);
|
||
printLine("", "log-dim");
|
||
printLine("Deep Thought: Good morning.", "log-k");
|
||
await sleep(800);
|
||
printLine("", "log-dim");
|
||
printLine(
|
||
"Deep Thought: I am the second greatest computer in the Universe of Time and Space.",
|
||
"log-k",
|
||
);
|
||
await sleep(1000);
|
||
printLine(
|
||
"Deep Thought: The Answer to the Ultimate Question...?",
|
||
"log-k",
|
||
);
|
||
await sleep(1000);
|
||
|
||
if (currentMusic) {
|
||
currentMusic.stop();
|
||
currentMusic = null;
|
||
}
|
||
currentMusic = playHitchhikersTheme();
|
||
|
||
printLine("Deep Thought: Thinking...", "log-dim");
|
||
await sleep(2000);
|
||
printLine("Deep Thought: I have the answer.", "log-k");
|
||
await sleep(1000);
|
||
printLine("", "log-dim");
|
||
printLine("42", "log-k");
|
||
}
|
||
|
||
async function initiateMeltdown() {
|
||
systemFrozen = true;
|
||
if (inputContainer) inputContainer.style.display = "none";
|
||
if (currentMusic) {
|
||
currentMusic.stop();
|
||
currentMusic = null;
|
||
}
|
||
|
||
printLine("CRITICAL: Attempting to delete root filesystem...", "log-err");
|
||
await sleep(500);
|
||
printLine("WARNING: Memory corruption detected!", "log-warn");
|
||
await sleep(400);
|
||
playSynth("melt");
|
||
|
||
let corruptionCount = 0;
|
||
const corruptInterval = interval(() => {
|
||
if (!output) return;
|
||
const nodes = Array.from(output.childNodes) as HTMLElement[];
|
||
if (nodes.length > 0) {
|
||
const randomNode = nodes[Math.floor(Math.random() * nodes.length)];
|
||
if (randomNode.innerText && randomNode.innerText.length > 3) {
|
||
const chars = "¥§¶$@#%&XØ¥€©±×÷";
|
||
const glitchChar = chars[Math.floor(Math.random() * chars.length)];
|
||
randomNode.innerHTML = randomNode.innerHTML.replace(
|
||
/[a-zA-Z0-9]/,
|
||
`<span class="corrupted-text">${glitchChar}</span>`,
|
||
);
|
||
}
|
||
}
|
||
corruptionCount++;
|
||
if (corruptionCount === 45) {
|
||
clearInterval(corruptInterval);
|
||
body.classList.add("meltdown");
|
||
playSynth("melt");
|
||
setTimeout(() => {
|
||
body.classList.remove("meltdown");
|
||
location.reload();
|
||
}, 2000);
|
||
}
|
||
}, 80);
|
||
}
|
||
|
||
/* --- EVENT LISTENERS --- */
|
||
const handleKeydown = (e: KeyboardEvent) => {
|
||
// Handle input focus
|
||
if (
|
||
!systemFrozen &&
|
||
inputContainer &&
|
||
inputContainer.style.display === "flex" &&
|
||
document.activeElement !== input
|
||
) {
|
||
input?.focus();
|
||
}
|
||
|
||
if (e.key === "Tab") {
|
||
e.preventDefault();
|
||
handleTabComplete();
|
||
return;
|
||
}
|
||
|
||
try {
|
||
playSynth("key");
|
||
} catch (e) {}
|
||
|
||
if (e.key === "ArrowUp" && historyIndex > 0) {
|
||
historyIndex--;
|
||
if (input) input.value = commandHistory[historyIndex];
|
||
} else if (
|
||
e.key === "ArrowDown" &&
|
||
historyIndex < commandHistory.length - 1
|
||
) {
|
||
historyIndex++;
|
||
if (input) input.value = commandHistory[historyIndex];
|
||
} else if (e.key === "ArrowDown") {
|
||
historyIndex = commandHistory.length;
|
||
if (input) input.value = "";
|
||
} else if (e.key === "Enter") {
|
||
runCmd();
|
||
}
|
||
};
|
||
|
||
if (input) input.addEventListener("keydown", handleKeydown);
|
||
|
||
return () => {
|
||
timers.forEach((t) =>
|
||
typeof t === "number" ? clearInterval(t) : clearTimeout(t),
|
||
);
|
||
if (input) input.removeEventListener("keydown", handleKeydown);
|
||
if (currentMusic && currentMusic.stop) currentMusic.stop();
|
||
if (body) {
|
||
body.classList.remove("hawkins", "meltdown", "fsociety-boot");
|
||
body.style.filter = "";
|
||
}
|
||
};
|
||
}, []);
|
||
|
||
return (
|
||
<>
|
||
<style jsx global>{`
|
||
:root {
|
||
--bg-color: #020202;
|
||
--phosphor: #33ff00;
|
||
--phosphor-sec: #008f11;
|
||
--alert: #ff3333;
|
||
--font: "Courier New", Courier, monospace;
|
||
}
|
||
|
||
/* --- CRT EFFECTS --- */
|
||
.crt-wrap {
|
||
width: 100%;
|
||
height: 100vh;
|
||
padding: 30px;
|
||
box-sizing: border-box;
|
||
background: radial-gradient(circle at center, #111 0%, #000 100%);
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.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 --- */
|
||
#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);
|
||
}
|
||
|
||
/* --- OVERLAYS FOR EASTER EGGS --- */
|
||
#flash-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
z-index: 999;
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: rgba(255, 0, 0, 0.3);
|
||
mix-blend-mode: overlay;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.ascii-art {
|
||
font-size: 8px;
|
||
line-height: 8px;
|
||
white-space: pre;
|
||
text-align: center;
|
||
color: var(--alert);
|
||
font-weight: bold;
|
||
font-family: monospace;
|
||
}
|
||
|
||
/* --- HAWKINS / UPSIDE DOWN MODE --- */
|
||
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.hawkins .crt-wrap::after {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
opacity: 0.5;
|
||
z-index: 80;
|
||
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10' cy='20' r='1.5' fill='white' opacity='0.8'/%3E%3Ccircle cx='50' cy='80' r='1' fill='white' opacity='0.6'/%3E%3Ccircle cx='150' cy='30' r='1.5' fill='white' opacity='0.8'/%3E%3Ccircle cx='100' cy='150' r='1.2' fill='white' opacity='0.7'/%3E%3Ccircle cx='180' cy='100' r='1' fill='white' opacity='0.6'/%3E%3C/svg%3E");
|
||
animation: spores 15s linear infinite;
|
||
pointer-events: none;
|
||
}
|
||
|
||
@keyframes spores {
|
||
from {
|
||
background-position: 0 0;
|
||
}
|
||
to {
|
||
background-position: 200px 400px;
|
||
}
|
||
}
|
||
|
||
.spore {
|
||
position: fixed;
|
||
width: 4px;
|
||
height: 4px;
|
||
background: rgba(255, 0, 0, 0.6);
|
||
border-radius: 50%;
|
||
pointer-events: none;
|
||
z-index: 100;
|
||
animation: sporeFloat 3s ease-out forwards;
|
||
}
|
||
|
||
@keyframes sporeFloat {
|
||
0% {
|
||
opacity: 0.8;
|
||
transform: translateY(0) scale(1);
|
||
}
|
||
100% {
|
||
opacity: 0;
|
||
transform: translateY(-100px) scale(0.5);
|
||
}
|
||
}
|
||
|
||
/* --- MELTDOWN / RAM CORRUPTION --- */
|
||
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);
|
||
}
|
||
}
|
||
|
||
.corrupted-text {
|
||
display: inline-block;
|
||
animation: text-flicker 0.08s infinite;
|
||
color: var(--alert);
|
||
font-weight: bold;
|
||
}
|
||
|
||
@keyframes text-flicker {
|
||
0% {
|
||
opacity: 1;
|
||
transform: scaleX(1);
|
||
}
|
||
25% {
|
||
opacity: 0.3;
|
||
transform: scaleX(-1) scaleY(1.2);
|
||
}
|
||
50% {
|
||
opacity: 0.7;
|
||
transform: scaleX(1) scaleY(0.8);
|
||
}
|
||
75% {
|
||
opacity: 0.2;
|
||
transform: scaleX(-1);
|
||
}
|
||
100% {
|
||
opacity: 1;
|
||
transform: scaleX(1);
|
||
}
|
||
}
|
||
|
||
.memory-error {
|
||
color: var(--alert);
|
||
text-shadow: 0 0 10px red;
|
||
animation: pulse-error 0.5s infinite;
|
||
}
|
||
|
||
@keyframes pulse-error {
|
||
0%,
|
||
100% {
|
||
opacity: 1;
|
||
}
|
||
50% {
|
||
opacity: 0.5;
|
||
}
|
||
}
|
||
|
||
/* --- FSOCIETY BOOT EFFECT --- */
|
||
body.fsociety-boot {
|
||
background: #000;
|
||
filter: contrast(1.3) brightness(0.9);
|
||
}
|
||
|
||
body.fsociety-boot .crt-wrap::before {
|
||
opacity: 0.8;
|
||
background:
|
||
linear-gradient(rgba(0, 255, 0, 0.1) 50%, rgba(0, 0, 0, 0.3) 50%),
|
||
linear-gradient(
|
||
90deg,
|
||
rgba(0, 255, 0, 0.1),
|
||
rgba(0, 255, 0, 0.05),
|
||
rgba(0, 255, 0, 0.1)
|
||
);
|
||
}
|
||
|
||
.fsociety-mask {
|
||
font-size: 11px;
|
||
line-height: 11px;
|
||
white-space: pre;
|
||
color: #fff;
|
||
text-shadow:
|
||
0 0 15px #fff,
|
||
0 0 30px #fff,
|
||
0 0 45px #00ff00;
|
||
animation: mask-glow 1.5s infinite;
|
||
font-weight: bold;
|
||
}
|
||
|
||
@keyframes mask-glow {
|
||
0%,
|
||
100% {
|
||
text-shadow:
|
||
0 0 15px #fff,
|
||
0 0 30px #fff,
|
||
0 0 45px #00ff00;
|
||
opacity: 1;
|
||
}
|
||
50% {
|
||
text-shadow:
|
||
0 0 25px #fff,
|
||
0 0 50px #fff,
|
||
0 0 75px #00ff00,
|
||
0 0 100px #00ff00;
|
||
opacity: 0.95;
|
||
}
|
||
}
|
||
|
||
/* --- UTILITY CLASSES --- */
|
||
.log-k {
|
||
color: #fff;
|
||
font-weight: bold;
|
||
}
|
||
.log-err {
|
||
color: var(--alert);
|
||
text-shadow: 0 0 5px red;
|
||
}
|
||
.log-warn {
|
||
color: #ffb000;
|
||
}
|
||
.log-sys {
|
||
color: cyan;
|
||
}
|
||
.log-dim {
|
||
opacity: 0.5;
|
||
}
|
||
.is-dir {
|
||
color: #5e91ff;
|
||
font-weight: bold;
|
||
}
|
||
.is-exe {
|
||
color: var(--phosphor);
|
||
font-weight: bold;
|
||
}
|
||
|
||
.kernel-panic {
|
||
color: var(--alert);
|
||
font-weight: bold;
|
||
text-shadow: 0 0 10px red;
|
||
animation: panic-flash 0.3s infinite;
|
||
}
|
||
|
||
@keyframes panic-flash {
|
||
0%,
|
||
100% {
|
||
opacity: 1;
|
||
}
|
||
50% {
|
||
opacity: 0.7;
|
||
}
|
||
}
|
||
|
||
/* --- ENHANCED VISUAL EFFECTS --- */
|
||
.glitch-text {
|
||
animation: glitch-text 0.3s infinite;
|
||
}
|
||
|
||
@keyframes glitch-text {
|
||
0% {
|
||
transform: translate(0);
|
||
}
|
||
20% {
|
||
transform: translate(-2px, 2px);
|
||
}
|
||
40% {
|
||
transform: translate(-2px, -2px);
|
||
}
|
||
60% {
|
||
transform: translate(2px, 2px);
|
||
}
|
||
80% {
|
||
transform: translate(2px, -2px);
|
||
}
|
||
100% {
|
||
transform: translate(0);
|
||
}
|
||
}
|
||
|
||
.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;
|
||
}
|
||
}
|
||
`}</style>
|
||
|
||
<div id="flash-overlay" ref={overlayRef}></div>
|
||
|
||
<div className="crt-wrap glow" ref={bodyRef}>
|
||
<div id="terminal">
|
||
<div id="output" ref={outputRef}></div>
|
||
<div
|
||
className="input-line"
|
||
id="input-container"
|
||
ref={inputContainerRef}
|
||
>
|
||
<span className="prompt">guest@404:~$ </span>
|
||
<input
|
||
type="text"
|
||
id="cmd-input"
|
||
ref={inputRef}
|
||
autoComplete="off"
|
||
spellCheck={false}
|
||
tabIndex={0}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</>
|
||
);
|
||
}
|