diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000000..ee4db01f5a
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,43 @@
+name: LCOS Static Checks
+
+on:
+ pull_request:
+ push:
+ branches-ignore: [master]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ static-checks:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ - name: Validate JavaScript syntax
+ run: node --check app.js
+
+ - name: Validate required files and references
+ shell: bash
+ run: |
+ set -euo pipefail
+ test -f index.html
+ test -f styles.css
+ test -f app.js
+ test -f README.md
+ test -f .nojekyll
+ for image in \
+ screenshots/lcos-01-shot-boot.png \
+ screenshots/lcos-01-shot-refractainstaller.png \
+ screenshots/lcos-01-shot1.png \
+ screenshots/lcos-01-shot2.png \
+ screenshots/lcos-01-shot3.png \
+ screenshots/lcos-01-shot4.png; do
+ test -f "$image"
+ grep -q "$image" index.html
+ done
+ grep -q 'href="styles.css"' index.html
+ grep -q 'src="app.js"' index.html
+ grep -q 'This site is satire' index.html
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
new file mode 100644
index 0000000000..19e13df188
--- /dev/null
+++ b/.github/workflows/pages.yml
@@ -0,0 +1,56 @@
+name: Deploy LCOS to GitHub Pages
+
+on:
+ push:
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: pages
+ cancel-in-progress: true
+
+jobs:
+ deploy:
+ if: github.event_name == 'workflow_dispatch' || github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ - name: Validate JavaScript syntax
+ run: node --check app.js
+
+ - name: Validate static assets
+ shell: bash
+ run: |
+ set -euo pipefail
+ test -f index.html
+ test -f styles.css
+ test -f app.js
+ test -f screenshots/lcos-01-shot-boot.png
+ test -f screenshots/lcos-01-shot-refractainstaller.png
+ test -f screenshots/lcos-01-shot1.png
+ test -f screenshots/lcos-01-shot2.png
+ test -f screenshots/lcos-01-shot3.png
+ test -f screenshots/lcos-01-shot4.png
+ grep -q 'styles.css' index.html
+ grep -q 'app.js' index.html
+
+ - name: Configure Pages
+ uses: actions/configure-pages@v5
+
+ - name: Upload static site
+ uses: actions/upload-pages-artifact@v4
+ with:
+ path: .
+
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.nojekyll b/.nojekyll
new file mode 100644
index 0000000000..34ea1239a6
--- /dev/null
+++ b/.nojekyll
@@ -0,0 +1 @@
+# Static LCOS Pages site; intentionally no Jekyll processing.
diff --git a/README.md b/README.md
index 8f9d677b5d..c0032eca78 100644
--- a/README.md
+++ b/README.md
@@ -1,41 +1,28 @@
-# The Lunduke Computer Operating System
+# LCOS — The Operating System We Absolutely Did Not Build
-A Linux system built by Lunduke, for Lunduke.
+> **Satire fork / browser visualization. This is not a Linux distribution. There is no ISO.**
-
+LCOS is an interactive GitHub Pages mock desktop imagining what the Lunduke Computer Operating System could look like if screenshots, Linux discourse, and far too much confidence achieved sentience.
-The Lunduke Computer Operating System (LCOS) adheres to a core set of ideas:
+## Live site
-- No Age or ID Verification.
-- No Online Accounts Needed.
-- No AI.
-- No Weird Politics.
-- No Systemd.
-- No Forced Rust Clones.
-- Modern Tech. 90s UI.
+https://qsolkcb.github.io/LCOS/
-LCOS is built on top of Devuan (a high quality fork of Debian, which removes Systemd), and includes carefully selected software to adhere to those core ideals (including the stripped-down Brave Origin as the default web browser).
+## Included
-## The Lunduke Computer Operating System is a Monarchy.
+- fake boot sequence and LCDE browser desktop
+- draggable, minimizable and maximizable windows
+- interactive terminal and `.debate` package manager
+- parody Issue Control Center
+- Ethics Daemon based on `CodeOfEthics.md`
+- gallery preserving the existing screenshots
+- GitHub Pages deployment and static-site CI
+- absolutely no actual distro
-LCOS is not a community project. The King has total control, both technologically and organizationally. This prevents Political Activists from seizing control, as has happened with so many other Open Source projects and organizations.
+## Run locally
-## Upstream First
+```bash
+python3 -m http.server 8000
+```
-LCOS tries to avoid LCOS-only code changes whenever possible, perfering to ship "vanilla" versions of upstream projects. When changes or fixes are required for LCOS, in upstream projects, the preference is to hire developers of that upstream project to implement those changes in upstream itself. That way everyone can benefit from the work being done while, simultaneously, supporting the work of engineeers who make all of this possible.
-
-As such, source code deviations, from upstream projects, is kept to an absolute minimum in LCOS. All modified source code, primarily in the form of [LCOS-specific packages](https://github.com/BryanLunduke/LCOS-Branding), are published and made available.
-
-## Early Development
-
-LCOS is in early development. Expect bugs.
-
-[The Lunduke Journal Forum](https://forum.lunduke.com/) is the exclusive place to ask questions, provide suggestions, report issues, or talk with other LCOS users. To keep trolls away, [this forum](https://forum.lunduke.com/) is only available to [Lunduke Journal subscribers](https://lunduke.com/).
-
-## Screenshots
-
-
-
-
-
-
+**This repository and website are satire.**
\ No newline at end of file
diff --git a/app.js b/app.js
new file mode 100644
index 0000000000..790262a293
--- /dev/null
+++ b/app.js
@@ -0,0 +1,416 @@
+(() => {
+ 'use strict';
+
+ const $ = (selector, root = document) => root.querySelector(selector);
+ const $$ = (selector, root = document) => [...root.querySelectorAll(selector)];
+
+ const boot = $('#boot');
+ const desktop = $('#desktop');
+ const bootLog = $('#bootLog');
+ const skipBoot = $('#skipBoot');
+ const appsButton = $('#applicationsButton');
+ const appsMenu = $('#applicationsMenu');
+ const taskButtons = $('#taskButtons');
+ const toast = $('#toast');
+ const clock = $('#clock');
+
+ let zCounter = 500;
+ let toastTimer;
+ let updateCheckTimer;
+ let bootFinished = false;
+
+ const bootLines = [
+ '[ 0.000000] LCOS BIOS: locating opinions... found 47',
+ '[ 0.041337] Loading kernel: vibes-6.9.420-lcos',
+ '[ 0.071000] Detecting hardware: beige tower preferred, modern hardware tolerated',
+ '[ 0.112358] Starting meritocracy-daemon.service [ OK ]',
+ '[ 0.161803] Mounting /home [ OK ]',
+ '[ 0.200000] Mounting /dev/null for telemetry [ OK ]',
+ '[ 0.271828] Negotiating X11/Wayland peace treaty [ FAILED ]',
+ '[ 0.314159] Falling back to strongly held opinions [ OK ]',
+ '[ 0.404000] Checking swear jar filesystem [ CLEAN ]',
+ '[ 0.512000] Initializing package format .debate [ OK ]',
+ '[ 0.640000] Starting desktop environment: LCDE',
+ '[ 0.777777] WARNING: this is a website, not an operating system.',
+ '[ 1.000000] Welcome to LCOS. Please keep all discourse inside the viewport.'
+ ];
+
+ function showToast(message, duration = 3200) {
+ clearTimeout(toastTimer);
+ toast.textContent = message;
+ toast.hidden = false;
+ toastTimer = setTimeout(() => { toast.hidden = true; }, duration);
+ }
+
+ function finishBoot() {
+ if (bootFinished) return;
+ bootFinished = true;
+ boot.hidden = true;
+ desktop.hidden = false;
+ openWindow('aboutWindow');
+ updateClock();
+ setInterval(updateClock, 1000);
+ }
+
+ async function runBoot() {
+ const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
+ if (reduceMotion) {
+ bootLog.textContent = bootLines.join('\n');
+ finishBoot();
+ return;
+ }
+
+ for (const line of bootLines) {
+ if (bootFinished) break;
+ bootLog.textContent += `${line}\n`;
+ bootLog.scrollTop = bootLog.scrollHeight;
+ await new Promise(resolve => setTimeout(resolve, 125 + Math.random() * 110));
+ }
+ await new Promise(resolve => setTimeout(resolve, 380));
+ finishBoot();
+ }
+
+ function updateClock() {
+ const now = new Date();
+ clock.textContent = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
+ clock.title = now.toLocaleString();
+ }
+
+ function titleFor(win) {
+ return $('.window-title', win)?.textContent?.trim() || win.id;
+ }
+
+ function ensureTaskButton(win) {
+ let button = taskButtons.querySelector(`[data-task-for="${win.id}"]`);
+ if (!button) {
+ button = document.createElement('button');
+ button.className = 'task-button';
+ button.type = 'button';
+ button.dataset.taskFor = win.id;
+ button.textContent = titleFor(win);
+ button.addEventListener('click', () => {
+ if (win.hidden) openWindow(win.id);
+ else if (win.classList.contains('active-window')) minimizeWindow(win);
+ else focusWindow(win);
+ });
+ taskButtons.append(button);
+ }
+ button.classList.toggle('active', !win.hidden && win.classList.contains('active-window'));
+ }
+
+ function syncTaskButtons() {
+ $$('.window').forEach(win => {
+ const button = taskButtons.querySelector(`[data-task-for="${win.id}"]`);
+ if (!button) return;
+ button.classList.toggle('active', !win.hidden && win.classList.contains('active-window'));
+ });
+ }
+
+ function focusWindow(win) {
+ if (!win || win.hidden) return;
+ $$('.window').forEach(item => item.classList.remove('active-window'));
+ win.classList.add('active-window');
+ win.style.zIndex = String(++zCounter);
+ ensureTaskButton(win);
+ syncTaskButtons();
+ }
+
+ function focusOpenedWindow(win) {
+ if (!win.hasAttribute('tabindex')) win.tabIndex = -1;
+ const target = win.id === 'terminalWindow'
+ ? $('#terminalInput', win)
+ : $('.window-body input, .window-body button, .window-body a[href]', win) || win;
+ setTimeout(() => target?.focus(), 0);
+ }
+
+ function openWindow(id) {
+ const win = document.getElementById(id);
+ if (!win) return;
+ win.hidden = false;
+ ensureTaskButton(win);
+ focusWindow(win);
+ appsMenu.hidden = true;
+ appsButton.setAttribute('aria-expanded', 'false');
+ focusOpenedWindow(win);
+ }
+
+ function closeWindow(win) {
+ win.hidden = true;
+ win.classList.remove('active-window');
+ const button = taskButtons.querySelector(`[data-task-for="${win.id}"]`);
+ button?.remove();
+ const visible = $$('.window').filter(item => !item.hidden);
+ if (visible.length) focusWindow(visible.sort((a, b) => (+b.style.zIndex || 0) - (+a.style.zIndex || 0))[0]);
+ }
+
+ function minimizeWindow(win) {
+ win.hidden = true;
+ win.classList.remove('active-window');
+ ensureTaskButton(win);
+ syncTaskButtons();
+ }
+
+ function toggleMaximize(win) {
+ win.classList.toggle('maximized');
+ focusWindow(win);
+ }
+
+ function toggleApplicationsMenu() {
+ appsMenu.hidden = !appsMenu.hidden;
+ appsButton.setAttribute('aria-expanded', String(!appsMenu.hidden));
+ }
+
+ function makeDraggable(win) {
+ const titlebar = $('.window-titlebar', win);
+ if (!titlebar) return;
+
+ let drag = null;
+
+ titlebar.addEventListener('pointerdown', event => {
+ if (event.target.closest('button') || win.classList.contains('maximized') || innerWidth <= 900) return;
+ focusWindow(win);
+ const rect = win.getBoundingClientRect();
+ drag = { x: event.clientX - rect.left, y: event.clientY - rect.top };
+ titlebar.setPointerCapture(event.pointerId);
+ event.preventDefault();
+ });
+
+ titlebar.addEventListener('pointermove', event => {
+ if (!drag) return;
+ const maxX = Math.max(0, innerWidth - win.offsetWidth);
+ const maxY = Math.max(42, innerHeight - win.offsetHeight - 48);
+ const x = Math.min(maxX, Math.max(0, event.clientX - drag.x));
+ const y = Math.min(maxY, Math.max(42, event.clientY - drag.y));
+ win.style.left = `${x}px`;
+ win.style.top = `${y}px`;
+ win.style.setProperty('--x', `${x}px`);
+ win.style.setProperty('--y', `${y}px`);
+ });
+
+ const endDrag = event => {
+ if (!drag) return;
+ drag = null;
+ try { titlebar.releasePointerCapture(event.pointerId); } catch (_) { /* already released */ }
+ };
+
+ titlebar.addEventListener('pointerup', endDrag);
+ titlebar.addEventListener('pointercancel', endDrag);
+ titlebar.addEventListener('dblclick', event => {
+ if (!event.target.closest('button')) toggleMaximize(win);
+ });
+ }
+
+ function panicAboutSystemd() {
+ appsMenu.hidden = true;
+ appsButton.setAttribute('aria-expanded', 'false');
+ showToast('SYSTEMD DETECTED: beginning a calm, proportionate 47-minute panel discussion.', 5200);
+ openWindow('terminalWindow');
+ appendTerminal('root@lcos:~# systemctl enable common-sense.target', 'term-bad');
+ appendTerminal('Failed: dependency "internet-consensus.service" does not exist.', 'term-gold');
+ }
+
+ function appendTerminal(text, className = '') {
+ const output = $('#terminalOutput');
+ const line = document.createElement('div');
+ if (className) line.className = className;
+ line.textContent = text;
+ output.append(line);
+ output.scrollTop = output.scrollHeight;
+ }
+
+ const terminalCommands = {
+ help() {
+ appendTerminal('Available commands: help, about, uname -a, neofetch, ls, apt update, sudo, systemctl, wayland, x11, ethics, clear, reboot, exit', 'term-dim');
+ },
+ about() {
+ appendTerminal('LCOS Browser Visualization Edition — a satire fork. No ISO. No installer. No warranty. Considerable confidence.');
+ },
+ 'uname -a'() {
+ appendTerminal('Linux lcos 6.9.420-lcos #1 SMP PREEMPT_DYNAMIC SatireOS x86_64 GNU/Linux');
+ },
+ neofetch() {
+ appendTerminal(' LLLLL trent@lcos');
+ appendTerminal(' L ---------');
+ appendTerminal(' L OS: LCOS Browser Edition');
+ appendTerminal(' L Kernel: vibes-6.9.420');
+ appendTerminal(' LLLLLLL Shell: bash-with-opinions');
+ appendTerminal(' DE: LCDE');
+ appendTerminal(' Packages: 5 (.debate)');
+ appendTerminal(' Uptime: longer than expected');
+ },
+ ls() {
+ appendTerminal('Desktop Documents screenshots opinions README.md absolutely-not-an-iso.iso', 'term-good');
+ },
+ 'apt update'() {
+ appendTerminal('Hit:1 https://mirror.invalid stable InRelease');
+ appendTerminal('Get:2 discourse://localhost opinions [47 MB]');
+ appendTerminal('Reading package lists... Done');
+ appendTerminal('3 packages can be upgraded. 38 arguments can be restarted.', 'term-gold');
+ },
+ sudo() {
+ appendTerminal('trent is not in the sudoers file. This incident will be discussed on a podcast.', 'term-bad');
+ },
+ systemctl() {
+ appendTerminal('systemd-opinion-generator.service is active (running) despite multiple objections.', 'term-gold');
+ },
+ wayland() {
+ appendTerminal('wayland: command acknowledged. Desktop immediately split into two mailing lists.', 'term-bad');
+ },
+ x11() {
+ appendTerminal('X.Org Server 21.1.∞ — if it was good enough for 1987, it can probably open xterm.', 'term-good');
+ },
+ ethics() {
+ openWindow('ethicsWindow');
+ appendTerminal('Ethics daemon opened. Please remain excellent.', 'term-good');
+ },
+ clear() {
+ $('#terminalOutput').replaceChildren();
+ },
+ reboot() {
+ appendTerminal('Reboot denied: this is JavaScript and we are trying to maintain standards.', 'term-bad');
+ },
+ exit() {
+ minimizeWindow($('#terminalWindow'));
+ }
+ };
+
+ function executeTerminal(raw) {
+ const command = raw.trim();
+ if (!command) return;
+ appendTerminal(`trent@lcos:~$ ${command}`);
+ const normalized = command.toLowerCase().replace(/\s+/g, ' ');
+
+ if (terminalCommands[normalized]) {
+ terminalCommands[normalized]();
+ return;
+ }
+
+ if (normalized.startsWith('sudo ')) {
+ terminalCommands.sudo();
+ return;
+ }
+
+ if (normalized.startsWith('systemctl ')) {
+ terminalCommands.systemctl();
+ return;
+ }
+
+ appendTerminal(`bash: ${command}: command not found. Have you considered filing an issue about it?`, 'term-bad');
+ }
+
+ function initTerminal() {
+ const form = $('#terminalForm');
+ const input = $('#terminalInput');
+ appendTerminal('LCOS terminal 0.1. Type "help". Please do not attempt actual administration.', 'term-gold');
+ form.addEventListener('submit', event => {
+ event.preventDefault();
+ executeTerminal(input.value);
+ input.value = '';
+ });
+ }
+
+ function initPackageManager() {
+ const log = $('#updateLog');
+ const summary = $('#updateSummary');
+
+ $('#checkUpdates').addEventListener('click', () => {
+ clearTimeout(updateCheckTimer);
+ summary.textContent = 'Checking mirrors and prevailing sentiment…';
+ log.textContent = 'Contacting mirror.invalid...\nReading package lists...\nCross-referencing comments...\nIgnoring one guy who suggested Electron...\n\n3 updates found; 1 package held due to ideological conflict.';
+ updateCheckTimer = setTimeout(() => {
+ updateCheckTimer = null;
+ summary.textContent = '3 updates available; 1 eternal argument held back';
+ showToast('Updates checked. Your computer is now 12% more aware of discourse.');
+ }, 650);
+ });
+
+ $('#applyUpdates').addEventListener('click', () => {
+ clearTimeout(updateCheckTimer);
+ updateCheckTimer = null;
+ log.textContent = 'Preparing upgrade...\nInstalling no-cursin-filter 1.5... OK\nInstalling lcos-base 0.1.1... OK\nRestarting meritocracy-daemon... OK\nHolding systemd-opinion-generator... obviously\n\nDone. Reboot strongly discouraged because this is a webpage.';
+ summary.textContent = 'System is completely up to date, spiritually';
+ showToast('Upgrade complete. Zero real packages were modified.');
+ });
+ }
+
+ function initEthics() {
+ const input = $('#ethicsInput');
+ const result = $('#ethicsResult');
+ const forbidden = /\b(fuck|shit|cunt|bastard|damn|bloody hell)\b/i;
+
+ $('#ethicsCheck').addEventListener('click', () => {
+ const value = input.value.trim();
+ if (!value) {
+ result.textContent = 'Nothing entered. Ethics daemon awards points for restraint.';
+ } else if (forbidden.test(value)) {
+ result.textContent = '⚠ CURSIN\' DETECTED. One virtual coin deposited in the kernel swear jar.';
+ } else {
+ result.textContent = '✓ Excellent. Meritocracy daemon reluctantly approves this sentence.';
+ }
+ });
+
+ input.addEventListener('keydown', event => {
+ if (event.key === 'Enter') $('#ethicsCheck').click();
+ });
+ }
+
+ appsButton.addEventListener('click', event => {
+ event.stopPropagation();
+ toggleApplicationsMenu();
+ });
+
+ document.addEventListener('click', event => {
+ if (!event.target.closest('#applicationsMenu') && !event.target.closest('#applicationsButton')) {
+ appsMenu.hidden = true;
+ appsButton.setAttribute('aria-expanded', 'false');
+ }
+ });
+
+ $$('[data-open]').forEach(button => {
+ button.addEventListener('click', () => openWindow(button.dataset.open));
+ });
+
+ $$('[data-action="panic"]').forEach(button => button.addEventListener('click', panicAboutSystemd));
+
+ $$('.window').forEach(win => {
+ makeDraggable(win);
+ win.addEventListener('pointerdown', () => focusWindow(win));
+
+ const closeButton = $('[data-close]', win);
+ const minimizeButton = $('[data-minimize]', win);
+ const maximizeButton = $('[data-maximize]', win);
+
+ closeButton?.setAttribute('aria-label', 'Close');
+ minimizeButton?.setAttribute('aria-label', 'Minimize');
+ maximizeButton?.setAttribute('aria-label', 'Maximize');
+
+ closeButton?.addEventListener('click', () => closeWindow(win));
+ minimizeButton?.addEventListener('click', () => minimizeWindow(win));
+ maximizeButton?.addEventListener('click', () => toggleMaximize(win));
+ });
+
+ $('#showDesktop').addEventListener('click', () => {
+ const visible = $$('.window').filter(win => !win.hidden);
+ if (visible.length) {
+ visible.forEach(minimizeWindow);
+ showToast('Desktop shown. Productivity has been minimized.');
+ } else {
+ openWindow('aboutWindow');
+ }
+ });
+
+ clock.addEventListener('click', () => showToast(`Current LCOS time: ${new Date().toLocaleString()}. Still no RTC driver drama.`));
+ skipBoot.addEventListener('click', finishBoot);
+
+ window.addEventListener('keydown', event => {
+ if (event.key === 'Escape') {
+ appsMenu.hidden = true;
+ appsButton.setAttribute('aria-expanded', 'false');
+ }
+ });
+
+ initTerminal();
+ initPackageManager();
+ initEthics();
+ runBoot();
+})();
diff --git a/index.html b/index.html
new file mode 100644
index 0000000000..22f6c49307
--- /dev/null
+++ b/index.html
@@ -0,0 +1,196 @@
+
+
+
+
+
+
+
+ LCOS — The Operating System We Absolutely Did Not Build
+
+
+
+
+ LCOS requires JavaScript because apparently even satire has dependencies now.
+
+
+
+
+
LCOS
+
+
skip ceremonial boot
+
+
+
+
+
+
+
+
+
+
+
+ 🖥️ About LCOS
+ ⌨️ Terminal
+ 📦 Updates
+ 🔥 Issues
+ 🖼️ Screenshots
+ 📜 Ethics
+
+
+
+
+
About LCOS
+
+ —
+ □
+ ×
+
+
+
+
+
LCOS
+
+
The Lunduke Computer Operating System*
+
*This site is satire. It is a browser visualization. It is not a Linux distribution and will not repartition your toaster.
+
+
+
+
Kernel Vibes 6.9.420-lcos
+
Init Argument Pending
+
Desktop LCDE (Lunduke Computer Desktop Environment)
+
Package format .debate
+
Release model Rolling Commentary
+
Support window Until the next video
+
+
+ Mission statement: visualize what LCOS could look like if a README, six screenshots, a GitHub issue tracker and approximately eleven gallons of Linux discourse achieved sentience.
+
+
+
+
+
+
+
+
trent@lcos: ~
+
+ — □ ×
+
+
+
+
+
+
+
+
LCOS Package Manager — Definitely Stable
+
— □ ×
+
+
+
Check for Updates Apply Everything Recklessly Package database last emotionally refreshed: recently
+
+
lcos-base Core philosophical dependencies
0.1 → 0.1.1 RECOMMENDED
+
meritocracy-daemon Ranks packages entirely by how confidently they compile
3.0 → 3.0 CURRENT
+
no-cursin-filter Kernel-space swear jar
1.4 → 1.5 SECURITY
+
systemd-opinion-generator Generates a 47-minute response before PID 1 starts
∞ → ∞+1 HELD
+
x11-forever Because changing display servers is how civilization ends
1984 → 1984 PINNED
+
+
Ready. No package manager was harmed in the making of this page.
+
+
+
+
+
+
Issue Control Center
+
— □ ×
+
+
+
Project health: 97% opinions, 3% shell scripts. Everything is proceeding according to somebody's plan.
+
+
OPEN
+
#001 Should the installer ask which decade your desktop belongs to? Consensus blocked by somebody mentioning Wayland.
+
#002 Feature request: package manager should audibly sigh Accepted pending an ALSA/PulseAudio/PipeWire argument.
+
#003 Bug: user attempted to enjoy computing Cannot reproduce. Please provide logs and political alignment.
+
+
IN REVIEW
+
PR #004 Replace splash screen with 640×480 BMP Reviewer requested less modern typography.
+
PR #005 Add “Be Excellent” system call API bikeshedding currently at 84 comments.
+
+
WONTFIX
+
#006 Add telemetry Reporter has been escorted to /dev/null.
+
#007 Make it an actual distro Absolutely not. That would ruin the joke.
+
+
+
This panel is parody, not a mirror of real GitHub issues. The actual upstream project and discussion remain available on GitHub.
+
+
+
+
+
+
+
System-wide behavioral policy
+
The fork inherits a wonderfully compact social contract from CodeOfEthics.md:
+
✓ Be Excellent to Each Other.
✓ No Cursin' or Swearin'.
✓ Meritocracy Rules.
+
+
Test the no-cursin' filter:
+
Inspect
+
Daemon idle. Morality load average: 0.03.
+
+
This page is comedic UI around text already present in the repository; it is not a statement of QSOL policy.
+
+
+
+
+ Historical Evidence — Existing LCOS Screenshots — □ ×
+
+
+
Boot: where confidence begins.
+
Installer: choices were made.
+
Desktop specimen #1
+
Desktop specimen #2
+
Desktop specimen #3
+
Desktop specimen #4
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/styles-base.css b/styles-base.css
new file mode 100644
index 0000000000..0563f8bea1
--- /dev/null
+++ b/styles-base.css
@@ -0,0 +1,211 @@
+:root {
+ color-scheme: dark;
+ --panel: #191919;
+ --panel-2: #242424;
+ --window: #eeeeea;
+ --window-text: #171717;
+ --edge: #444;
+ --accent: #d6b45f;
+ --accent-2: #b98d31;
+ --danger: #b94b4b;
+ --shadow: 0 18px 55px rgba(0,0,0,.42);
+ --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
+ --sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+}
+
+* { box-sizing: border-box; }
+html, body { width: 100%; min-height: 100%; margin: 0; }
+body { overflow: hidden; font-family: var(--sans); background: #111; color: #eee; }
+button, input { font: inherit; }
+button { cursor: pointer; }
+a { color: inherit; }
+
+.noscript {
+ position: fixed; inset: 0; z-index: 9999; display: grid; place-items: center;
+ background: #111; color: #eee; padding: 2rem; font-family: var(--mono); text-align: center;
+}
+
+.boot-screen {
+ position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center;
+ background: radial-gradient(circle at 50% 42%, #202020 0, #0b0b0b 58%, #000 100%);
+ font-family: var(--mono);
+}
+.boot-terminal {
+ width: min(900px, 90vw); min-height: 540px; padding: 44px;
+ border: 1px solid #383838; background: rgba(4,4,4,.84); box-shadow: 0 30px 90px rgba(0,0,0,.8);
+}
+.boot-logo { font: 900 clamp(3rem, 9vw, 7rem)/.9 var(--sans); letter-spacing: -.08em; color: var(--accent); margin-bottom: 32px; }
+#bootLog { min-height: 300px; white-space: pre-wrap; line-height: 1.55; color: #d8d8d0; margin: 0; }
+.boot-skip { margin-top: 22px; border: 1px solid #555; color: #aaa; background: #111; padding: 8px 12px; }
+.boot-skip:hover { color: #fff; border-color: #888; }
+
+.desktop {
+ position: fixed; inset: 0; overflow: hidden;
+ background:
+ linear-gradient(115deg, rgba(12,12,12,.08), rgba(245,219,150,.03)),
+ radial-gradient(circle at 68% 37%, #5c5547 0, #38352f 24%, #201f1c 52%, #121212 83%);
+}
+.wallpaper-noise {
+ pointer-events: none; position: absolute; inset: 0; opacity: .12;
+ background-image: repeating-linear-gradient(0deg, rgba(255,255,255,.035) 0 1px, transparent 1px 4px);
+ mix-blend-mode: overlay;
+}
+.desktop::after {
+ content: "LCOS"; position: absolute; right: 4vw; bottom: 9vh; color: rgba(255,255,255,.035);
+ font-size: clamp(7rem, 22vw, 22rem); line-height: .8; font-weight: 950; letter-spacing: -.09em; pointer-events: none;
+}
+
+.top-panel, .taskbar {
+ position: absolute; left: 0; right: 0; z-index: 800; display: flex; align-items: center;
+ background: rgba(20,20,20,.96); border-color: #373737; box-shadow: 0 2px 12px rgba(0,0,0,.28);
+}
+.top-panel { top: 0; height: 42px; border-bottom: 1px solid #353535; }
+.taskbar { bottom: 0; min-height: 48px; border-top: 1px solid #3b3b3b; padding: 5px 8px; gap: 8px; }
+.panel-button, .clock, .start-button, .task-button {
+ border: 0; color: #eee; background: transparent; height: 100%; padding: 0 13px;
+}
+.panel-button:hover, .clock:hover, .start-button:hover, .task-button:hover { background: #333; }
+.brand-button { display: flex; gap: 9px; align-items: center; font-weight: 700; }
+.brand-mark {
+ display: inline-grid; place-items: center; width: 25px; height: 25px; border-radius: 4px; background: var(--accent); color: #111; font-weight: 950;
+}
+.brand-mark.small { width: 24px; height: 24px; }
+.panel-title { flex: 1; text-align: center; color: #aaa; font-size: 13px; letter-spacing: .02em; }
+.panel-status { display: flex; align-items: center; gap: 16px; height: 100%; font: 12px var(--mono); color: #bebebe; }
+.clock { font-family: var(--mono); color: #fff; }
+
+.applications-menu {
+ position: absolute; z-index: 900; top: 42px; left: 7px; width: 300px; padding: 9px;
+ background: rgba(30,30,30,.98); border: 1px solid #4b4b4b; box-shadow: var(--shadow);
+}
+.menu-heading { padding: 11px 12px; color: var(--accent); font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .12em; }
+.menu-item { width: 100%; display: flex; gap: 12px; align-items: center; padding: 11px 12px; border: 0; background: transparent; color: #eee; text-align: left; }
+.menu-item:hover { background: #414141; }
+.menu-item.danger:hover { background: #642c2c; }
+
+.desktop-icons {
+ position: absolute; z-index: 20; top: 62px; left: 18px; display: grid; grid-template-columns: repeat(1, 92px); gap: 14px;
+}
+.desktop-icon {
+ display: grid; justify-items: center; gap: 4px; width: 92px; min-height: 76px; border: 1px solid transparent; border-radius: 5px;
+ background: transparent; color: #f4f4f4; padding: 6px; text-shadow: 0 2px 4px #000; font-size: 12px;
+}
+.desktop-icon:hover, .desktop-icon:focus { background: rgba(255,255,255,.09); border-color: rgba(255,255,255,.15); outline: none; }
+.icon-glyph { font-size: 34px; filter: drop-shadow(0 3px 5px rgba(0,0,0,.55)); }
+
+.window {
+ position: absolute; z-index: 100; left: var(--x); top: var(--y); width: min(var(--w), calc(100vw - 30px)); height: min(var(--h), calc(100vh - 100px));
+ border: 1px solid #5d5d5d; background: var(--window); color: var(--window-text); box-shadow: var(--shadow); overflow: hidden; resize: both;
+ min-width: min(340px, calc(100vw - 16px)); min-height: 240px;
+}
+.window.maximized { left: 0 !important; top: 42px !important; width: 100vw !important; height: calc(100vh - 90px) !important; resize: none; }
+.window.active-window { z-index: 500; }
+.window-titlebar {
+ height: 34px; display: flex; align-items: center; justify-content: space-between; padding-left: 11px;
+ background: linear-gradient(#333, #252525); color: #eee; user-select: none; cursor: move; border-bottom: 1px solid #111;
+}
+.window-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 650; }
+.window-controls { height: 100%; display: flex; }
+.window-controls button { width: 40px; border: 0; border-left: 1px solid #424242; background: transparent; color: #ddd; font-size: 16px; }
+.window-controls button:hover { background: #555; }
+.window-controls button:last-child:hover { background: #a83838; }
+.window-body { height: calc(100% - 34px); overflow: auto; padding: 22px; }
+
+.about-body { background: #f1f0eb; }
+.hero-card { display: grid; grid-template-columns: 120px 1fr; gap: 22px; align-items: center; margin-bottom: 20px; }
+.hero-logo { width: 112px; height: 112px; display: grid; place-items: center; border-radius: 18px; background: #222; color: var(--accent); font-weight: 950; font-size: 33px; letter-spacing: -.06em; box-shadow: inset 0 0 0 1px #444; }
+h1, h2, h3, p { margin-top: 0; }
+h1 { font-size: 27px; margin-bottom: 8px; line-height: 1.08; letter-spacing: -.035em; }
+.asterisk { font-size: 12px; line-height: 1.5; color: #646464; }
+.spec-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border: 1px solid #cac8c0; background: #fff; }
+.spec-grid > div { padding: 12px; border-right: 1px solid #dedcd5; border-bottom: 1px solid #dedcd5; display: flex; flex-direction: column; gap: 3px; }
+.spec-grid strong { font-size: 11px; color: #777; text-transform: uppercase; letter-spacing: .07em; }
+.spec-grid span { font: 13px var(--mono); }
+.callout { margin: 18px 0; padding: 14px 16px; border-left: 4px solid var(--accent-2); background: #e5e0d3; line-height: 1.5; }
+.button-row { display: flex; gap: 8px; flex-wrap: wrap; }
+.button-row button, .button-link, .toolbar button, .ethics-test button {
+ border: 1px solid #9f9f98; background: #e5e5df; color: #222; padding: 8px 12px; text-decoration: none; border-radius: 3px;
+}
+.button-row button:hover, .button-link:hover, .toolbar button:hover, .ethics-test button:hover { background: #d7d7d0; }
+button.primary, .button-row .primary { background: #3a3935; color: #fff; border-color: #222; }
+button.primary:hover { background: #252421; }
+
+.terminal-body { padding: 0; display: flex; flex-direction: column; background: #080808; color: #e9e6da; font: 13px/1.55 var(--mono); }
+.terminal-output { flex: 1; overflow: auto; padding: 15px 17px 4px; white-space: pre-wrap; }
+.terminal-line { display: flex; align-items: center; gap: 8px; padding: 0 17px 14px; }
+.prompt { color: var(--accent); white-space: nowrap; }
+.terminal-line input { flex: 1; border: 0; outline: 0; background: transparent; color: #fff; font-family: var(--mono); }
+.term-dim { color: #8e8e8e; }
+.term-good { color: #a7c98b; }
+.term-bad { color: #e38b80; }
+.term-gold { color: #e1c470; }
+
+.package-body { padding: 0; background: #eeede8; }
+.toolbar { position: sticky; top: 0; z-index: 1; display: flex; gap: 8px; align-items: center; padding: 12px; background: #d9d8d2; border-bottom: 1px solid #bab9b2; }
+.toolbar-note { margin-left: auto; color: #686861; font-size: 11px; }
+.package-list { padding: 12px; display: grid; gap: 7px; }
+.package { display: grid; grid-template-columns: 1fr auto auto; gap: 14px; align-items: center; padding: 12px; border: 1px solid #cac8c0; background: #faf9f5; }
+.package div { display: flex; flex-direction: column; gap: 2px; }
+.package small { color: #696963; }
+.version { font: 12px var(--mono); color: #555; }
+.badge { padding: 3px 7px; background: #ddd; color: #555; border-radius: 20px; font-size: 9px; font-weight: 800; }
+.badge.recommended { background: #dce7ca; color: #466127; }
+.danger-badge { background: #edd0cc; color: #7b3028; }
+.mini-log { margin: 0 12px 12px; padding: 12px; background: #171717; color: #d9d6ca; min-height: 80px; font: 11px/1.5 var(--mono); white-space: pre-wrap; }
+
+.issues-body { background: #eceae4; }
+.issue-banner { padding: 12px 14px; margin-bottom: 14px; background: #d9d3c4; border: 1px solid #c1b8a0; }
+.issue-columns { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; align-items: start; }
+.issue-column { background: #dddcd6; padding: 9px; min-height: 360px; }
+.issue-column h3 { margin: 4px 4px 10px; font-size: 11px; letter-spacing: .12em; color: #65655f; }
+.issue-card { background: #fff; border-top: 3px solid #718662; padding: 11px; margin-bottom: 9px; box-shadow: 0 1px 3px rgba(0,0,0,.08); }
+.issue-card.amber { border-top-color: #b18d3c; }
+.issue-card.red { border-top-color: #a55148; }
+.issue-card span { font: 10px var(--mono); color: #777; }
+.issue-card strong { display: block; margin: 6px 0; line-height: 1.3; font-size: 13px; }
+.issue-card p { margin: 0; color: #666; font-size: 11px; line-height: 1.4; }
+.source-note { margin: 13px 0 0; color: #666; font-size: 11px; }
+
+.ethics-body { background: #efeee9; }
+.ethics-rules { display: grid; gap: 8px; margin: 18px 0; }
+.ethics-rules div { padding: 12px 14px; border: 1px solid #cbc8bd; background: #fff; font-weight: 700; }
+.ethics-console { margin: 20px 0; padding: 16px; background: #1a1a1a; color: #eee; font-family: var(--mono); }
+.ethics-console label { display: block; margin-bottom: 10px; color: var(--accent); }
+.ethics-test { display: flex; gap: 8px; }
+.ethics-test input { flex: 1; min-width: 0; padding: 8px 10px; border: 1px solid #555; background: #080808; color: #fff; font-family: var(--mono); }
+#ethicsResult { margin: 12px 0 0; color: #bdbdb5; }
+
+.gallery-body { background: #1f1f1f; padding: 14px; }
+.gallery-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
+.gallery-grid figure { margin: 0; padding: 8px; background: #101010; border: 1px solid #393939; }
+.gallery-grid img { display: block; width: 100%; height: auto; background: #000; }
+.gallery-grid figcaption { padding: 7px 2px 1px; color: #bbb; font-size: 11px; }
+
+.task-buttons { display: flex; gap: 5px; flex: 1; min-width: 0; overflow-x: auto; }
+.task-button { height: 36px; max-width: 190px; border: 1px solid #454545; background: #282828; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
+.task-button.active { border-color: #8a7748; background: #423b2d; }
+.start-button { height: 36px; display: flex; align-items: center; gap: 7px; border-right: 1px solid #444; font-weight: 700; }
+.taskbar-joke { padding: 0 10px; color: #777; font-size: 10px; white-space: nowrap; }
+
+.toast {
+ position: absolute; z-index: 950; right: 20px; bottom: 68px; max-width: min(420px, calc(100vw - 40px)); padding: 13px 15px;
+ background: #191919; color: #eee; border: 1px solid #555; border-left: 4px solid var(--accent); box-shadow: var(--shadow); font-size: 12px;
+}
+
+@media (max-width: 900px) {
+ .panel-title, .panel-status > span, .taskbar-joke { display: none; }
+ .panel-status { margin-left: auto; }
+ .desktop-icons { grid-template-columns: repeat(2, 82px); }
+ .window { left: 8px !important; top: 50px !important; width: calc(100vw - 16px) !important; height: calc(100vh - 108px) !important; min-width: 0; resize: none; }
+ .spec-grid, .issue-columns, .gallery-grid { grid-template-columns: 1fr; }
+ .hero-card { grid-template-columns: 80px 1fr; }
+ .hero-logo { width: 76px; height: 76px; font-size: 24px; }
+ .toolbar { flex-wrap: wrap; }
+ .toolbar-note { width: 100%; margin-left: 0; }
+ .package { grid-template-columns: 1fr auto; }
+ .package .badge { grid-column: 2; }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ *, *::before, *::after { scroll-behavior: auto !important; transition: none !important; animation: none !important; }
+}
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000000..8fe894e148
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,8 @@
+@import url("styles-base.css");
+
+/* Author styles may override the browser's default [hidden] rule.
+ LCOS uses the hidden attribute for boot overlays, windows, menus and toasts,
+ so make that contract explicit and non-negotiable. */
+[hidden] {
+ display: none !important;
+}