mirror of
https://github.com/ION606/ion606.github.io.git
synced 2026-05-14 22:16:59 +00:00
updated resume
This commit is contained in:
+204
@@ -0,0 +1,204 @@
|
||||
// Initialize animations and interactions
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
createStars();
|
||||
initObservers();
|
||||
initKonamiCode();
|
||||
});
|
||||
|
||||
function createStars() {
|
||||
const starfield = document.getElementById("starfield");
|
||||
starfield.innerHTML = "";
|
||||
|
||||
for (let i = 0; i < 200; i++) {
|
||||
const star = document.createElement("div");
|
||||
star.className = "star";
|
||||
star.style.width = Math.random() * 3 + "px";
|
||||
star.style.height = star.style.width;
|
||||
star.style.left = Math.random() * 100 + "%";
|
||||
star.style.top = Math.random() * 100 + "%";
|
||||
star.style.animationDuration = Math.random() * 3 + 1 + "s";
|
||||
starfield.appendChild(star);
|
||||
}
|
||||
}
|
||||
|
||||
function initObservers() {
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.style.opacity = 1;
|
||||
entry.target.style.transform = "translateY(0)";
|
||||
}
|
||||
});
|
||||
},
|
||||
{ threshold: 0.1 }
|
||||
);
|
||||
|
||||
document.querySelectorAll(".section, .timeline-item").forEach((el) => {
|
||||
observer.observe(el);
|
||||
});
|
||||
}
|
||||
|
||||
function initKonamiCode() {
|
||||
const konamiCode = [
|
||||
"ArrowUp",
|
||||
"ArrowUp",
|
||||
"ArrowDown",
|
||||
"ArrowDown",
|
||||
"ArrowLeft",
|
||||
"ArrowRight",
|
||||
"ArrowLeft",
|
||||
"ArrowRight",
|
||||
"b",
|
||||
"a",
|
||||
];
|
||||
let index = 0;
|
||||
|
||||
document.addEventListener("keydown", (e) => {
|
||||
e.key === konamiCode[index] ? index++ : (index = 0);
|
||||
if (index === konamiCode.length) {
|
||||
document.body.classList.add("konami-mode");
|
||||
const ufo = document.querySelector(".ufo");
|
||||
ufo.style.animation = "flyby 15s linear infinite";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// create starfield effect
|
||||
const createStarfield = () => {
|
||||
const starfield = document.querySelector("#starfield");
|
||||
const numStars = 150;
|
||||
for (let i = 0; i < numStars; i++) {
|
||||
const star = document.createElement("div");
|
||||
star.classList.add("star");
|
||||
// randomize size and position
|
||||
const size = Math.random() * 3 + 1;
|
||||
star.style.width = `${size}px`;
|
||||
star.style.height = `${size}px`;
|
||||
star.style.top = `${Math.random() * 100}vh`;
|
||||
star.style.left = `${Math.random() * 100}vw`;
|
||||
// random duration for twinkling
|
||||
star.style.setProperty("--duration", `${Math.random() * 3 + 2}s`);
|
||||
// add click event to form constellations
|
||||
star.addEventListener("click", (e) => {
|
||||
console.log("star clicked at", e.pageX, e.pageY);
|
||||
});
|
||||
starfield.appendChild(star);
|
||||
}
|
||||
};
|
||||
|
||||
// implement typewriter effect for hero section
|
||||
function typewriterEffect() {
|
||||
const el = document.querySelector(".typing-text");
|
||||
const text = el.getAttribute("data-text");
|
||||
el.innerHTML = ""; // Clear any existing content
|
||||
|
||||
// Create a span for the typed text
|
||||
const textSpan = document.createElement("span");
|
||||
textSpan.className = "typed-text";
|
||||
el.appendChild(textSpan);
|
||||
|
||||
// Create a blinking caret appended after the text
|
||||
const caretSpan = document.createElement("span");
|
||||
caretSpan.className = "typing-cursor";
|
||||
el.appendChild(caretSpan);
|
||||
|
||||
let index = 0;
|
||||
const speed = 100; // ms/char
|
||||
|
||||
function type() {
|
||||
if (index < text.length) {
|
||||
textSpan.textContent += text.charAt(index);
|
||||
index++;
|
||||
setTimeout(type, speed);
|
||||
} else setTimeout(() => caretSpan.remove(), 2000);
|
||||
}
|
||||
type();
|
||||
}
|
||||
|
||||
const createParticleEffect = () => {
|
||||
const particles = document.createElement("div");
|
||||
particles.style.position = "fixed";
|
||||
particles.style.top = `${Math.random() * window.innerHeight}px`;
|
||||
particles.style.left = `${Math.random() * window.innerWidth}px`;
|
||||
particles.style.width = "5px";
|
||||
particles.style.height = "5px";
|
||||
particles.style.background = "var(--primary)";
|
||||
particles.style.borderRadius = "50%";
|
||||
particles.style.opacity = "0.8";
|
||||
particles.style.pointerEvents = "none";
|
||||
particles.style.transition = "opacity 1s ease-out";
|
||||
document.body.appendChild(particles);
|
||||
setTimeout(() => {
|
||||
particles.style.opacity = "0";
|
||||
}, 50);
|
||||
setTimeout(() => {
|
||||
particles.remove();
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// implement particle effect on scroll
|
||||
const particleEffectOnScroll = () => {
|
||||
window.addEventListener("scroll", () => createParticleEffect);
|
||||
};
|
||||
|
||||
// konami code detection for UFO easter egg
|
||||
let keyBuffer = [];
|
||||
|
||||
// launch UFO easter egg
|
||||
const launchUFO = () => {
|
||||
const ufo = document.createElement("div");
|
||||
ufo.classList.add("ufo");
|
||||
document.body.appendChild(ufo);
|
||||
// remove UFO after animation
|
||||
ufo.addEventListener("animationend", () => {
|
||||
ufo.remove();
|
||||
});
|
||||
};
|
||||
|
||||
// intersection observer for sections
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.style.opacity = 1;
|
||||
entry.target.style.transform = "translateY(0)";
|
||||
}
|
||||
});
|
||||
},
|
||||
{ threshold: 0.1 }
|
||||
);
|
||||
|
||||
document.querySelectorAll(".section").forEach((section, index) => {
|
||||
observer.observe(section);
|
||||
section.style.animationDelay = `${index * 0.2}s`;
|
||||
});
|
||||
|
||||
createStarfield();
|
||||
typewriterEffect();
|
||||
particleEffectOnScroll();
|
||||
|
||||
let hovered = false;
|
||||
const modTitle = document.querySelector("#moduleTitle"),
|
||||
modules = modTitle.parentElement.querySelectorAll(".module");
|
||||
|
||||
modules.forEach((el) => {
|
||||
el.addEventListener("mouseenter", () => el.classList.add("hovered"));
|
||||
el.addEventListener("mouseleave", () => el.classList.remove("hovered"));
|
||||
});
|
||||
|
||||
modTitle.addEventListener("mouseenter", async () => {
|
||||
if (hovered) return;
|
||||
hovered = true;
|
||||
|
||||
for (const el of modules) {
|
||||
el.classList.add("hovered");
|
||||
|
||||
// anim is .2 seconds
|
||||
setTimeout(() => el.classList.remove("hovered"), 200);
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
});
|
||||
|
||||
modTitle.addEventListener("mouseleave", () => (hovered = false));
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
async function triggerVirus() {
|
||||
const stage1 = 3000; // 3 s red alert
|
||||
const stage2 = 3000; // next 3 s data corruption
|
||||
|
||||
const snapshot = await html2canvas(document.body);
|
||||
const img = PIXI.Sprite.from(snapshot.toDataURL());
|
||||
|
||||
// wipe page & set black background
|
||||
document.body.innerHTML = "";
|
||||
document.documentElement.style.cssText =
|
||||
"background: black; margin: 0; padding: 0; overflow: hidden;";
|
||||
|
||||
// container for overlays/canvas
|
||||
const container = document.createElement("div");
|
||||
container.id = "virusContainer";
|
||||
Object.assign(container.style, {
|
||||
position: "fixed", top: 0, left: 0,
|
||||
width: "100vw", height: "100vh",
|
||||
display: "flex", alignItems: "center",
|
||||
justifyContent: "center", flexDirection: "column",
|
||||
color: "white", fontFamily: "monospace",
|
||||
});
|
||||
document.body.appendChild(container);
|
||||
|
||||
// -- stage 1: red alert + countdown --
|
||||
const alert = document.createElement("div");
|
||||
alert.id = "virusAlert";
|
||||
container.appendChild(alert);
|
||||
|
||||
let countdown = 10;
|
||||
alert.textContent = `⚠️ SYSTEM PURGE IN ${countdown} ⚠️`;
|
||||
alert.style.cssText = "font-size: 3rem; color: #f00;";
|
||||
|
||||
const timerId = setInterval(() => {
|
||||
countdown -= 1;
|
||||
alert.textContent = `⚠️ SYSTEM PURGE IN ${countdown} ⚠️`;
|
||||
// flash effect
|
||||
alert.style.visibility =
|
||||
alert.style.visibility === "hidden" ? "visible" : "hidden";
|
||||
}, 500);
|
||||
|
||||
// after stage1 ms → stage 2
|
||||
setTimeout(() => {
|
||||
clearInterval(timerId);
|
||||
container.removeChild(alert);
|
||||
|
||||
// -- stage 2: hex stream + shake/flicker --
|
||||
const hex = document.createElement("pre");
|
||||
hex.id = "virusHex";
|
||||
hex.style.cssText = "font-size:1rem; width:80vw; height:100vh; overflow:hidden;";
|
||||
container.appendChild(hex);
|
||||
|
||||
// stream fake hex
|
||||
const hexChars = "0123456789ABCDEF";
|
||||
const streamId = setInterval(() => {
|
||||
let line = "";
|
||||
for (let i = 0; i < 64; i++) {
|
||||
line += hexChars.charAt(Math.random() * 16 | 0);
|
||||
}
|
||||
hex.textContent += line + "\n";
|
||||
hex.scrollTop = hex.scrollHeight;
|
||||
}, 50);
|
||||
|
||||
document.body.classList.add("shake", "flicker");
|
||||
|
||||
setTimeout(() => {
|
||||
console.debug("▶️ entering stage 3 (glitch filter)");
|
||||
|
||||
clearInterval(streamId);
|
||||
container.removeChild(hex);
|
||||
|
||||
// -- stage 3: pixi.js glitch filter on canvas --
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.id = "virusCanvas";
|
||||
|
||||
canvas.addEventListener('webglcontextlost', event => {
|
||||
event.preventDefault(); // opt into manual recovery
|
||||
console.warn('⚠️ my WebGL context was lost');
|
||||
}, false);
|
||||
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
|
||||
Object.assign(canvas.style, {
|
||||
position: "fixed", top: 0, left: 0,
|
||||
width: "100vw", height: "100vh", zIndex: 9999,
|
||||
});
|
||||
|
||||
|
||||
container.appendChild(canvas);
|
||||
|
||||
// initialize PixiJS application
|
||||
const app = new PIXI.Application({
|
||||
view: canvas,
|
||||
resizeTo: window,
|
||||
resolution: 1, // force 1× device pixel ratio
|
||||
autoDensity: true // keep CSS size but lower GPU size
|
||||
});
|
||||
|
||||
app.renderer.view.addEventListener('webglcontextlost', (e) => {
|
||||
e.preventDefault();
|
||||
console.warn('WebGL lost, falling back to CanvasRenderer');
|
||||
app.destroy(true, { children: true });
|
||||
});
|
||||
|
||||
|
||||
// Create a full-screen white rectangle as the sprite
|
||||
img.width = window.innerWidth;
|
||||
img.height = window.innerHeight;
|
||||
app.stage.addChild(img);
|
||||
|
||||
// apply realistic glitch filter
|
||||
const filter = new PIXI.filters.GlitchFilter({ slices: 20, offset: 10 });
|
||||
app.stage.filters = [filter];
|
||||
|
||||
// animate the filter
|
||||
app.ticker.add(() => {
|
||||
filter.slices = 10 + Math.random() * 30;
|
||||
filter.offset = Math.random() * 20;
|
||||
});
|
||||
|
||||
console.log(app.renderer)
|
||||
|
||||
// block all input
|
||||
const block = (e) => { e.preventDefault(); e.stopImmediatePropagation(); };
|
||||
window.addEventListener("keydown", block, true);
|
||||
window.addEventListener("mousedown", block, true);
|
||||
window.addEventListener("touchstart", block, true);
|
||||
|
||||
}, stage2);
|
||||
}, stage1);
|
||||
|
||||
return "";
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
function createPageMenu() {
|
||||
const navMenu = document.createElement('nav');
|
||||
navMenu.id = 'page-menu';
|
||||
navMenu.className = 'hidden';
|
||||
|
||||
const ul = document.createElement('ul');
|
||||
|
||||
const links = [
|
||||
{ text: 'Home', href: '/' },
|
||||
{ text: 'Projects', href: 'projects' },
|
||||
{ text: 'README', href: 'README' },
|
||||
{ text: 'Links', href: 'links' }
|
||||
];
|
||||
|
||||
links.forEach(link => {
|
||||
const li = document.createElement('li');
|
||||
const a = document.createElement('a');
|
||||
a.textContent = link.text;
|
||||
a.href = link.href;
|
||||
li.appendChild(a);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
|
||||
navMenu.appendChild(ul);
|
||||
|
||||
document.body.prepend(navMenu);
|
||||
|
||||
if (document.querySelector('.title')) {
|
||||
document.addEventListener('scroll', function () {
|
||||
var menu = document.querySelector('#page-menu');
|
||||
var currentScroll = window.pageYOffset || document.documentElement.scrollTop;
|
||||
|
||||
if (currentScroll > lastScrollTop && !isHovered) {
|
||||
menu.classList.add('hidden');
|
||||
} else if (!isHovered) {
|
||||
menu.classList.remove('hidden');
|
||||
}
|
||||
lastScrollTop = currentScroll <= 0 ? 0 : currentScroll; // For Mobile or negative scrolling
|
||||
});
|
||||
|
||||
document.querySelectorAll('#page-menu, .title').forEach(el => {
|
||||
el.addEventListener('mouseenter', function () {
|
||||
isHovered = true;
|
||||
document.querySelector('#page-menu').classList.remove('hidden');
|
||||
document.querySelector('.title').style.marginTop = '40px';
|
||||
});
|
||||
|
||||
el.addEventListener('mouseleave', function () {
|
||||
isHovered = false;
|
||||
document.querySelector('#page-menu').classList.add('hidden');
|
||||
document.querySelector('.title').style.marginTop = '20px';
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
document.querySelector('#page-menu').classList.remove('hidden');
|
||||
document.body.children[1].style.marginTop = '40px';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
function getRandomColorScheme() {
|
||||
const schemes = [
|
||||
() => `rgb(${Math.floor(Math.random() * 205) + 50}, 0, ${Math.floor(Math.random() * 205) + 50})`, // Pink and purple shades
|
||||
() => `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, 0)`, // Yellow
|
||||
() => `rgb(0, ${Math.floor(Math.random() * 256)}, 0)`, // Green
|
||||
() => `rgb(0, 0, ${Math.floor(Math.random() * 256)})`, // Blue
|
||||
() => `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)})`, // White (grayscale)
|
||||
() => 'rgb(0,0,0)' //`rgb(${Math.floor(Math.random() * 56)}, ${Math.floor(Math.random() * 56)}, ${Math.floor(Math.random() * 56)})` // Black (dark grayscale)
|
||||
];
|
||||
const ind = Math.floor(Math.random() * schemes.length);
|
||||
return { ind, scheme: schemes[ind] };
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', (e) => {
|
||||
const {ind, scheme} = getRandomColorScheme();
|
||||
|
||||
console.log(ind);
|
||||
|
||||
const canvas = document.getElementById('matrixCanvas');
|
||||
const context = canvas.getContext('2d');
|
||||
|
||||
let columns;
|
||||
let drops;
|
||||
|
||||
function setup() {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
|
||||
columns = Math.floor(canvas.width / fontSize);
|
||||
drops = [];
|
||||
|
||||
for (let x = 0; x < columns; x++)
|
||||
drops[x] = 1;
|
||||
}
|
||||
|
||||
window.addEventListener('resize', setup);
|
||||
|
||||
let fontSize = 16;
|
||||
|
||||
const katakana = "アカサタナハマヤラワガザダバパイキシチニヒミリギジヂビピウクスツヌフムユルグズヅブプエケセテネヘメレゲゼデベペオコソトノホモヨロゴゾドボポ";
|
||||
const latin = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const nums = "0123456789";
|
||||
const matrixChars = katakana + latin + nums;
|
||||
|
||||
function draw() {
|
||||
context.fillStyle = (ind === 5) ? 'rgba(255, 255, 255, 0.05)' : 'rgba(0, 0, 0, 0.05)';
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
context.fillStyle = scheme(); //'#ff00ff'; // Bright pink color
|
||||
context.font = fontSize + 'px monospace';
|
||||
|
||||
for (let i = 0; i < drops.length; i++) {
|
||||
const text = matrixChars.charAt(Math.floor(Math.random() * matrixChars.length));
|
||||
context.fillText(text, i * fontSize, drops[i] * fontSize);
|
||||
|
||||
// Randomly go back to the top
|
||||
if (drops[i] * fontSize > canvas.height && Math.random() > 0.975)
|
||||
drops[i] = 0;
|
||||
|
||||
// Move the drop down
|
||||
drops[i]++;
|
||||
|
||||
// Assign a random color from the color schemes
|
||||
context.fillStyle = scheme();
|
||||
}
|
||||
}
|
||||
|
||||
setup(); // Call setup initially to set up canvas and drops
|
||||
setInterval(draw, 33);
|
||||
});
|
||||
+470
@@ -0,0 +1,470 @@
|
||||
const projectLinks = {
|
||||
"bluesky-client": "https://github.com/ION606/bluesky-client",
|
||||
"workout-app": "https://workout.ion606.com/",
|
||||
"AI-overlord": "https://github.com/ION606/AI-overlord",
|
||||
"black-hole-sim": "https://github.com/ION606/black-hole-sim",
|
||||
"chatjs-main": "https://github.com/Proto-Chat/chatJS-main",
|
||||
"custom_discordjs": "https://github.com/ION606/custom_discordjs",
|
||||
"learn": "https://github.com/ION606/learn",
|
||||
"ion-lang": "https://github.com/The-ION-Language/ION-Lang",
|
||||
"vcs": "https://github.com/ION606/VCS",
|
||||
"ml-pipeline": "https://github.com/ION606/ML-pipeline",
|
||||
"browser-chromium": "https://github.com/ION606/browser-chromium",
|
||||
"static-site-hosting": "https://github.com/ION606/static-site-hosting",
|
||||
"procgen": "https://github.com/ION606/ProcGen",
|
||||
"linkedin-api": "https://github.com/ION606/linkedin-api",
|
||||
"github-to-fs": "https://github.com/ION606/github-to-fs",
|
||||
"web-to-fish": "https://github.com/ION606/web-to-fish",
|
||||
"commit_grabber": "https://github.com/ION606/commit_grabber",
|
||||
"youtube-music-meta-extract": "https://github.com/ION606/youtube-music-meta-extract",
|
||||
"mailpocket": "https://github.com/ION606/MailPocket",
|
||||
};
|
||||
|
||||
const glitchText = 'T̵̙̻̭̤̺̱̥̖̤̭̗̜͓̓̈́̏͋̔̕̚͠h̴ͽ̳͎̳̱̘̎͛͆̓̐͑͛̈́̕̕͝͝é̷̛̮̥̲͇̊̅͋̏̊̅͊͝͝ ̵̡̛̪̮̦̘̘̼̼̺̪̪̋͋̀̌̇̉̋͌̾̿̓͝͝V̶̡̨̧̨̟̙̻͓̪͇̻̞̥͑̎͋͗̿́̓̌͒͊̈́́̚͠ơ̴̛̱̞̾̎̒̋̾̔̈́̓͑̋̉ȋ̴̡̛͔̙̘̝̙̬̠̹̙̻͖̽̿̓̑̈́͋́̐̕͠d̷̲̲̘̈́̑́̿̆̓̔͋́̓̋̅̏̚';
|
||||
|
||||
// secret developer console toggle (using backtick key)
|
||||
const devConsoleToggle = () => {
|
||||
const devConsole = document.querySelector("#dev-console");
|
||||
if (
|
||||
devConsole.style.display === "none" ||
|
||||
devConsole.style.display === ""
|
||||
) {
|
||||
devConsole.style.display = "block";
|
||||
} else {
|
||||
devConsole.style.display = "none";
|
||||
devConsole.querySelector(".consoleout").innerHTML = "";
|
||||
}
|
||||
|
||||
// for the command
|
||||
return true;
|
||||
};
|
||||
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "`") devConsoleToggle();
|
||||
});
|
||||
|
||||
class TerminalFS {
|
||||
constructor() {
|
||||
const consoleInput = document.querySelector("#dev-console input");
|
||||
const consoleOutput = document.createElement("div");
|
||||
consoleOutput.className = "consoleout";
|
||||
document.querySelector("#dev-console").prepend(consoleOutput);
|
||||
|
||||
// not set bc indexing
|
||||
const userInps = [];
|
||||
let uInpInd = 0;
|
||||
|
||||
consoleInput?.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
const commandText = e.target.value.trim();
|
||||
const [cmd, ...args] = commandText.split(" ");
|
||||
|
||||
if (cmd === "clear") consoleOutput.innerHTML = "";
|
||||
else {
|
||||
const eggResponse = this.easterEggs(commandText);
|
||||
if (eggResponse) {
|
||||
consoleOutput.innerHTML += `<div style="color: var(--command-color)">> ${commandText}</div><div>${eggResponse}</div>`;
|
||||
e.target.value = "";
|
||||
} else {
|
||||
const cmdContent = this.commands[cmd]?.(args.join(" "));
|
||||
if (!cmdContent) {
|
||||
consoleOutput.innerHTML += `<div class="consolerrdiv">🚨 Unknown command: \`${cmd}\`</div>`;
|
||||
} else if (cmdContent != true) {
|
||||
consoleOutput.innerHTML += `<div>${cmdContent}</div>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!userInps.includes(commandText)) userInps.push(commandText);
|
||||
e.target.value = "";
|
||||
uInpInd = 0; // reset history index
|
||||
consoleOutput.scrollTop = consoleOutput.scrollHeight;
|
||||
} else if (e.key === "ArrowUp") {
|
||||
if (userInps.length > 0 && uInpInd < userInps.length) {
|
||||
uInpInd++;
|
||||
consoleInput.value = userInps[userInps.length - uInpInd];
|
||||
consoleInput.setSelectionRange(
|
||||
consoleInput.value.length,
|
||||
consoleInput.value.length
|
||||
);
|
||||
}
|
||||
} else if (e.key === "ArrowDown") {
|
||||
if (uInpInd > 1) {
|
||||
uInpInd--;
|
||||
consoleInput.value = userInps[userInps.length - uInpInd];
|
||||
consoleInput.setSelectionRange(
|
||||
consoleInput.value.length,
|
||||
consoleInput.value.length
|
||||
);
|
||||
} else {
|
||||
uInpInd = 0;
|
||||
consoleInput.value = "";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.currentDir = "/";
|
||||
this.fs = {
|
||||
"/": {
|
||||
type: "dir",
|
||||
children: ["home", "projects", "fun", "etc", "sys"],
|
||||
},
|
||||
"/home": { type: "dir", children: ["ion606", "guest"] },
|
||||
"/home/ion606": {
|
||||
type: "dir",
|
||||
children: [
|
||||
"resume.txt",
|
||||
"todo.txt",
|
||||
".secret_config",
|
||||
"diary.md",
|
||||
],
|
||||
},
|
||||
"/projects": {
|
||||
type: "dir",
|
||||
children: Object.keys(projectLinks),
|
||||
},
|
||||
"/fun": {
|
||||
type: "dir",
|
||||
children: ["joke.txt", "konami.seq", "uwu.md", "hackerman.gif"],
|
||||
},
|
||||
"/etc": {
|
||||
type: "dir",
|
||||
children: ["motd", "syslog", "joke_of_the_day"],
|
||||
},
|
||||
"/sys": {
|
||||
type: "dir",
|
||||
children: ["self-destruct.exe", "disco-bootloader"],
|
||||
},
|
||||
};
|
||||
|
||||
this.files = {
|
||||
"/home/ion606/todo.txt": `
|
||||
1. Take over the world
|
||||
2. Make coffee ☕
|
||||
3. Fix CSS in production
|
||||
4. ????
|
||||
5. PROFIT!
|
||||
`,
|
||||
"/home/ion606/resume.txt": `
|
||||
ION606 - Resume
|
||||
|
||||
Skills:
|
||||
- Programming: C, C++, Python, JavaScript, TypeScript, Rust, Go, Java, etc.
|
||||
- Web: HTML, CSS, React, Vue, Express.js, Node.js, Flask, FastAPI
|
||||
- ML: TensorFlow, scikit-learn
|
||||
- Databases: MongoDB, PostgreSQL, MySQL, SQLite, Redis
|
||||
- Tools: Git, Docker, Kubernetes, Vagrant, Electron, Next.js
|
||||
|
||||
Contact: ion606@protonmail.com
|
||||
`,
|
||||
"/home/ion606/.secret_config": `
|
||||
[disco_settings]
|
||||
sparkle_level=9001
|
||||
rainbow_mode=enabled
|
||||
pink_nodders: online
|
||||
`,
|
||||
"/home/ion606/diary.md": `
|
||||
Dear Diary,
|
||||
|
||||
Today I discovered the Konami code activates a UFO.
|
||||
Also, typing "make me a sandwich" works sometimes...
|
||||
Note to self: Buy more coffee.
|
||||
`,
|
||||
"/fun/joke.txt": `
|
||||
Why do Java developers wear glasses?
|
||||
Because they can't C#!
|
||||
|
||||
(•_•)
|
||||
( •_•)>⌐■-■
|
||||
(⌐■_■)
|
||||
`,
|
||||
"/fun/konami.seq": `
|
||||
↑ ↑ ↓ ↓ ← → ← → B A
|
||||
|
||||
Hint: Try entering this sequence on the main page!
|
||||
`,
|
||||
"/fun/uwu.md": `
|
||||
# Nya~ Welcome to my secret docs!
|
||||
|
||||
(´• ω •\`)ノ Here's some important stuff:
|
||||
- Pet all the cats 🐈
|
||||
- Drink more water 💧
|
||||
- Remember to uwu-ify your code
|
||||
`,
|
||||
"/fun/hackerman.gif": `
|
||||
[Imagine a cool ASCII art of Hackerman here!]
|
||||
You are now... HACKERMAN.
|
||||
`,
|
||||
"/projects/bluesky-client": `
|
||||
bluesky-client
|
||||
|
||||
My Bluesky client. See: https://github.com/ION606/bluesky-client
|
||||
`,
|
||||
"/projects/workout-app": `
|
||||
ION Workout App
|
||||
|
||||
An open source workout app! See: https://workout.ion606.com/
|
||||
`,
|
||||
"/projects/AI-overlord": `
|
||||
AI Overlord
|
||||
|
||||
A project to automate everything (and maybe take over the world).
|
||||
`,
|
||||
"/projects/black-hole-sim": `
|
||||
Black Hole Simulator
|
||||
|
||||
A physics simulation of black holes and gravitational lensing.
|
||||
`,
|
||||
"/projects/virus.exe": `
|
||||
VIRUS.EXE
|
||||
|
||||
WARNING: This file is highly suspicious. Running it may cause unexpected behavior!
|
||||
`,
|
||||
"/etc/motd": `
|
||||
WARNING: This system is powered by ✨imagination✨
|
||||
Unauthorized access will result in ${glitchText}
|
||||
`,
|
||||
"/etc/syslog": `
|
||||
[INFO] System booted successfully.
|
||||
[INFO] User 'ion606' logged in.
|
||||
[WARN] Too much imagination detected.
|
||||
[INFO] All systems nominal.
|
||||
`,
|
||||
"/etc/joke_of_the_day": `
|
||||
Why do programmers prefer dark mode?
|
||||
Because light attracts bugs! 🐛
|
||||
|
||||
How many programmers does it take to change a light bulb?
|
||||
None, that's a hardware problem!
|
||||
`,
|
||||
"/sys/self-destruct.exe": `
|
||||
*** WARNING ***
|
||||
You have attempted to access the self-destruct sequence.
|
||||
This feature is disabled for your safety.
|
||||
`,
|
||||
"/sys/disco-bootloader": `
|
||||
Disco Bootloader v1.0
|
||||
|
||||
Initializing disco mode...
|
||||
Boot sequence: 🕺💃🪩
|
||||
`,
|
||||
};
|
||||
}
|
||||
|
||||
// Easter egg commands
|
||||
easterEggs(command) {
|
||||
const responses = {
|
||||
"sudo make me a sandwich": "What? Make it yourself.",
|
||||
"why did the chicken cross the road?":
|
||||
'To git commit -m "migration"',
|
||||
"open the pod bay doors":
|
||||
"I'm sorry Dave, I'm afraid I can't do that",
|
||||
"there is no spoon": "System matrix compromised...",
|
||||
"beam me up": "Energizing! ♫♪♫ ♪♫♪ ♫♪♫",
|
||||
};
|
||||
|
||||
return responses[command.toLowerCase()] || null;
|
||||
}
|
||||
|
||||
// Path resolution logic
|
||||
resolvePath(targetPath) {
|
||||
const path = targetPath.replace(/\/+/g, "/").replace(/\/$/, "") || "/";
|
||||
|
||||
if (path.startsWith("/")) return path;
|
||||
else {
|
||||
let fullPath = `${this.currentDir}/${path}`.replace(/\/+/g, "/");
|
||||
const segments = fullPath.split("/").filter(Boolean);
|
||||
const resolvedSegments = [];
|
||||
|
||||
for (const segment of segments) {
|
||||
// Current directory, skip
|
||||
if (segment === ".") continue;
|
||||
|
||||
// Move up one level if possible
|
||||
if (segment === "..") resolvedSegments.pop();
|
||||
else resolvedSegments.push(segment);
|
||||
}
|
||||
|
||||
return "/" + resolvedSegments.join("/");
|
||||
}
|
||||
}
|
||||
|
||||
// Command implementations
|
||||
commands = {
|
||||
ls: (path) => {
|
||||
if (!path) path = this.currentDir;
|
||||
|
||||
const absPath = this.resolvePath(path);
|
||||
const dir = this.fs[absPath];
|
||||
|
||||
if (!dir)
|
||||
return `ls: cannot access '${path}': No such file or directory`;
|
||||
if (dir.type !== "dir") return `ls: ${path}: Not a directory`;
|
||||
|
||||
const items = dir.children.map((item) => {
|
||||
const fullPath =
|
||||
absPath === "/" ? `/${item}` : `${absPath}/${item}`;
|
||||
const isDir = this.fs[fullPath]?.type === "dir";
|
||||
return `${isDir ? "📁" : "📄"} ${item}${isDir ? "/" : ""}`;
|
||||
});
|
||||
|
||||
return `<pre>${absPath}\n${"-".repeat(40)}\n${items.join(
|
||||
"\n"
|
||||
)}</pre>`;
|
||||
},
|
||||
|
||||
cd: (path) => {
|
||||
const absPath = this.resolvePath(path);
|
||||
if (!this.fs[absPath] || this.fs[absPath].type !== "dir") {
|
||||
return `cd: ${path}: No such directory`;
|
||||
}
|
||||
this.currentDir = absPath;
|
||||
return `<pre>moved to ${absPath}</pre>`;
|
||||
},
|
||||
|
||||
cat: (filePath) => {
|
||||
const absPath = this.resolvePath(filePath);
|
||||
|
||||
if (!this.files[absPath]) {
|
||||
// Easter egg for missing files
|
||||
const jokes = [
|
||||
"File not found... but here's a joke!",
|
||||
"404: Humor not found... just kidding!",
|
||||
"This file is in another castle! 🍄",
|
||||
];
|
||||
const asciiArts = [
|
||||
`
|
||||
<pre>
|
||||
.--.
|
||||
|o_o |
|
||||
|:_/ |
|
||||
// \\ \\
|
||||
(| | )
|
||||
/'\\_ _/\\\`
|
||||
\\___)=(___/
|
||||
</pre>
|
||||
`,
|
||||
`
|
||||
<pre>
|
||||
(╯°□°)╯︵ ┻━┻
|
||||
</pre>
|
||||
`
|
||||
];
|
||||
|
||||
const joke = jokes[Math.floor(Math.random() * jokes.length)],
|
||||
art = asciiArts[Math.floor(Math.random() * asciiArts.length)];
|
||||
return `<div style="color:#ff4081">${joke}</div>${art}`;
|
||||
}
|
||||
|
||||
return `<pre>${this.files[absPath].trim()}</pre>`;
|
||||
},
|
||||
help: () => `
|
||||
<ul>
|
||||
<li><strong>exit</strong> - Exit the console</li>
|
||||
<li><strong>clear</strong> - Clear the console</li>
|
||||
<li><strong>help</strong> - Show this help message</li>
|
||||
<li><strong>ls [path]</strong> - List directory contents</li>
|
||||
<li><strong>cd [path]</strong> - Change directory</li>
|
||||
<li><strong>cat [file]</strong> - Display file content</li>
|
||||
<li><strong>theme day/night</strong> - Switch between day/night modes</li>
|
||||
<li><strong>background [ocean/sunset/forest]</strong> - Set a new background gradient (or reset with no valid argument)</li>
|
||||
<li><strong>ufo</strong> - Launch UFO animation</li>
|
||||
<li><strong>starfield</strong> - Regenerate stars</li>
|
||||
<li><strong>random</strong> - Activate random color chaos!</li>
|
||||
<li><strong>secret</strong> - Activate disco mode!</li>
|
||||
<li><strong>run [file]</strong> - Run a file (e.g., .exe)</li>
|
||||
</ul>`,
|
||||
|
||||
exit: devConsoleToggle,
|
||||
|
||||
theme: (arg) => {
|
||||
const themeArg = arg.trim().toLowerCase();
|
||||
if (themeArg === "night" || themeArg === "dark") {
|
||||
document.body.setAttribute("data-theme", "night");
|
||||
return "🌙 Switched to night theme!";
|
||||
} else if (themeArg === "day" || themeArg === "light") {
|
||||
document.body.setAttribute("data-theme", "day");
|
||||
return "☀️ Switched to day theme!";
|
||||
} else {
|
||||
return "Usage: theme [day/night]";
|
||||
}
|
||||
},
|
||||
|
||||
background: (arg) => {
|
||||
const bgArg = arg.trim().toLowerCase();
|
||||
if (bgArg === "ocean") {
|
||||
document.body.style.background =
|
||||
"linear-gradient(to right, #1e3c72, #2a5298)";
|
||||
return "🌊 Ocean background set!";
|
||||
} else if (bgArg === "sunset") {
|
||||
document.body.style.background =
|
||||
"linear-gradient(to right, #ff7e5f, #feb47b)";
|
||||
return "🌇 Sunset background set!";
|
||||
} else if (bgArg === "forest") {
|
||||
document.body.style.background =
|
||||
"linear-gradient(to right, #134e5e, #71b280)";
|
||||
return "🌲 Forest background set!";
|
||||
} else {
|
||||
document.body.style.background = "";
|
||||
return "Background reset to default!";
|
||||
}
|
||||
},
|
||||
|
||||
ufo: () => {
|
||||
launchUFO();
|
||||
return "🛸 UFO launched!";
|
||||
},
|
||||
|
||||
starfield: () => {
|
||||
createStars();
|
||||
return "✨ Starfield regenerated!";
|
||||
},
|
||||
|
||||
random: () => {
|
||||
const colors = ["#ff4081", "#7c3aed", "#4f46e5", "#00ff88"];
|
||||
document.body.style.color =
|
||||
colors[Math.floor(Math.random() * colors.length)];
|
||||
return "🌈 Color chaos activated!";
|
||||
},
|
||||
|
||||
secret: () => {
|
||||
document.body.classList.toggle("disco-mode");
|
||||
return "🎆 Disco mode activated!";
|
||||
},
|
||||
|
||||
run: (filePath) => {
|
||||
const absPath = terminalFS.resolvePath(filePath.trim());
|
||||
console.log(absPath, filePath);
|
||||
|
||||
// Project links
|
||||
if (
|
||||
absPath.startsWith("/projects/") &&
|
||||
projectLinks[filePath.replace("/projects/", "")]
|
||||
) {
|
||||
window.open(projectLinks[filePath], "_blank");
|
||||
return `<span style="color: #7c3aed">🚀 Opening project: ${projectLinks[filePath]}</span>`;
|
||||
}
|
||||
|
||||
// Multi-stage "virus.exe"
|
||||
if (absPath === "/projects/virus.exe") {
|
||||
triggerVirus()
|
||||
setTimeout(1000, () => {
|
||||
const el = document.querySelector('.consoleout').lastChild;
|
||||
el.textContent = glitchText;
|
||||
})
|
||||
return "Error running "
|
||||
}
|
||||
|
||||
if (absPath === "/sys/self-destruct.exe") {
|
||||
return `<span style="color: red; font-weight: bold;">💥 Self-destruct is disabled for your safety.</span>`;
|
||||
}
|
||||
if (absPath.endsWith(".exe")) {
|
||||
return `<span style="color: orange;">🛑 Cannot execute: ${filePath}</span>`;
|
||||
}
|
||||
return `<span style="color: gray;">Nothing to run for: ${filePath}</span>`;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Initialize terminal system
|
||||
const terminalFS = new TerminalFS();
|
||||
Reference in New Issue
Block a user