Initial commit — Meridian OS browser desktop demo

This commit is contained in:
2026-04-19 23:18:55 +00:00
commit 8e30dd3597
30 changed files with 6277 additions and 0 deletions

316
js/apps/terminal.js Normal file
View File

@@ -0,0 +1,316 @@
export default {
id: 'terminal',
title: 'Terminal',
render: function (container, api) {
var commandHistory = [];
var historyIndex = -1;
var outputLines = [];
var bus = api.bus;
// ── DOM Structure ──────────────────────────────────────
container.style.cssText = 'height:100%;width:100%;background:#0a0b0d;color:#cfd3d8;display:flex;flex-direction:column;font-family:ui-monospace,"JetBrains Mono",Menlo,monospace;overflow:hidden;cursor:text;';
var outputEl = document.createElement('div');
outputEl.style.cssText = 'flex:1;overflow-y:auto;padding:12px;font-size:14px;line-height:1.5;white-space:pre-wrap;word-break:break-word;';
var inputRow = document.createElement('div');
inputRow.style.cssText = 'display:flex;align-items:center;padding:4px 12px 12px;';
var promptEl = document.createElement('span');
promptEl.style.cssText = 'color:#d4a24c;font-size:14px;line-height:1.5;white-space:pre;user-select:none;';
promptEl.textContent = 'tarnished@meridian:~$ ';
var inputEl = document.createElement('input');
inputEl.style.cssText = 'flex:1;background:transparent;border:none;color:inherit;outline:none;font-family:inherit;font-size:14px;line-height:1.5;cursor:text;';
inputEl.setAttribute('type', 'text');
inputEl.setAttribute('autocomplete', 'off');
inputEl.setAttribute('autocorrect', 'off');
inputEl.setAttribute('autocapitalize', 'off');
inputEl.setAttribute('spellcheck', 'false');
inputRow.appendChild(promptEl);
inputRow.appendChild(inputEl);
container.appendChild(outputEl);
container.appendChild(inputRow);
// ── Helpers ────────────────────────────────────────────
function appendLine(text, color) {
var line = document.createElement('div');
line.style.cssText = 'font-size:14px;line-height:1.5;';
line.style.color = color || '#cfd3d8';
line.textContent = text;
outputEl.appendChild(line);
outputLines.push(line);
outputEl.scrollTop = outputEl.scrollHeight;
}
function printBanner() {
appendLine('Meridian Shell 1.0 (kernel 4.19-browser)');
appendLine("Type 'help' to begin. Try 'praise_the_sun' if you know what you're doing.");
appendLine('');
}
// ── Real Commands ──────────────────────────────────────
function cmdHelp() {
appendLine('Available commands:');
appendLine(' help Show this help message');
appendLine(' ls List directory contents');
appendLine(' whoami Show current user');
appendLine(' date Show current date');
appendLine(' uname Show system info');
appendLine(' echo <text> Print text');
appendLine(' clear Clear terminal output');
appendLine(' cat <file> Read a file');
appendLine(' history Show command history');
appendLine(' achievements Show unlocked achievements');
appendLine(' exit Close terminal');
appendLine('');
appendLine("Try 'praise_the_sun' if you know what you're doing.");
}
function cmdLs() {
appendLine('Documents Downloads Music Pictures save_files.dat');
}
function cmdWhoami() {
var user = api.state.get('user');
appendLine(user ? user.name : 'tarnished');
}
function cmdDate() {
appendLine(new Date().toString());
}
function cmdUname() {
appendLine('Meridian 1.0 (browser-kernel)');
}
function cmdEcho(args) {
if (args.length === 0) return;
appendLine(args.join(' '));
}
function cmdClear() {
outputEl.innerHTML = '';
outputLines = [];
}
function cmdCat(file) {
if (!file) {
appendLine('cat: missing operand', '#c85d5d');
return;
}
if (file === 'save_files.dat') {
appendLine("Ah, you want to read your save file? Not today. Some mysteries are better left unsolved.", '#d4a24c');
return;
}
appendLine('cat: ' + file + ': No such file or directory', '#c85d5d');
}
function cmdHistory() {
if (commandHistory.length === 0) {
appendLine('No commands in history.');
return;
}
commandHistory.forEach(function (cmd, i) {
appendLine(' ' + String(i + 1).padStart(4) + ' ' + cmd);
});
}
function cmdAchievements() {
var achievements = api.state.get('achievements');
if (!achievements || achievements.length === 0) {
appendLine('No achievements unlocked yet.');
return;
}
appendLine('Unlocked achievements (' + achievements.length + '):');
achievements.forEach(function (a) {
appendLine(' [x] ' + a);
});
}
function cmdExit() {
api.close();
}
// ── Easter Eggs ────────────────────────────────────────
var easterEggs = {
'praise_the_sun': {
msg: 'A grace of Gold is bestowed upon you.\nMay it guide you in the dark times ahead.',
slug: 'er_grace'
},
'tarnished': {
msg: 'Well then, tarnished. Seek strength. For that is your duty.',
slug: 'er_tarnished'
},
'try finger, but hole': {
msg: 'Message left by a fellow traveler. Rating: brilliant. Rating: inappropriate.',
slug: 'er_bong_hits'
},
'dropshot': {
msg: 'Hitmarker. Clean drop.',
slug: 'er_dropshot'
},
'360_noscope': {
msg: ' |\n /|\\\n-------\n |/\nmontage material acquired.',
slug: 'er_360noscope'
},
'mw2': {
msg: 'A true classic. Soap would be proud.',
slug: 'er_mw2'
},
'siuuu': {
msg: 'SIUUUUU! The keeper had no chance.',
slug: 'er_siuuu'
},
'golazo': {
msg: 'Top bins. What a strike. What a moment.',
slug: 'er_golazo'
},
'wonderkid': {
msg: 'Regen detected. Potential: 5 stars.',
slug: 'er_wonderkid'
},
'konami': {
msg: 'Cheat mode enabled. (it does nothing. you are already a legend.)',
slug: 'er_konami'
},
'matrix': {
msg: null,
slug: 'er_matrix'
},
'sudo rm -rf /': {
msg: 'nice try, tarnished. root is a state of mind.',
slug: 'er_sudo_rm_rf'
}
};
function triggerEasterEgg(cmdName, egg) {
bus.emit('term:cmd', { cmd: cmdName });
bus.emit('easter:found', { id: egg.slug });
if (cmdName === 'matrix') {
appendLine('Entering the matrix...', '#d4a24c');
var mlines = [];
for (var mi = 0; mi < 8; mi++) {
var row = '';
for (var mj = 0; mj < 40; mj++) {
row += Math.random() < 0.5 ? '0' : '1';
}
mlines.push(row);
}
var mlIdx = 0;
function typeNext() {
if (mlIdx < mlines.length) {
appendLine(mlines[mlIdx], '#41c35a');
mlIdx++;
setTimeout(typeNext, 30);
}
}
setTimeout(typeNext, 30);
return;
}
if (cmdName === 'sudo rm -rf /') {
appendLine('...', '#d4a24c');
setTimeout(function () {
outputEl.removeChild(outputEl.lastChild);
appendLine('nice try, tarnished. root is a state of mind.', '#d4a24c');
}, 900);
return;
}
if (egg.msg && egg.msg.indexOf('\n') !== -1) {
egg.msg.split('\n').forEach(function (ln) {
appendLine(ln, '#d4a24c');
});
} else if (egg.msg) {
appendLine(egg.msg, '#d4a24c');
}
}
// ── Command Processing ─────────────────────────────────
function emitRealCmd(cmd) {
bus.emit('term:cmd', { cmd: cmd });
}
function processInput(raw) {
var trimmed = raw.trim();
if (!trimmed) return;
commandHistory.push(trimmed);
if (commandHistory.length > 50) {
commandHistory.shift();
}
historyIndex = commandHistory.length;
appendLine(promptEl.textContent + trimmed, '#d4a24c');
if (easterEggs[trimmed]) {
triggerEasterEgg(trimmed, easterEggs[trimmed]);
return;
}
var parts = trimmed.split(/\s+/);
var cmd = parts[0].toLowerCase();
if (easterEggs[cmd]) {
triggerEasterEgg(cmd, easterEggs[cmd]);
return;
}
emitRealCmd(cmd);
switch (cmd) {
case 'help': cmdHelp(); break;
case 'ls': cmdLs(); break;
case 'whoami': cmdWhoami(); break;
case 'date': cmdDate(); break;
case 'uname': cmdUname(); break;
case 'echo': cmdEcho(parts.slice(1)); break;
case 'clear': cmdClear(); break;
case 'cat': cmdCat(parts[1]); break;
case 'history': cmdHistory(); break;
case 'achievements': cmdAchievements(); break;
case 'exit': cmdExit(); break;
default:
appendLine('Command not found: ' + cmd, '#c85d5d');
}
}
// ── Keyboard Handling ──────────────────────────────────
inputEl.addEventListener('keydown', function (e) {
if (e.key === 'Enter') {
processInput(inputEl.value);
inputEl.value = '';
historyIndex = commandHistory.length;
} else if (e.key === 'ArrowUp') {
e.preventDefault();
if (historyIndex > 0) {
historyIndex--;
inputEl.value = commandHistory[historyIndex];
}
} else if (e.key === 'ArrowDown') {
e.preventDefault();
if (historyIndex < commandHistory.length - 1) {
historyIndex++;
inputEl.value = commandHistory[historyIndex];
} else {
historyIndex = commandHistory.length;
inputEl.value = '';
}
} else if (e.ctrlKey && e.key.toLowerCase() === 'l') {
e.preventDefault();
cmdClear();
}
});
// ── Click to Focus ─────────────────────────────────────
container.addEventListener('click', function () {
inputEl.focus();
});
// ── Initial Banner ─────────────────────────────────────
printBanner();
inputEl.focus();
}
};