there current source code for my Dream Operating Environment , single file version. it's an example of what is possible with gemini.
<!--
Copyright (c) 2026 Nicholas Paul Wilde. All rights reserved.
DreamOS Server Edition - Modular Microkernel Loader
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>DreamOS Gold - Server Edition</title>
<style>
/* Basic Reset & Body */
body, html {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow: hidden;
font-family: 'Consolas', 'Courier New', monospace;
background-color: #010115; /* Dark blue background */
color: #c0c0c0;
}
/* Desktop Area */
#desktop {
position: relative;
width: 100%;
height: calc(100% - 30px); /* Full height minus taskbar */
}
/* Taskbar */
#taskbar {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 30px;
background-color: #1c1c1c;
border-top: 1px solid #444;
display: flex;
align-items: center;
padding: 0 5px;
box-sizing: border-box;
z-index: 1000;
}
#start-btn {
background-color: #333;
border: 1px solid #555;
color: white;
padding: 2px 10px;
cursor: pointer;
}
#start-menu {
position: fixed;
bottom: 30px;
left: 0;
background-color: #2a2a2a;
border: 1px solid #555;
padding: 5px;
z-index: 999;
}
#start-menu ul { list-style: none; margin: 0; padding: 0; }
#start-menu li { padding: 5px 10px; cursor: pointer; }
#start-menu li:hover { background-color: #444; }
.taskbar-divider {
width: 1px;
height: 20px;
background-color: #444;
margin: 0 10px;
}
#clock {
margin-left: auto;
padding-right: 10px;
}
#vdd-status {
padding-right: 10px;
}
/* App Windows */
.app-window {
position: absolute;
top: 50px;
left: 50px;
width: 600px;
height: 400px;
background-color: #1e1e1e;
border: 1px solid #555;
box-shadow: 5px 5px 15px rgba(0,0,0,0.5);
display: flex;
flex-direction: column;
z-index: 100;
}
.window-header {
background-color: #333;
color: white;
padding: 5px;
cursor: move; /* For future drag functionality */
display: flex;
justify-content: space-between;
align-items: center;
}
.window-controls {
display: flex;
gap: 3px;
}
.window-controls button {
background-color: #555;
color: white;
border: 1px solid #777;
width: 20px;
height: 20px;
line-height: 18px;
text-align: center;
padding: 0;
font-family: 'Consolas', 'Courier New', monospace;
cursor: pointer;
}
.window-close-btn {
background-color: #c00;
color: white;
border: none;
width: 20px;
height: 20px;
cursor: pointer;
}
.window-content {
flex-grow: 1;
padding: 10px;
overflow: auto;
display: flex;
flex-direction: column;
}
/* Terminal Specific */
#terminal-window {
width: 80vw;
height: 80vh;
top: 10vh;
left: 10vw;
}
.app-window.minimized {
display: none;
}
#output {
flex-grow: 1;
white-space: pre-wrap;
word-break: break-all;
}
#prompt {
display: flex;
}
#command-input {
flex-grow: 1;
border: none;
background: transparent;
color: #c0c0c0;
font-family: inherit;
font-size: inherit;
outline: none;
}
.prompt { color: #00aa00; }
/* Editor & IDE Specific */
.editor-area, #js-ide-code {
width: 100%;
height: 100%;
flex-grow: 1;
background-color: #282c34;
color: #abb2bf;
border: none;
font-family: inherit;
resize: none;
box-sizing: border-box;
}
.editor-toolbar, .ide-toolbar {
padding-bottom: 10px;
display: flex;
gap: 10px;
align-items: center;
}
.editor-toolbar input, .ide-toolbar input {
flex-grow: 1;
background-color: #333;
border: 1px solid #555;
color: white;
padding: 2px;
}
.editor-toolbar button, .ide-toolbar button {
background-color: #444;
border: 1px solid #666;
color: white;
padding: 2px 8px;
}
#editor-status-bar, #dreamscript-ide-output {
height: 40px;
background-color: #222;
padding: 5px;
overflow-y: auto;
margin-top: 5px;
white-space: pre-wrap;
}
/* DreamScript IDE Syntax Highlighting */
.ide-editor-container {
position: relative;
flex-grow: 1;
background-color: #282c34; /* Background on container */
}
/* Both textarea and pre need to be layered */
.ide-editor-container > textarea,
.ide-editor-container > pre {
margin: 0;
padding: 5px;
box-sizing: border-box;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
font-family: inherit;
font-size: inherit;
line-height: 1.4; /* Adjust for best line-to-line match */
white-space: pre;
word-break: normal;
overflow-wrap: break-word;
background: transparent; /* Both are transparent */
}
/* The actual textarea is on top, but its text is invisible */
#dreamscript-ide-code {
z-index: 1;
color: transparent;
caret-color: white; /* Make the cursor visible */
resize: none;
}
/* The highlighting <pre> is underneath and not interactive */
#dreamscript-ide-highlighting {
z-index: 0;
pointer-events: none;
}
/* Utility */
.hidden {
display: none !important;
}
/* Main Frame for apps */
#main-frame {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
z-index: 50;
}
#vdd-overlay {
position: fixed;
top: 0;
right: 0;
background: rgba(0,0,0,0.5);
color: lime;
padding: 2px 5px;
font-size: 10px;
z-index: 2000;
}
.app-window.maximized {
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
border: none;
box-shadow: none;
}
#taskbar-apps {
display: flex;
height: 100%;
align-items: center;
gap: 5px;
margin-left: 5px;
}
.taskbar-item {
background-color: #4a4a4a;
color: white;
padding: 4px 12px;
border: 1px solid #666;
cursor: pointer;
font-size: 12px;
white-space: nowrap;
border-radius: 2px;
}
/* Syntax highlighting colors for DreamScript */
.ds-keyword { color: #569cd6; font-weight: bold; }
.ds-string { color: #ce9178; }
.ds-comment { color: #6a9955; font-style: italic; }
.ds-linenumber { color: #608b4e; }
.ds-variable { color: #9cdcfe; }
.ds-number { color: #b5cea8; }
/* DreamScript IDE Help Window Content */
#dreamscript-help-content {
background-color: #fdfdfd;
color: #111;
padding: 15px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
}
#dreamscript-help-content h2, #dreamscript-help-content h3 {
border-bottom: 1px solid #ccc;
padding-bottom: 5px;
margin-top: 20px;
color: #005a9e;
}
#dreamscript-help-content pre {
background-color: #e7e7e7;
padding: 10px;
border-radius: 3px;
font-family: 'Consolas', 'Courier New', monospace;
white-space: pre-wrap;
margin: 10px 0;
}
#dreamscript-help-content .toc {
background-color: #f0f0f0;
border: 1px solid #ddd;
padding: 10px 20px;
}
#dreamscript-help-content a {
color: #0066cc;
text-decoration: none;
}
#dreamscript-help-content a:hover {
text-decoration: underline;
}
/* Main Help Window Content */
#help-content {
background-color: #fdfdfd;
color: #111;
padding: 15px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
}
#help-content h2, #help-content h3 {
border-bottom: 1px solid #ccc;
padding-bottom: 5px;
margin-top: 20px;
color: #005a9e;
}
#help-content pre {
background-color: #e7e7e7;
padding: 10px;
border-radius: 3px;
font-family: 'Consolas', 'Courier New', monospace;
white-space: pre-wrap;
margin: 10px 0;
}
#help-content .toc {
background-color: #f0f0f0;
border: 1px solid #ddd;
padding: 10px 20px;
}
#help-content a {
color: #0066cc;
text-decoration: none;
}
#help-content a:hover { text-decoration: underline; }
/* Chess Game */
#chess-status-bar {
text-align: center;
padding-bottom: 10px;
font-weight: bold;
}
#chessboard-container {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
}
#chessboard {
display: grid;
grid-template-columns: repeat(8, 5vh);
grid-template-rows: repeat(8, 5vh);
width: 40vh;
height: 40vh;
border: 2px solid #333;
}
.chess-square {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 3.5vh;
cursor: pointer;
}
.chess-square.light { background-color: #f0d9b5; color: black; }
.chess-square.dark { background-color: #b58863; color: black; }
.chess-square.selected { background-color: #6a9955 !important; }
.chess-square .legal-move-dot {
width: 30%;
height: 30%;
background-color: rgba(0, 0, 0, 0.2);
border-radius: 50%;
}
.chess-toolbar {
padding-top: 10px;
display: flex;
justify-content: center;
}
/* Responsive Design for Mobile Devices */
@media (max-width: 768px) {
/* Make all app windows take up most of the screen */
.app-window {
width: 98vw;
height: calc(100% - 5px); /* Almost full height */
top: 2px;
left: 1vw;
box-shadow: none; /* Remove shadow on mobile for performance */
}
/* Ensure the terminal specifically fills the screen */
#terminal-window {
width: 100%;
height: 100%;
top: 0;
left: 0;
border: none;
}
/* Make start menu items a bit bigger for touch */
#start-menu li {
padding: 10px 15px;
font-size: 16px;
}
}
/* Adventure Game App */
#adventure-window .window-content {
background-color: #000;
color: #0f0;
padding: 5px;
}
#adventure-output {
flex-grow: 1;
overflow-y: auto;
white-space: pre-wrap;
margin-bottom: 10px;
}
#adventure-input {
border: none;
background-color: #111;
color: #0f0;
width: 100%;
padding: 5px;
box-sizing: border-box;
font-family: inherit;
}
.room-title { color: #fff; font-weight: bold; }
.room-desc { color: #0f0; }
.command-echo { color: #888; }
</style>
</head>
<body>
<div id="desktop">
<!-- VDD Overlay -->
<div id="vdd-overlay">VDD_STAT: Loading...</div>
<!-- Main IFrame for external apps -->
<iframe id="main-frame" src="about:blank"></iframe>
<!-- Terminal Window -->
<div id="terminal-window" class="app-window">
<div class="window-header">
<span>DreamShell</span>
<div class="window-controls">
<button class="window-minimize-btn">_</button>
<button class="window-maximize-btn">[]</button>
<button class="window-close-btn">X</button>
</div>
</div>
<div class="window-content">
<div id="output">
<div>DreamOS [Version 10.0.2026] (c) 2026 Nicholas Paul Wilde. All rights reserved.</div>
</div>
<div id="prompt">
<span id="prompt-text">C:\></span>
<input type="text" id="command-input" autocomplete="off" spellcheck="false" />
</div>
</div>
</div>
<!-- Text Editor App Window -->
<div id="text-editor-window" class="app-window hidden">
<div class="window-header">
<span>Notepad</span>
<div class="window-controls">
<button class="window-minimize-btn">_</button>
<button class="window-maximize-btn">[]</button>
<button class="window-close-btn">X</button>
</div>
</div>
<div class="window-content">
<div class="editor-toolbar">
<input type="text" id="editor-filename" placeholder="C:\path\to\file.txt">
<button id="editor-load-btn">Load</button>
<button id="editor-save-btn">Save</button>
</div>
<textarea id="editor-content-area" class="editor-area"></textarea>
<div id="editor-status-bar">Ready</div>
</div>
</div>
<!-- DreamScript IDE App Window -->
<div id="dreamscript-ide-window" class="app-window hidden">
<div class="window-header">
<span>DreamScript IDE</span>
<div class="window-controls">
<button class="window-minimize-btn">_</button>
<button class="window-maximize-btn">[]</button>
<button class="window-close-btn">X</button>
</div>
</div>
<div class="window-content">
<div class="ide-toolbar">
<input type="text" id="dreamscript-ide-filename" placeholder="C:\path\to\program.ds">
<button id="dreamscript-ide-load-btn">Load</button>
<button id="dreamscript-ide-save-btn">Save</button>
<button id="dreamscript-ide-help-btn">Help</button>
<button id="dreamscript-ide-execute-btn">Run</button>
</div>
<div class="ide-editor-container">
<textarea id="dreamscript-ide-code" spellcheck="false"></textarea>
<pre id="dreamscript-ide-highlighting" aria-hidden="true"><code></code></pre>
</div>
<div id="dreamscript-ide-output">Output...</div>
</div>
</div>
<!-- DreamScript IDE Help Window -->
<div id="dreamscript-help-window" class="app-window hidden">
<div class="window-header">
<span>DreamScript Language Help</span>
<div class="window-controls">
<button class="window-minimize-btn">_</button>
<button class="window-maximize-btn">[]</button>
<button class="window-close-btn">X</button>
</div>
</div>
<div class="window-content" id="dreamscript-help-content">
<!-- Help content is injected by basic.js -->
</div>
</div>
<!-- Chess App Window -->
<div id="chess-window" class="app-window hidden">
<div class="window-header">
<span>Chess</span>
<div class="window-controls">
<button class="window-minimize-btn">_</button>
<button class="window-maximize-btn">[]</button>
<button class="window-close-btn">X</button>
</div>
</div>
<div class="window-content">
<div id="chess-status-bar">New game. White to move.</div>
<div id="chessboard-container">
<div id="chessboard"></div>
</div>
<div class="chess-toolbar">
<button id="chess-new-game-btn">New Game</button>
</div>
</div>
</div>
<!-- Adventure Game App Window -->
<div id="adventure-window" class="app-window hidden">
<div class="window-header">
<span>Adventure</span>
<div class="window-controls">
<button class="window-minimize-btn">_</button>
<button class="window-maximize-btn">[]</button>
<button class="window-close-btn">X</button>
</div>
</div>
<div class="window-content">
<div id="adventure-output"></div>
<input type="text" id="adventure-input" autocomplete="off" spellcheck="false" />
</div>
</div>
<!-- Main Help Window -->
<div id="help-window" class="app-window hidden">
<div class="window-header">
<span>DreamOS Help</span>
<div class="window-controls">
<button class="window-minimize-btn">_</button>
<button class="window-maximize-btn">[]</button>
<button class="window-close-btn">X</button>
</div>
</div>
<div class="window-content" id="help-content">
<!-- Help content is injected by help.js -->
</div>
</div>
</div>
<div id="taskbar">
<button id="start-btn">Start</button>
<div id="taskbar-apps"></div>
<div id="start-menu" class="hidden">
<ul>
<li id="start-menu-nwhome">NW_Home</li>
<li id="start-menu-fleagrass">Fleagrass</li>
<li id="start-menu-dalnet">Dal.net Chat</li>
<li id="start-menu-console">Console</li>
<li id="start-menu-notepad">Notepad</li>
<li id="start-menu-dreamscript">DreamScript IDE</li>
<li id="start-menu-chess">Chess</li>
<li id="start-menu-adventure">Text Adventure</li>
<li id="start-menu-reboot">Reboot</li>
</ul>
</div>
<div class="taskbar-divider"></div>
<span id="vdd-status">WDDM:OK</span>
<span id="clock">00:00</span>
</div>
<script>
/*
* Copyright (c) 2026 Nicholas Paul Wilde. All rights reserved.
* DREAMOS HAL - Hardware Abstraction Layer (Server/Web Edition)
*/
window.HAL = {
/**
* sysCall: The only authorized bridge to hardware.
* In this standalone web version, logic is handled locally or mocked.
*/
sysCall: (task, data) => {
if (window.Android && window.Android.sysCall) {
return window.Android.sysCall(task, data);
}
// Mock hardware responses for pure web deployment
if (task === "get_hw_id") return "HW_DREAMOS_V1_STANDALONE";
return "MODE_STANDALONE_WEB";
},
getPowerStatus: () => {
return { gpu: "Web-Accelerated VDD", vram: "Shared Browser Memory", status: "OK" };
}
};
/*
* Copyright (c) 2026 Nicholas Paul Wilde. All rights reserved.
* DREAMOS VFS - Virtual File System Module
* -----------------------------------------
* Strictly virtualized C:\ drive modeled after Windows Server.
*/
window.VFS = (() => {
const CURRENT_VFS_NAME_KEY = 'dreamos_vfs_current_name';
let VFS_STORAGE_KEY;
let PATH_STORAGE_KEY;
let vfsName;
// Default structure for a fresh install or a reset.
const getDefaultFs = () => ({
"c:": { type: "dir", name: "C:", metadata: { createdAt: new Date().toISOString(), modifiedAt: new Date().toISOString() } },
"c:\\inetpub": { type: "dir", name: "inetpub", metadata: { createdAt: new Date().toISOString(), modifiedAt: new Date().toISOString() } },
"c:\\inetpub\\wwwroot": { type: "dir", name: "wwwroot", metadata: { createdAt: new Date().toISOString(), modifiedAt: new Date().toISOString() } },
"c:\\inetpub\\wwwroot\\site_logs.txt": {
type: "file",
name: "site_logs.txt",
content: "DreamOS Server Deployment Log\n-----------------------------\nStatus: Online\nArchitecture: Microkernel JS\nHAL: Virtualized",
metadata: {
createdAt: new Date().toISOString(),
modifiedAt: new Date().toISOString(),
size: 146
}
},
"c:\\inetpub\\wwwroot\\adventure.json": {
type: "file",
name: "adventure.json",
content: JSON.stringify({
"startRoom": "clearing",
"rooms": {
"clearing": {
"name": "Forest Clearing",
"desc": "You are in a sun-dappled clearing. A path leads east into the darker woods. A strange, monolithic server hums quietly in the center of the clearing.",
"exits": { "east": "path" }
},
"path": {
"name": "Winding Path",
"desc": "A narrow path winds through ancient, moss-covered trees. The air is cool and smells of damp earth. The path continues to the east, and the clearing is to the west.",
"exits": { "west": "clearing" }
}
}
}, null, 2),
metadata: {
createdAt: new Date().toISOString(),
modifiedAt: new Date().toISOString(),
size: 500 // Approximate size
}
},
"c:\\inetpub\\wwwroot\\adventure.ds": {
type: "file",
name: "adventure.ds",
content: `' DreamScript Adventure!
DIM currentRoom = "clearing"
WHILE 1=1
PRINT ""
IF currentRoom = "clearing" THEN
PRINT "You are in a sun-dappled clearing. A path leads east."
ELSEIF currentRoom = "path" THEN
PRINT "You are on a winding path. The clearing is west."
END IF
INPUT "What now?>", command$
IF command$ = "east" AND currentRoom = "clearing" THEN
currentRoom = "path"
ELSEIF command$ = "west" AND currentRoom = "path" THEN
currentRoom = "clearing"
ELSE
PRINT "You can't do that."
END IF
WEND
`,
metadata: {
createdAt: new Date().toISOString(),
modifiedAt: new Date().toISOString(),
size: 600
}
},
"c:\\dreamos": { type: "dir", name: "DreamOS", metadata: { createdAt: new Date().toISOString(), modifiedAt: new Date().toISOString() } },
"c:\\dreamos\\system32": { type: "dir", name: "System32", metadata: { createdAt: new Date().toISOString(), modifiedAt: new Date().toISOString() } },
"c:\\dreamos\\system32\\dir.ds": {
type: "file",
name: "dir.ds",
content: `' The "dir" command, implemented in DreamScript.\nSYSCALL "VFS.getPath"\nDIM currentPath = RESULT\nSYSCALL "VFS.getDirectoryListing", currentPath\nPRINT RESULT`,
metadata: {
createdAt: new Date().toISOString(),
modifiedAt: new Date().toISOString(),
size: 150
}
},
"c:\\python312": { type: "dir", name: "Python312", metadata: { createdAt: new Date().toISOString(), modifiedAt: new Date().toISOString() } },
"c:\\python312\\python.exe": {
type: "file",
name: "python.exe",
content: "BINARY_EXEC",
metadata: {
createdAt: new Date().toISOString(),
modifiedAt: new Date().toISOString(),
size: 11
}
}
});
let fs;
let currentPath;
// Private function to save the current state to LocalStorage.
const _persist = () => {
try {
localStorage.setItem(VFS_STORAGE_KEY, JSON.stringify(fs));
localStorage.setItem(PATH_STORAGE_KEY, currentPath);
} catch (e) {
console.error(`Failed to save VFS '${vfsName}' to LocalStorage:`, e);
}
};
// Load state from LocalStorage or initialize with defaults.
const _load = () => {
console.log('[DreamOS Debug] VFS: Loading from localStorage...');
const storedFs = localStorage.getItem(VFS_STORAGE_KEY);
const storedPath = localStorage.getItem(PATH_STORAGE_KEY);
let fsNeedsInit = true;
// When loading, ensure all keys are canonical (lowercase)
if (storedFs) {
try {
console.log('[DreamOS Debug] VFS: Found existing FS in localStorage.');
const loadedFs = JSON.parse(storedFs);
fs = {};
for (const key in loadedFs) {
fs[key.toLowerCase()] = loadedFs[key];
}
fsNeedsInit = false;
} catch (e) {
console.warn('[DreamOS Debug] VFS: Failed to parse VFS from localStorage. Data may be corrupt. Resetting to default FS.', e);
}
}
if (fsNeedsInit) {
console.log('[DreamOS Debug] VFS: No valid FS found or data was corrupt. Initializing with default.');
fs = {};
const defaultFs = getDefaultFs();
for (const key in defaultFs) {
fs[key.toLowerCase()] = defaultFs[key];
}
}
// Ensure currentPath is also canonical (lowercase)
currentPath = (storedPath || "C:\\inetpub\\wwwroot").toLowerCase();
console.log(`[DreamOS Debug] VFS: Path set to "${currentPath}".`);
// If the FS was not in storage OR if we just re-initialized it, persist it.
if (!storedFs || fsNeedsInit) {
console.log('[DreamOS Debug] VFS: Persisting default/re-initialized FS to localStorage.');
_persist();
}
};
const _initVfs = () => {
console.log('[DreamOS Debug] VFS: Initializing...');
vfsName = localStorage.getItem(CURRENT_VFS_NAME_KEY) || 'default';
VFS_STORAGE_KEY = `dreamos_vfs_${vfsName}`;
PATH_STORAGE_KEY = `dreamos_vfs_path_${vfsName}`;
console.log(`[DreamOS Debug] VFS: Active VFS instance is '${vfsName}'.`);
_load();
};
// Initialize the file system on module load.
_initVfs();
/**
* Normalizes a given path relative to a base path, handling '..' and '.'
* and ensuring consistent '\' separators.
* @param {string} basePath The current working directory (e.g., "C:\inetpub\wwwroot").
* @param {string} targetPath The path to normalize (e.g., "..\logs", "C:\Windows\System32").
* @returns {string} The normalized absolute path (e.g., "C:\inetpub\logs").
*/
const _normalizePath = (basePath, targetPath) => {
let pathParts;
let currentPathArray;
// Handle absolute paths
if (targetPath.match(/^c:\\/i)) { // Starts with C:\ or c:\
pathParts = targetPath.substring(3).split('\\').filter(p => p !== '');
currentPathArray = []; // Start fresh from root
} else if (targetPath.match(/^c:/i)) { // Just C:
pathParts = [];
currentPathArray = []; // Start fresh from root
} else { // Relative path
currentPathArray = basePath.substring(2).split('\\').filter(p => p !== '');
pathParts = targetPath.split('\\').filter(p => p !== '');
}
for (const part of pathParts) {
if (part === '..') {
if (currentPathArray.length > 0) {
currentPathArray.pop();
}
} else if (part !== '.') {
currentPathArray.push(part);
}
}
let normalized = "C:";
if (currentPathArray.length > 0) {
normalized += "\\" + currentPathArray.join('\\');
}
return normalized;
};
const _listVfs = () => {
const vfsNames = new Set();
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key.startsWith('dreamos_vfs_') && key !== CURRENT_VFS_NAME_KEY) {
const name = key.startsWith('dreamos_vfs_path_')
? key.substring('dreamos_vfs_path_'.length)
: key.substring('dreamos_vfs_'.length);
vfsNames.add(name);
}
}
return Array.from(vfsNames);
};
const _switchVfs = (newName) => {
if (!newName || typeof newName !== 'string' || newName.trim() === '') {
return { success: false, message: "Invalid VFS name." };
}
// Sanitize name to prevent issues
const cleanName = newName.trim().replace(/\s+/g, '_');
localStorage.setItem(CURRENT_VFS_NAME_KEY, cleanName);
return { success: true, message: `Switched to VFS '${cleanName}'. System will reboot.` };
};
const _deleteVfs = (nameToDelete) => {
if (!nameToDelete || typeof nameToDelete !== 'string' || nameToDelete.trim() === '') {
return { success: false, message: "Invalid VFS name." };
}
const cleanName = nameToDelete.trim();
if (cleanName === vfsName) {
return { success: false, message: `Error: Cannot delete the currently active VFS ('${cleanName}').` };
}
if (cleanName === 'default') {
return { success: false, message: "Error: Cannot delete the 'default' VFS." };
}
const vfsKey = `dreamos_vfs_${cleanName}`;
const pathKey = `dreamos_vfs_path_${cleanName}`;
if (localStorage.getItem(vfsKey) === null && localStorage.getItem(pathKey) === null) {
return { success: false, message: `Error: VFS '${cleanName}' not found.` };
}
localStorage.removeItem(vfsKey);
localStorage.removeItem(pathKey);
return { success: true, message: `VFS '${cleanName}' deleted.` };
};
const _renameVfs = (oldName, newName) => {
if (!oldName || !newName || typeof oldName !== 'string' || typeof newName !== 'string') {
return { success: false, message: "Invalid VFS names provided." };
}
const cleanOldName = oldName.trim();
const cleanNewName = newName.trim().replace(/\s+/g, '_');
if (cleanOldName === vfsName) {
return { success: false, message: `Error: Cannot rename the currently active VFS ('${cleanOldName}').` };
}
if (cleanOldName === 'default') {
return { success: false, message: "Error: Cannot rename the 'default' VFS." };
}
if (cleanNewName === 'default' || cleanNewName === '') {
return { success: false, message: "Error: Invalid new name." };
}
const oldVfsKey = `dreamos_vfs_${cleanOldName}`;
const oldPathKey = `dreamos_vfs_path_${cleanOldName}`;
const newVfsKey = `dreamos_vfs_${cleanNewName}`;
const newPathKey = `dreamos_vfs_path_${cleanNewName}`;
const vfsData = localStorage.getItem(oldVfsKey);
if (vfsData === null) {
return { success: false, message: `Error: Source VFS '${cleanOldName}' not found.` };
}
if (localStorage.getItem(newVfsKey) !== null || localStorage.getItem(newPathKey) !== null) {
return { success: false, message: `Error: Destination VFS '${cleanNewName}' already exists.` };
}
const pathData = localStorage.getItem(oldPathKey);
localStorage.setItem(newVfsKey, vfsData);
if (pathData !== null) {
localStorage.setItem(newPathKey, pathData);
}
localStorage.removeItem(oldVfsKey);
localStorage.removeItem(oldPathKey);
return { success: true, message: `VFS '${cleanOldName}' renamed to '${cleanNewName}'.` };
};
const _copyVfs = (sourceName, destName) => {
if (!sourceName || !destName || typeof sourceName !== 'string' || typeof destName !== 'string') {
return { success: false, message: "Invalid VFS names provided." };
}
const cleanSourceName = sourceName.trim();
const cleanDestName = destName.trim().replace(/\s+/g, '_');
if (cleanSourceName === cleanDestName) {
return { success: false, message: "Error: Source and destination names cannot be the same." };
}
const sourceVfsKey = `dreamos_vfs_${cleanSourceName}`;
const sourcePathKey = `dreamos_vfs_path_${cleanSourceName}`;
const destVfsKey = `dreamos_vfs_${cleanDestName}`;
const destPathKey = `dreamos_vfs_path_${cleanDestName}`;
const vfsData = localStorage.getItem(sourceVfsKey);
if (vfsData === null) {
return { success: false, message: `Error: Source VFS '${cleanSourceName}' not found.` };
}
if (localStorage.getItem(destVfsKey) !== null || localStorage.getItem(destPathKey) !== null) {
return { success: false, message: `Error: Destination VFS '${cleanDestName}' already exists.` };
}
const pathData = localStorage.getItem(sourcePathKey);
localStorage.setItem(destVfsKey, vfsData);
if (pathData !== null) {
localStorage.setItem(destPathKey, pathData);
}
return { success: true, message: `VFS '${cleanSourceName}' copied to '${cleanDestName}'.` };
};
const _getDirectoryListing = (path) => {
const canonicalPath = _normalizePath(currentPath, path).toLowerCase();
if (!fs[canonicalPath] || fs[canonicalPath].type !== 'dir') {
return "The system cannot find the path specified.";
}
const children = [];
for (const [fullPathKey, entry] of Object.entries(fs)) {
let isDirectChild = false;
if (canonicalPath === 'c:') {
if (fullPathKey.startsWith('c:\\') && fullPathKey.split('\\').length === 2) {
isDirectChild = true;
}
} else if (fullPathKey.startsWith(canonicalPath + '\\')) {
const relativePath = fullPathKey.substring(canonicalPath.length + 1);
if (relativePath && !relativePath.includes('\\')) {
isDirectChild = true;
}
}
if (isDirectChild) {
children.push(entry);
}
}
if (children.length === 0) return "File Not Found";
let output = ` Directory of ${canonicalPath.toUpperCase()}\n\n`;
let totalFiles = 0;
let totalSize = 0;
let totalDirs = 0;
const formatDosDate = (isoString) => {
if (!isoString) return ' '.repeat(20);
const d = new Date(isoString);
const month = (d.getMonth() + 1).toString().padStart(2, '0');
const day = d.getDate().toString().padStart(2, '0');
const year = d.getFullYear();
let hours = d.getHours();
const minutes = d.getMinutes().toString().padStart(2, '0');
const ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12;
hours = hours ? hours : 12; // the hour '0' should be '12'
const strHours = hours.toString().padStart(2, ' ');
return `${month}/${day}/${year} ${strHours}:${minutes} ${ampm}`;
};
children.forEach(entry => {
const dateStr = formatDosDate(entry.metadata?.modifiedAt);
if (entry.type === "dir") {
output += `${dateStr} <DIR> ${entry.name}\n`;
totalDirs++;
} else {
const size = entry.metadata?.size || 0;
const sizeStr = size.toLocaleString().padStart(12);
output += `${dateStr} ${sizeStr} ${entry.name}\n`;
totalFiles++;
totalSize += size;
}
});
output += `\n ${totalFiles} File(s) ${totalSize.toLocaleString()} bytes`;
output += `\n ${totalDirs} Dir(s)`;
return output;
};
return {
getPath: () => currentPath, // Returns canonical (lowercase) path
setPath: (path) => {
currentPath = path.toLowerCase(); // Ensure path is always canonical
_persist();
},
normalizePath: _normalizePath, // Returns path with input casing, but canonical form is lowercase
exists: (path) => {
const canonicalPath = _normalizePath(currentPath, path).toLowerCase();
return fs[canonicalPath] ? canonicalPath : null; // Returns the canonical key if it exists
},
getEntry: (canonicalPath) => fs[canonicalPath], // Expects a canonical (lowercase) path
getAllEntries: () => fs, // Returns entries with lowercase keys
readFile: (path) => {
const canonicalPath = _normalizePath(currentPath, path).toLowerCase();
const entry = fs[canonicalPath]; // Directly look up using canonical path
if (entry) {
if (entry.type === "file") {
// Return the original path for user feedback, but content from canonical entry
return { success: true, path: _normalizePath(currentPath, path), content: entry.content };
} else if (entry.type === "dir") {
return { success: false, message: `Error: '${path}' is a directory.` };
}
}
return { success: false, message: "Error: The system cannot find the file specified." };
},
writeFile: (path, content) => {
const resolvedPath = _normalizePath(currentPath, path); // Path with input casing
const canonicalResolvedPath = resolvedPath.toLowerCase(); // Canonical key for storage
const lastSlash = canonicalResolvedPath.lastIndexOf('\\');
const parentDirCanonical = (lastSlash > 2) ? canonicalResolvedPath.substring(0, lastSlash) : "c:";
if (!fs[parentDirCanonical] || fs[parentDirCanonical].type !== 'dir') {
return { success: false, message: "Error: The system cannot find the path specified." };
}
const filename = resolvedPath.substring(resolvedPath.lastIndexOf('\\') + 1); // Keep original casing for name property
const now = new Date().toISOString();
const existingEntry = fs[canonicalResolvedPath];
if (existingEntry) {
if (existingEntry.type === 'dir') {
return { success: false, message: `Error: Cannot write to '${path}'. It is a directory.` };
}
// Update existing file
existingEntry.content = content;
if (!existingEntry.metadata) {
// For backward compatibility with files created before metadata existed
existingEntry.metadata = { createdAt: now };
}
existingEntry.metadata.modifiedAt = now;
existingEntry.metadata.size = content.length;
} else {
// Create new file
fs[canonicalResolvedPath] = {
type: "file",
name: filename,
content: content,
metadata: {
createdAt: now,
modifiedAt: now,
size: content.length
}
};
}
_persist(); // Save changes to LocalStorage
return { success: true, message: `File saved: ${resolvedPath}` }; // Return resolvedPath for user feedback
},
makeDirectory: (path) => {
const resolvedPath = _normalizePath(currentPath, path);
const canonicalResolvedPath = resolvedPath.toLowerCase();
if (fs[canonicalResolvedPath]) {
return { success: false, message: "A subdirectory or file with that name already exists." };
}
const lastSlash = canonicalResolvedPath.lastIndexOf('\\');
const parentDirCanonical = (lastSlash > 2) ? canonicalResolvedPath.substring(0, lastSlash) : "c:";
if (!fs[parentDirCanonical] || fs[parentDirCanonical].type !== 'dir') {
return { success: false, message: "The system cannot find the path specified." };
}
const dirname = resolvedPath.substring(resolvedPath.lastIndexOf('\\') + 1);
const now = new Date().toISOString();
fs[canonicalResolvedPath] = { type: "dir", name: dirname, metadata: { createdAt: now, modifiedAt: now } };
_persist();
return { success: true, message: "" };
},
format: () => {
try {
localStorage.removeItem(VFS_STORAGE_KEY);
localStorage.removeItem(PATH_STORAGE_KEY);
// Re-initialize the file system to its default state.
_initVfs();
} catch (e) {
console.error(`Failed to format VFS '${vfsName}':`, e);
}
},
listVfs: _listVfs,
switchVfs: _switchVfs,
deleteVfs: _deleteVfs,
renameVfs: _renameVfs,
copyVfs: _copyVfs,
getCurrentVfsName: () => vfsName,
getDirectoryListing: _getDirectoryListing
};
})();
/*
* Copyright (c) 2026 Nicholas Paul Wilde. All rights reserved.
* DREAMOS WINDOW MANAGER (win.sys.js)
*/
window.WindowManager = (() => {
let highestZ = 100;
let taskbarAppsContainer;
// The main initialization function for the window manager.
const init = () => {
taskbarAppsContainer = document.getElementById('taskbar-apps');
if (!taskbarAppsContainer) {
console.error("Window Manager Error: Taskbar container '#taskbar-apps' not found.");
return;
}
// Find all elements with the class 'app-window' and make them behave like windows.
document.querySelectorAll('.app-window').forEach(windowEl => {
_makeDraggable(windowEl);
_setupWindowControls(windowEl);
});
};
// Private function to make a window draggable by its header.
const _makeDraggable = (windowEl) => {
const header = windowEl.querySelector('.window-header');
let offsetX, offsetY;
const onMouseDown = (e) => {
// Bring window to the front when clicked.
_bringToFront(windowEl);
// Don't start dragging if a button in the header was clicked.
if (e.target.closest('.window-controls')) return;
// Don't drag if the window is maximized.
if (windowEl.classList.contains('maximized')) return;
offsetX = e.clientX - windowEl.offsetLeft;
offsetY = e.clientY - windowEl.offsetTop;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
};
const onMouseMove = (e) => {
windowEl.style.left = `${e.clientX - offsetX}px`;
windowEl.style.top = `${e.clientY - offsetY}px`;
};
const onMouseUp = () => {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
};
header.addEventListener('mousedown', onMouseDown);
};
// Private function to set up the minimize, maximize, and close buttons.
const _setupWindowControls = (windowEl) => {
windowEl.addEventListener('mousedown', () => _bringToFront(windowEl));
const windowId = windowEl.id;
const title = windowEl.querySelector('.window-header span').textContent;
const minBtn = windowEl.querySelector('.window-minimize-btn');
const maxBtn = windowEl.querySelector('.window-maximize-btn');
const closeBtn = windowEl.querySelector('.window-close-btn');
if (minBtn) {
minBtn.addEventListener('click', () => TaskbarManager.add(windowEl, title));
}
if (maxBtn) {
maxBtn.addEventListener('click', () => windowEl.classList.toggle('maximized'));
}
if (closeBtn) {
closeBtn.addEventListener('click', () => {
// Special case for the terminal: minimize instead of closing to preserve the session.
if (windowId === 'terminal-window') {
TaskbarManager.add(windowEl, title);
} else {
windowEl.classList.add('hidden');
TaskbarManager.remove(windowId);
}
});
}
};
// Private function to bring a window to the top of the stack.
const _bringToFront = (windowEl) => {
highestZ++;
windowEl.style.zIndex = highestZ;
};
// An internal object to manage minimized windows on the taskbar.
const TaskbarManager = {
minimizedWindows: {},
add: (windowEl, title) => {
const windowId = windowEl.id;
if (TaskbarManager.minimizedWindows[windowId]) return; // Already on taskbar.
const taskbarItem = document.createElement('div');
taskbarItem.className = 'taskbar-item';
taskbarItem.textContent = title;
taskbarItem.dataset.window = windowId;
taskbarItem.addEventListener('click', () => {
TaskbarManager.restore(windowId);
});
taskbarAppsContainer.appendChild(taskbarItem);
TaskbarManager.minimizedWindows[windowId] = taskbarItem;
windowEl.classList.add('minimized');
},
restore: (windowId) => {
const windowEl = document.getElementById(windowId);
const taskbarItem = TaskbarManager.minimizedWindows[windowId];
if (windowEl && taskbarItem) {
windowEl.classList.remove('minimized');
taskbarItem.remove();
delete TaskbarManager.minimizedWindows[windowId];
_bringToFront(windowEl);
// If it's the terminal, focus the input.
if (windowId === 'terminal-window') {
const input = document.getElementById('command-input');
if (input) input.focus();
}
}
},
remove: (windowId) => {
const taskbarItem = TaskbarManager.minimizedWindows[windowId];
if (taskbarItem) {
taskbarItem.remove();
delete TaskbarManager.minimizedWindows[windowId];
}
}
};
// The public API for the WindowManager.
return {
init: init,
focusOrRestore: (windowId) => {
const windowEl = document.getElementById(windowId);
if (!windowEl) return;
if (windowEl.classList.contains('minimized')) {
TaskbarManager.restore(windowId);
} else {
_bringToFront(windowEl);
}
}
};
})();
/*
* Copyright (c) 2026 Nicholas Paul Wilde. All rights reserved.
* DREAMOS CLUSTER - WebRTC Distributed Computing Module
*/
window.DreamCluster = (() => {
// The address of your signaling server.
// When loading the page over HTTPS, the WebSocket must also be secure (WSS).
// Browsers block insecure WebSocket (ws://) connections from secure pages.
const SIGNALING_SERVER_URL = 'wss://mars.fleagrass.com:1874';
let ws; // This will hold our WebSocket connection.
let peers = {}; // An object to store all our peer connections.
let localId = 'peer_' + Math.random().toString(36).substr(2, 9); // A random, unique ID for this browser session.
let onMessageCallback; // A function to call when we receive data from a peer.
let encryptionKey; // This will hold the password for simple encryption.
// Configuration for the RTCPeerConnection. This includes STUN servers.
// STUN servers are public utilities that help browsers figure out their public IP address
// so they can connect even if they are behind a home router (NAT).
const peerConnectionConfig = {
'iceServers': [
{ 'urls': 'stun:stun.stunprotocol.org:3478' },
{ 'urls': 'stun:stun.l.google.com:19302' },
]
};
// This function starts the connection to the signaling server.
const init = (key, statusCallback) => {
console.log('[DreamOS Debug] DreamCluster: Initializing...');
if (!key) {
console.error("Cluster initialization failed: An encryption key is required.");
if (statusCallback) statusCallback({ connected: false, message: "Cluster initialization failed: An encryption key is required." });
return;
}
encryptionKey = key;
ws = new WebSocket(SIGNALING_SERVER_URL);
// When the connection to the signaling server is open...
ws.onopen = () => {
console.log("Connected to signaling server.");
if (statusCallback) statusCallback({ connected: true, message: "Successfully connected to cluster signaling server." });
// ...we announce our presence to everyone else by sending our unique ID.
ws.send(JSON.stringify({ type: 'new-peer', id: localId }));
};
// This function runs every time we get a message from the signaling server.
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log("Signaling message received:", msg);
// If a new peer announces itself (and it's not us)...
if (msg.type === 'new-peer' && msg.id !== localId) {
// ...we will try to connect to it by creating and sending an "offer".
const peerConnection = getOrCreatePeerConnection(msg.id);
// As the initiator of this connection, we create the data channel.
// The other peer will receive this via its 'ondatachannel' event.
console.log("Creating data channel for peer:", msg.id);
const dataChannel = peerConnection.createDataChannel('dreamos-data');
// Store the data channel so we can use it later.
peers[msg.id].dataChannel = dataChannel;
setupDataChannelEvents(dataChannel, msg.id);
peerConnection.createOffer()
.then(offer => peerConnection.setLocalDescription(offer))
.then(() => {
console.log("Sending offer to peer:", msg.id);
ws.send(JSON.stringify({
type: 'offer',
sdp: peerConnection.localDescription,
senderId: localId,
receiverId: msg.id
}));
})
.catch(e => console.error("Offer creation failed:", e));
}
// If we receive an "offer" from another peer...
else if (msg.type === 'offer' && msg.receiverId === localId) {
// ...we create an "answer" and send it back.
const peerConnection = getOrCreatePeerConnection(msg.senderId);
peerConnection.setRemoteDescription(new RTCSessionDescription(msg.sdp))
.then(() => peerConnection.createAnswer())
.then(answer => peerConnection.setLocalDescription(answer))
.then(() => {
console.log("Sending answer to peer:", msg.senderId);
ws.send(JSON.stringify({
type: 'answer',
sdp: peerConnection.localDescription,
senderId: localId,
receiverId: msg.senderId
}));
})
.catch(e => console.error("Answer creation failed:", e));
}
// If we receive an "answer" from a peer we sent an offer to...
else if (msg.type === 'answer' && msg.receiverId === localId) {
// ...we complete the connection setup.
getOrCreatePeerConnection(msg.senderId).setRemoteDescription(new RTCSessionDescription(msg.sdp))
.catch(e => console.error("setRemoteDescription failed:", e));
}
// An "ICE candidate" is a potential network path. Peers exchange them to find the best way to connect.
else if (msg.type === 'ice-candidate' && msg.receiverId === localId) {
const candidate = new RTCIceCandidate(msg.candidate);
getOrCreatePeerConnection(msg.senderId).addIceCandidate(candidate)
.catch(e => console.error("addIceCandidate failed:", e));
}
};
ws.onerror = (error) => {
console.error("Signaling server connection error:", error);
if (statusCallback) statusCallback({ connected: false, message: "Error: Could not connect to cluster signaling server." });
};
};
// A helper function to get an existing peer connection or create a new one.
const getOrCreatePeerConnection = (peerId) => {
if (!peers[peerId]) {
console.log(`Creating new peer connection for ${peerId}`);
const pc = new RTCPeerConnection(peerConnectionConfig);
// Add a listener to log connection state changes for debugging.
pc.onconnectionstatechange = (event) => {
console.log(`Connection state with ${peerId} changed to: ${pc.connectionState}`);
};
// This event fires when our browser finds a network path (an ICE candidate).
// We need to send this to the other peer through the signaling server.
pc.onicecandidate = (event) => {
if (event.candidate) {
ws.send(JSON.stringify({
type: 'ice-candidate',
candidate: event.candidate,
senderId: localId,
receiverId: peerId
}));
}
};
// This event fires when the *other* peer opens a data channel to us.
pc.ondatachannel = (event) => {
console.log(`Data channel connection established with ${peerId}`);
peers[peerId].dataChannel = event.channel;
setupDataChannelEvents(event.channel, peerId);
};
peers[peerId] = { connection: pc, dataChannel: null };
}
return peers[peerId].connection;
};
// Sets up events for a data channel (either one we created or one we received).
const setupDataChannelEvents = (dataChannel, peerId) => {
dataChannel.onopen = () => console.log(`Data channel with ${peerId} is open!`);
dataChannel.onclose = () => console.log(`Data channel with ${peerId} is closed.`);
dataChannel.onmessage = (event) => {
console.log(`Message from ${peerId}:`, event.data);
// Decrypt the message before passing it on.
const decryptedMessage = _xorCipher(event.data, encryptionKey);
if (onMessageCallback) {
onMessageCallback(decryptedMessage);
}
};
};
// Sends a message to all connected peers.
const broadcast = (message) => {
let count = 0;
for (const peerId in peers) {
const dataChannel = peers[peerId].dataChannel;
if (dataChannel && dataChannel.readyState === 'open') {
// Encrypt the message before sending.
const encryptedMessage = _xorCipher(message, encryptionKey);
dataChannel.send(encryptedMessage);
count++;
}
}
return `Message broadcast to ${count} peer(s).`;
};
// Gets the current status of the cluster.
const getStatus = () => {
if (!ws || ws.readyState !== WebSocket.OPEN) {
return "Cluster status: Disconnected from signaling server.";
}
const peerIds = Object.keys(peers);
const connectedPeers = peerIds.filter(id => peers[id].dataChannel && peers[id].dataChannel.readyState === 'open');
let status = `Cluster status: Connected to signaling server.\n`;
status += `Local Peer ID: ${localId}\n`;
status += `Discovered Peers: ${peerIds.length}\n`;
status += `Connected Peers: ${connectedPeers.length}`;
if (connectedPeers.length > 0) {
status += ` (${connectedPeers.join(', ')})`;
}
return status;
};
// Allows other parts of the OS to listen for messages from peers.
const setOnMessage = (callback) => {
onMessageCallback = callback;
};
// A simple XOR cipher for "encryption". This is NOT secure for real-world use.
// It works by combining the message with the key. The same function is used
// to encrypt and decrypt.
const _xorCipher = (text, key) => {
let result = '';
for (let i = 0; i < text.length; i++) {
// We get the character code (a number) for the message character and the key character.
// The '%' (modulo) operator makes the key repeat if it's shorter than the message.
const charCode = text.charCodeAt(i) ^ key.charCodeAt(i % key.length);
result += String.fromCharCode(charCode);
}
return result;
};
// Expose the public functions.
return {
init,
broadcast,
getStatus,
setOnMessage
};
})();
/*
* Copyright (c) 2026 Nicholas Paul Wilde. All rights reserved.
* DREAMOS KERNEL - Command Processing & Logic Module
* --------------------------------------------------
* Handles the logic for the shell and coordinates between VFS and HAL.
*/
window.Kernel = (() => {
/**
* Python Emulator Logic (Python License Applies)
*/
const runPython = (code) => {
if (!code) return "Python 3.12.2 (DreamOS JS-Kernel)\nType \"help\", \"copyright\" for more info.\n>>>";
if (code.toLowerCase().startsWith("print(")) {
// This regex now correctly handles single or double quotes and captures only the content.
const match = code.match(/print\((?:"([^"]*)"|'([^']*)')\)/i);
// The result will be in either the first or second capture group.
return match ? (match[1] !== undefined ? match[1] : match[2]) : "SyntaxError: invalid syntax";
}
return `Traceback (most recent call last):\n NameError: name '${code}' is not defined`;
};
const internalWriteFile = (path, content) => {
if (!path || content === undefined) {
return { success: false, message: "Error: Path and content required." };
}
const resolved = VFS.normalizePath(VFS.getPath(), path);
return VFS.writeFile(resolved, content);
};
const internalReadFile = (path) => {
return VFS.readFile(VFS.normalizePath(VFS.getPath(), path));
};
return {
/**
* The primary command execution engine.
*/
execute: (input) => {
console.log(`[DreamOS Debug] Kernel: Executing command: "${input}"`);
const parts = input.trim().split(/\s+/);
const cmd = parts[0].toLowerCase();
const args = parts.slice(1).join(" ");
switch (cmd) {
case "ver":
return "DreamOS [Version 10.0.2026] (Server Port)\n(c) 2026 Nicholas Paul Wilde. Runs on any modern web browser.\nMicrosoft Windows is a registered trademark of Microsoft Corporation.";
case "pwd":
return VFS.getPath();
case "whoami":
return "DREAMOS\\nicholas_paul_wilde";
case "dir":
case "ls":
{
const dirScript = internalReadFile("c:\\dreamos\\system32\\dir.ds");
if (dirScript.success) {
// The output from runSync has an extra newline at the end, so trim it.
return DreamScriptInterpreter.runSync(dirScript.content).trim();
} else {
return "Error: dir.ds command not found. " + (dirScript.message || "");
}
}
case "cd":
if (!args) return "";
const searchPath = VFS.normalizePath(VFS.getPath(), args);
const actualPath = VFS.exists(searchPath);
if (actualPath && VFS.getEntry(actualPath).type === "dir") { // actualPath is now canonical (lowercase)
VFS.setPath(actualPath);
return "";
}
return "The system cannot find the path specified.";
case "type":
case "cat":
const targetFile = VFS.normalizePath(VFS.getPath(), args);
const actualFile = VFS.exists(targetFile); // actualFile is now canonical (lowercase)
if (actualFile && VFS.getEntry(actualFile).type === "file") {
return VFS.getEntry(actualFile).content;
}
return "The system cannot find the file specified.";
case "edit": {
const targetPath = VFS.normalizePath(VFS.getPath(), args);
// If no file is specified, just open a blank editor
if (!args) {
return { signal: "KERNEL_SIGNAL_OPEN_EDITOR", path: '', content: '' };
}
const actualFile = VFS.exists(targetPath); // actualFile is now canonical (lowercase)
let content = '';
// Use actual path to preserve casing, or target path for new file
let path = actualFile || targetPath;
if (actualFile && VFS.getEntry(actualFile).type === "file") {
content = VFS.getEntry(actualFile).content;
} else if (actualFile && VFS.getEntry(actualFile).type === "dir") {
return `Error: '${args}' is a directory.`;
}
return { signal: "KERNEL_SIGNAL_OPEN_EDITOR", path: path, content: content };
}
case "python":
if (args.toLowerCase().startsWith("-c ")) {
return runPython(args.substring(3).replace(/^["']|["']$/g, ""));
}
return runPython("");
case "msg":
if (!args) return "Usage: msg <message>";
alert(args);
return ""; // Return empty string so nothing is printed to the console
case "reset":
const resetMessage = "WARNING: This will erase all data on the virtual file system.\n\nThis is useful if your files have become corrupted or if a new version of DreamOS requires a clean slate.\n\nAre you sure you want to proceed?";
if (confirm(resetMessage)) {
VFS.format();
setTimeout(() => location.reload(), 1500);
return "Resetting virtual file system... Success. System will now reboot.";
}
return "Reset operation cancelled.";
case "mkdir":
case "md":
if (!args) {
return "The syntax of the command is incorrect.";
}
const mkdirResult = VFS.makeDirectory(args);
return mkdirResult.success ? "" : mkdirResult.message;
case "dreamscript":
case "basic":
return { signal: "KERNEL_SIGNAL_OPEN_DREAMSCRIPT_IDE" };
case "adventure":
return { signal: "KERNEL_SIGNAL_OPEN_ADVENTURE" };
case "chess":
return { signal: "KERNEL_SIGNAL_OPEN_CHESS" };
case "cluster": {
const subCmd = (args.split(' ')[0] || '').toLowerCase();
const subArgs = args.split(' ').slice(1).join(' ');
switch (subCmd) {
case 'status':
return DreamCluster.getStatus();
case 'broadcast':
if (!subArgs) return "Usage: cluster broadcast <message>";
return DreamCluster.broadcast(subArgs);
default:
return `DreamOS Cluster Management\nUsage:\n cluster status - Show network status.\n cluster broadcast - Send a message to all peers.`;
}
}
case "music": {
if (!window.musicControls) {
return "Music controls are not available.";
}
const subCmd = (args || '').toLowerCase();
switch (subCmd) {
case 'play':
case 'unpause':
window.musicControls.play();
return "Playing music.";
case 'pause':
case 'stop':
window.musicControls.pause();
return "Music paused.";
case 'skip':
case 'next':
window.musicControls.skip();
return "Skipping to next song.";
default:
return "Usage: music <play|pause|skip>";
}
}
case "vfs": {
const subCmdParts = args.split(/\s+/);
const subCmd = (subCmdParts[0] || '').toLowerCase();
const arg1 = subCmdParts[1];
const arg2 = subCmdParts[2];
switch (subCmd) {
case 'list':
const vfsList = VFS.listVfs();
const currentVfs = VFS.getCurrentVfsName();
if (vfsList.length === 0) {
return `No VFS instances found. Current is '${currentVfs}'.`;
}
let vfsOutput = "Available VFS instances:\n";
vfsList.forEach(name => {
vfsOutput += ` ${name}` + (name === currentVfs ? ' (current)' : '') + '\n';
});
return vfsOutput.trim();
case 'use':
case 'switch':
if (!arg1) return "Usage: vfs use <name>";
const result = VFS.switchVfs(arg1);
if (result.success) setTimeout(() => location.reload(), 1000);
return result.message;
case 'current':
return `Current VFS is: '${VFS.getCurrentVfsName()}'`;
case 'copy':
case 'cp':
if (!arg1 || !arg2) return "Usage: vfs copy <source_name> <destination_name>";
return VFS.copyVfs(arg1, arg2).message;
case 'rename':
case 'mv':
if (!arg1 || !arg2) return "Usage: vfs rename <old_name> <new_name>";
return VFS.renameVfs(arg1, arg2).message;
case 'delete':
case 'rm':
if (!arg1) return "Usage: vfs delete <name>";
return VFS.deleteVfs(arg1).message;
default:
return `VFS Management Command\nUsage:\n vfs list - List all VFS instances.\n vfs use <name> - Switch to a different VFS instance.\n vfs current - Show the current VFS name.\n vfs copy <src> <dest> - Copy a VFS instance.\n vfs rename <old> <new> - Rename a VFS instance.\n vfs delete <name> - Delete a VFS instance.`;
}
}
case "help":
return { signal: "KERNEL_SIGNAL_OPEN_HELP" };
case "cls":
case "clear":
return "KERNEL_SIGNAL_CLS";
case "":
return "";
default:
// If no JS command matches, try passing to HAL (Native hardware fallback)
return HAL.sysCall("execute_cmd", input);
}
},
writeFile: internalWriteFile,
readFile: internalReadFile
};
})();
/*
* Copyright (c) 2026 Nicholas Paul Wilde. All rights reserved.
* DREAMOS EDIT - Simple Text Editor App
*/
window.EditApp = (() => {
// Define variables for DOM elements. They will be assigned after the DOM is loaded.
let textEditorWindow, editorFilename, editorContentArea, editorLoadBtn, editorSaveBtn, editorStatusBar;
/**
* Initializes the module by caching DOM elements and setting up event listeners.
* This function is called once the DOM is fully loaded.
*/
const init = () => {
console.log('[DreamOS Debug] EditApp: Initializing...');
// Get references to the editor's DOM elements
textEditorWindow = document.getElementById('text-editor-window');
editorFilename = document.getElementById('editor-filename');
editorContentArea = document.getElementById('editor-content-area');
editorLoadBtn = document.getElementById('editor-load-btn');
editorSaveBtn = document.getElementById('editor-save-btn');
editorStatusBar = document.getElementById('editor-status-bar');
// Event listener for Save button
editorSaveBtn.addEventListener('click', onSave);
// Event listener for Load button
editorLoadBtn.addEventListener('click', onLoad);
console.log('[DreamOS Debug] EditApp: Initialized successfully.');
};
/**
* Opens the text editor window and initializes it with content and path.
* @param {string} path - The file path to display in the filename input.
* @param {string} content - The content to load into the editor.
*/
const open = (path = '', content = '') => {
console.log(`[DreamOS Debug] EditApp: Opening with path: "${path}"`);
// Ensure init has run
if (!textEditorWindow) {
console.error("Editor not initialized. DOM may not be ready.");
return;
}
textEditorWindow.classList.remove('hidden');
editorFilename.value = path;
editorContentArea.value = content;
editorStatusBar.innerText = path ? `Loaded ${path}` : 'Ready';
editorContentArea.focus();
};
const onSave = () => {
const path = editorFilename.value;
const content = editorContentArea.value;
if (!path) {
editorStatusBar.innerText = "Error: Filename is required to save.";
return;
}
const result = Kernel.writeFile(path, content);
editorStatusBar.innerText = result.message;
};
const onLoad = () => {
const path = editorFilename.value;
if (!path) {
editorStatusBar.innerText = "Error: Filename is required to load.";
return;
}
const result = Kernel.readFile(path);
if (result.success) {
editorContentArea.value = result.content;
editorStatusBar.innerText = `Successfully loaded ${result.path}`;
} else {
editorStatusBar.innerText = result.message;
}
};
// Expose the public API for the EditApp module
return {
open: open,
init: init
};
})();
/*
* Copyright (c) 2026 Nicholas Paul Wilde. All rights reserved.
* DREAMOS DREAMSCRIPT - A simple scripting language interpreter and IDE
*/
window.DreamScriptInterpreter = (() => {
// --- Interpreter State ---
let state = {};
const resetState = () => {
state = {
lines: [],
pc: 0, // Program Counter
scopes: [{}], // Scope stack, global scope is at the bottom
loopStack: [], // For tracking WHILE/WEND loops
subroutines: {}, // To store SUB definitions
callStack: [], // For CALL/END SUB flow
isWaitingForInput: false,
inputVarName: null,
onOutput: () => {},
onPrompt: () => {},
onEnd: () => {},
};
};
// --- Callbacks for async operations ---
let onOutput, onPrompt, onEnd;
// --- Scope Management ---
const getCurrentScope = () => state.scopes[state.scopes.length - 1];
const getVariable = (name) => {
const varName = name.toUpperCase();
for (let i = state.scopes.length - 1; i >= 0; i--) {
if (Object.prototype.hasOwnProperty.call(state.scopes[i], varName)) {
return state.scopes[i][varName];
}
}
return undefined;
};
const setVariable = (name, value) => {
const varName = name.toUpperCase();
for (let i = state.scopes.length - 1; i >= 0; i--) {
if (Object.prototype.hasOwnProperty.call(state.scopes[i], varName)) {
state.scopes[i][varName] = value;
return;
}
}
// If not found, declare in current scope
getCurrentScope()[varName] = value;
};
// --- Expression Evaluation ---
const evaluate = (expression) => {
// Note: This is a simple left-to-right evaluator.
// It does NOT respect standard operator precedence (e.g., 1 + 2 * 3 is 9, not 7).
// It does NOT support parentheses. This should be improved in the future.
expression = String(expression).trim();
// Tokenize the expression by spaces, but keep quoted strings together.
const tokens = expression.match(/"[^"]*"|\S+/g) || [];
if (tokens.length === 0) return "";
// First pass: resolve variables to their values
const values = tokens.map(token => {
if (token.startsWith('"') && token.endsWith('"')) return token.substring(1, token.length - 1);
if (!isNaN(token) && token.trim() !== '') return parseFloat(token);
const value = getVariable(token);
if (value !== undefined) return value;
return token; // Keep operators and unresolved tokens as strings
});
if (values.length === 1) return values[0];
// Second pass: evaluate expressions from left to right
let result = values[0];
for (let i = 1; i < values.length; i += 2) {
const op = values[i];
const right = values[i+1];
if (right === undefined) throw new Error(`Syntax error in expression near operator '${op}'`);
switch(op) {
case '+': result = result + right; break;
case '-': result = result - right; break;
case '*': result = result * right; break;
case '/': result = result / right; break;
case '=': result = result == right; break;
case '<>': result = result != right; break;
case '>': result = result > right; break;
case '<': result = result < right; break;
case '>=': result = result >= right; break;
case '<=': result = result <= right; break;
default: throw new Error(`Unknown operator or invalid expression: ${op}`);
}
}
return result;
};
// --- Pre-computation and Execution ---
const _scanForSubroutines = () => {
state.subroutines = {};
let currentSub = null;
let subStart = -1;
let depth = 0;
for (let i = 0; i < state.lines.length; i++) {
const uLine = state.lines[i].trim().toUpperCase();
if (uLine.startsWith('SUB ')) {
if (depth === 0) { // Only top-level SUBs
currentSub = uLine.substring(4).trim();
subStart = i;
}
depth++;
} else if (uLine === 'END SUB') {
depth--;
if (depth === 0 && currentSub) {
state.subroutines[currentSub] = { startPc: subStart + 1 };
currentSub = null;
}
}
}
if (depth !== 0) throw new Error(`Mismatched SUB/END SUB blocks.`);
};
// --- Main Execution Logic ---
const run = (code, outputCb, promptCb, endCb) => {
console.log('[DreamOS Debug] DreamScriptInterpreter: Running code...');
resetState();
state.lines = code.split('\n').map(line => line.trim());
_scanForSubroutines(); // Scan for subroutines after lines are loaded.
state.onOutput = outputCb;
state.onPrompt = promptCb;
state.onEnd = endCb;
resume();
};
const resume = (inputValue) => {
if (state.isWaitingForInput) {
const value = (inputValue === null || inputValue === "" || isNaN(inputValue)) ? inputValue : parseFloat(inputValue);
setVariable(state.inputVarName, value);
state.isWaitingForInput = false;
}
// Loop indefinitely until paused for input or script ends
while (true) {
if (state.pc >= state.lines.length) {
console.log('[DreamOS Debug] DreamScriptInterpreter: End of script.');
if (state.onEnd) state.onEnd();
return;
}
const line = state.lines[state.pc];
const uLine = line.toUpperCase();
let command = uLine.split(/\s+/)[0];
try {
// --- Pre-execution command handling (loops, etc.) ---
if (command === 'WEND') {
if (state.loopStack.length > 0) {
const loop = state.loopStack[state.loopStack.length - 1];
if (evaluate(loop.condition)) {
state.pc = loop.startPc; // Jump back to line after WHILE
continue;
} else {
state.loopStack.pop(); // End of loop
}
}
}
// --- Regular statement execution ---
if (line === '' || uLine.startsWith("'") || command === 'REM') {
// Skip comments and empty lines
} else if (command === 'PRINT') {
const expr = line.substring(5).trim();
state.onOutput(evaluate(expr));
} else if (command === 'INPUT') {
const inputParts = line.match(/INPUT\s*(?:"([^"]*)")?,\s*([A-Z_][A-Z0-9_$\s]*)/i);
if (!inputParts) throw new Error('Syntax error in INPUT');
const [, promptMsg = '? ', varName] = inputParts;
state.isWaitingForInput = true;
state.inputVarName = varName.trim();
state.onPrompt(promptMsg);
return; // PAUSE EXECUTION
} else if (command === 'DIM') {
const varName = line.substring(3).trim().split(' ')[0];
setVariable(varName, null);
} else if (uLine.startsWith('IF ')) {
const match = line.match(/IF\s+(.*)\s+THEN/i);
if (!match) throw new Error(`Syntax error in IF: ${line}`);
if (!evaluate(match[1])) {
// Condition is false, skip to ELSE or END IF
let depth = 1;
while (state.pc < state.lines.length - 1) {
state.pc++;
const nextLine = state.lines[state.pc].trim().toUpperCase();
if (nextLine.startsWith('IF ')) depth++;
else if (nextLine === 'END IF') depth--;
else if (depth === 1 && (nextLine === 'ELSE' || nextLine.startsWith('ELSEIF '))) {
state.pc--; // Let the next loop iteration handle the ELSE/ELSEIF
break;
}
if (depth === 0) {
state.pc--; // Found END IF, let next loop handle line after it
break;
}
}
}
} else if (uLine === 'ELSE' || uLine.startsWith('ELSEIF ')) {
// If we reach an ELSE, it means the IF was true, so skip to END IF
let depth = 1;
while (state.pc < state.lines.length - 1) {
state.pc++;
const nextLine = state.lines[state.pc].trim().toUpperCase();
if (nextLine.startsWith('IF ')) depth++;
else if (nextLine === 'END IF') depth--;
if (depth === 0) {
state.pc--;
break;
}
}
} else if (uLine === 'END IF') {
// Do nothing, just moves to next line
} else if (uLine.startsWith('WHILE ')) {
const condition = line.substring(5).trim();
if (evaluate(condition)) {
state.loopStack.push({ startPc: state.pc + 1, condition: condition });
} else {
// Skip to WEND
let depth = 1;
while (state.pc < state.lines.length - 1) {
state.pc++;
const nextLine = state.lines[state.pc].trim().toUpperCase();
if (nextLine.startsWith('WHILE ')) depth++;
else if (nextLine === 'WEND') depth--;
if (depth === 0) break;
}
}
} else if (uLine.startsWith('SUB ')) {
// This is a definition, skip to its corresponding END SUB
let depth = 1;
while (state.pc < state.lines.length - 1) {
state.pc++;
const nextLine = state.lines[state.pc].toUpperCase();
if (nextLine.startsWith('SUB ')) depth++;
else if (nextLine === 'END SUB') depth--;
if (depth === 0) break;
}
} else if (command === 'CALL') {
const subName = line.substring(5).trim().toUpperCase();
if (!state.subroutines[subName]) {
throw new Error(`Subroutine not found: ${subName}`);
}
state.callStack.push(state.pc); // Push current address for return
state.scopes.push({}); // New scope for the subroutine
state.pc = state.subroutines[subName].startPc;
continue; // Jump to subroutine, do not increment pc
} else if (command === 'END SUB') {
if (state.callStack.length === 0) {
throw new Error('END SUB without CALL');
}
state.scopes.pop(); // Pop subroutine's scope
state.pc = state.callStack.pop(); // Pop return address
} else if (command === 'SYSCALL') {
// SYSCALL "Module.function", arg1, "arg2", ...
// The result is stored in the 'RESULT' variable.
const argString = line.substring(7).trim();
const parts = argString.match(/(?:[^,"]+|"[^"]*")+/g) || [];
if (parts.length === 0) throw new Error("SYSCALL requires a function path.");
const funcPath = evaluate(parts[0]);
const args = parts.slice(1).map(arg => evaluate(arg));
const pathParts = funcPath.split('.');
let context = window;
let func = pathParts.reduce((obj, part) => {
context = obj; // Keep track of the object before the final function
return obj ? obj[part] : undefined;
}, window);
if (typeof func !== 'function') throw new Error(`SYSCALL error: '${funcPath}' is not a function.`);
setVariable('RESULT', func.apply(context, args));
} else {
// Default to assignment
const assignmentMatch = line.match(/^(.+?)\s*=\s*(.+)$/);
if (assignmentMatch) {
const lhs = assignmentMatch[1].trim();
const rhs = assignmentMatch[2].trim();
setVariable(lhs, evaluate(rhs));
} else {
throw new Error(`Unknown command: ${command}`);
}
}
} catch (e) {
const errorMsg = `RUNTIME ERROR (line ${state.pc + 1}): ${e.message}`;
console.error(errorMsg);
state.onOutput(errorMsg);
if (state.onEnd) state.onEnd();
return; // Halt execution
}
state.pc++; // Move to the next line
}
};
// For the IDE, a synchronous runner that uses prompt()
const runSync = (code) => {
let syncOutput = '';
run(
code,
(text) => { syncOutput += text + '\n'; }, // onOutput
(promptMsg) => { // onPrompt
const userInput = prompt(promptMsg);
// Immediately resume with the input
resume(userInput);
},
() => {} // onEnd
);
return syncOutput;
};
const interpreter_init = () => {
if (window.DreamCluster) {
console.log('[DreamOS Debug] DreamScriptInterpreter: Setting up cluster message listener.');
// This part is not fully integrated with the new async model yet.
}
};
return { run, resume, runSync, init: interpreter_init };
})();
window.DreamScriptApp = (() => {
let ideWindow, codeArea, outputArea, runBtn, saveBtn, loadBtn, filenameInput, helpBtn, highlightingEl, helpWindow, helpContent;
const DREAMSCRIPT_HELP_HTML = `
<div class="toc">
<h3>Table of Contents</h3>
<ul>
<li><a href="#intro">Introduction</a></li>
<li><a href="#comments">Comments</a></li>
<li><a href="#variables">Variables & Assignment</a></li>
<li><a href="#control-flow">Control Flow</a></li>
<li><a href="#io">Input/Output</a></li>
<li><a href="#subs">Subroutines</a></li>
<li><a href="#syscall">System Calls</a></li>
<li><a href="#cluster">Cluster Commands</a></li>
</ul>
</div>
<h2 id="intro">Introduction</h2>
<p>DreamScript is a modern, structured scripting language for DreamOS. It does not use line numbers and supports modern control flow.</p>
<h2 id="comments">Comments</h2>
<p>Comments are ignored by the interpreter and are used for code documentation.</p>
<pre><code>' This is a comment
REM This is also a comment</code></pre>
<h2 id="variables">Variables & Assignment</h2>
<p>Variables hold data. They can be explicitly declared with <code>DIM</code> or implicitly on first assignment.</p>
<h3>Declaration</h3>
<pre><code>DIM my_variable</code></pre>
<h3>Operators</h3>
<p>Supports <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code> for numbers, and <code>+</code> for string concatenation. Expressions are evaluated left-to-right without operator precedence.</p>
<h3>Assignment</h3>
<pre><code>my_variable = 10
my_string = "Hello, World!"</code></pre>
<h2 id="control-flow">Control Flow</h2>
<p>Control the order of execution.</p>
<h3>IF...THEN...ELSE</h3>
<pre><code>IF a = 10 THEN
PRINT "a is 10"
ELSEIF a = 20 THEN
PRINT "a is 20"
ELSE
PRINT "a is something else"
END IF</code></pre>
<h3>WHILE...WEND Loop</h3>
<pre><code>DIM i = 0
WHILE i < 5
PRINT i
i = i + 1
WEND</code></pre>
<h2 id="io">Input/Output</h2>
<h3>PRINT</h3>
<p>Displays text or variable values to the output panel.</p>
<pre><code>PRINT "Hello"
PRINT my_variable</code></pre>
<h3>INPUT</h3>
<p>Prompts the user for input and stores it in a variable.</p>
<pre><code>INPUT "What is your name?", user_name</code></pre>
<h2 id="subs">Subroutines</h2>
<p>Define reusable blocks of code. They have their own variable scope.</p>
<pre><code>PRINT "Calling sub..."
CALL MySub
PRINT "Returned from sub."
SUB MySub
PRINT "Inside the subroutine!"
END SUB</code></pre>
<h2 id="syscall">System Calls</h2>
<p>Execute underlying JavaScript functions. The return value is placed in the special <code>RESULT</code> variable.</p>
<pre><code>SYSCALL "VFS.readFile", "c:\\boot.ini"
PRINT RESULT</code></pre>
<h2 id="cluster">Cluster Commands</h2>
<p>Interact with the DreamOS cluster network.</p>
<h3>CLUSTER BROADCAST</h3>
<p>Sends a message to all connected peers.</p>
<pre><code>CLUSTER BROADCAST "Hello everyone!"</code></pre>
<h3>PEEKMSG$</h3>
<p>A special read-only variable that retrieves the oldest message from the incoming network queue. It returns an empty string if no messages are waiting.</p>
<pre><code>' This is not fully supported in the async interpreter yet
DIM msg = PEEKMSG$
PRINT msg</code></pre>
`;
const updateHighlighting = () => {
const code = codeArea.value;
const escapedCode = code.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
const tokenRegex = new RegExp(
`(?<comment>'.*|REM.*)|` + // Comments
`(?<string>".*?")|` + // Strings
`(?<keyword>\\b(?:PRINT|INPUT|IF|THEN|ELSEIF|ELSE|END IF|FOR|TO|STEP|NEXT|WHILE|WEND|DIM|SUB|END SUB|FUNCTION|END FUNCTION|CLASS|END CLASS|NEW|CALL|CLUSTER|BROADCAST|PEEKMSG\\$)\\b)|` + // Keywords
`(?<number>\\b\\d+(?:\\.\\d+)?\\b)|` + // Numbers
`(?<variable>\\b[A-Z_][A-Z0-9_]*\\$?\\b)`, // Variables
'gim'
);
const highlightedCode = escapedCode.replace(tokenRegex, (match, ...args) => {
const groups = args[args.length - 1];
for (const tokenType in groups) {
if (groups[tokenType]) {
// Use 'ds-' prefix for DreamScript styles
return `<span class="ds-${tokenType}">${groups[tokenType]}</span>`;
}
}
return match;
});
highlightingEl.querySelector('code').innerHTML = highlightedCode;
};
const syncScroll = () => {
highlightingEl.scrollTop = codeArea.scrollTop;
highlightingEl.scrollLeft = codeArea.scrollLeft;
};
const init = () => {
console.log('[DreamOS Debug] DreamScriptApp: Initializing...');
ideWindow = document.getElementById('dreamscript-ide-window');
codeArea = document.getElementById('dreamscript-ide-code');
outputArea = document.getElementById('dreamscript-ide-output');
highlightingEl = document.getElementById('dreamscript-ide-highlighting');
runBtn = document.getElementById('dreamscript-ide-execute-btn');
saveBtn = document.getElementById('dreamscript-ide-save-btn');
loadBtn = document.getElementById('dreamscript-ide-load-btn');
filenameInput = document.getElementById('dreamscript-ide-filename');
helpBtn = document.getElementById('dreamscript-ide-help-btn');
helpWindow = document.getElementById('dreamscript-help-window');
helpContent = document.getElementById('dreamscript-help-content');
runBtn.addEventListener('click', onRun);
saveBtn.addEventListener('click', onSave);
loadBtn.addEventListener('click', onLoad);
helpBtn.addEventListener('click', onHelp);
codeArea.addEventListener('input', updateHighlighting);
codeArea.addEventListener('scroll', syncScroll);
DreamScriptInterpreter.init();
console.log('[DreamOS Debug] DreamScriptApp: Initialized successfully.');
};
const open = (path = '', content = '') => {
console.log(`[DreamOS Debug] DreamScriptApp: Opening with path: "${path}"`);
if (!ideWindow) {
console.error("DreamScript IDE not initialized.");
return;
}
ideWindow.classList.remove('hidden');
WindowManager.focusOrRestore('dreamscript-ide-window');
filenameInput.value = path;
codeArea.value = content;
outputArea.innerText = 'Ready.';
codeArea.focus();
updateHighlighting();
syncScroll();
};
const onHelp = () => {
if (!helpWindow) return;
helpContent.innerHTML = DREAMSCRIPT_HELP_HTML;
helpWindow.classList.remove('hidden');
WindowManager.focusOrRestore('dreamscript-help-window');
};
const onRun = () => {
const code = codeArea.value;
outputArea.innerText = 'Running...\n';
// The IDE uses the synchronous runner with blocking prompts
const result = DreamScriptInterpreter.runSync(code);
outputArea.innerText = 'Done.\n------\n';
outputArea.innerText += result;
};
const onSave = () => {
const path = filenameInput.value;
if (!path) {
outputArea.innerText = "Error: Filename is required to save.";
return;
}
const result = Kernel.writeFile(path, codeArea.value);
outputArea.innerText = result.message;
};
const onLoad = () => {
const path = filenameInput.value;
if (!path) {
outputArea.innerText = "Error: Filename is required to load.";
return;
}
const result = Kernel.readFile(path);
if (result.success) {
codeArea.value = result.content;
updateHighlighting();
outputArea.innerText = `Successfully loaded ${result.path}`;
} else {
outputArea.innerText = result.message;
}
};
return { open: open,
init: init };
})();
/*
* Copyright (c) 2026 Nicholas Paul Wilde. All rights reserved.
* DREAMOS CHESS - A simple chess game app
*/
window.ChessApp = (() => {
// --- DOM Elements ---
let chessWindow, boardEl, statusEl, newGameBtn;
// --- Game State ---
let board = [];
let turn = 'w';
let selectedSquare = null;
let gameOver = false;
let playerColor = 'w';
let moveHistory = [];
// --- Constants ---
const PIECES = {
'wk': '♔', 'wq': '♕', 'wr': '♖', 'wb': '♗', 'wn': '♘', 'wp': '♙',
'bk': '♚', 'bq': '♛', 'br': '♜', 'bb': '♝', 'bn': '♞', 'bp': '♟︎'
};
const MATERIAL = { 'p': 1, 'n': 3, 'b': 3, 'r': 5, 'q': 9, 'k': 100 };
const AI_THINK_TIME = 250; // ms
const SEARCH_DEPTH = 2; // How many moves ahead the AI looks. 2 is reasonable.
// --- Private Engine Functions ---
const _getPiece = (r, c) => (board[r] && board[r][c]) ? board[r][c] : null;
const _isOpponent = (r, c, color) => {
const piece = _getPiece(r, c);
return piece && piece.color !== color;
};
const _isValid = (r, c) => r >= 0 && r < 8 && c >= 0 && c < 8;
const _getPieceLegalMoves = (r, c) => {
const piece = _getPiece(r, c);
if (!piece) return [];
const moves = [];
const { type, color } = piece;
const addMove = (tr, tc) => {
if (_isValid(tr, tc) && (!_getPiece(tr, tc) || _isOpponent(tr, tc, color))) {
moves.push({ from: [r, c], to: [tr, tc] });
}
};
const addSlidingMoves = (dirs) => {
for (const [dr, dc] of dirs) {
for (let i = 1; i < 8; i++) {
const tr = r + i * dr, tc = c + i * dc;
if (!_isValid(tr, tc)) break;
const targetPiece = _getPiece(tr, tc);
if (targetPiece) {
if (targetPiece.color !== color) addMove(tr, tc);
break;
}
addMove(tr, tc);
}
}
};
switch (type) {
case 'p': // Pawn
const dir = color === 'w' ? -1 : 1;
const startRow = color === 'w' ? 6 : 1;
// Forward 1
if (_isValid(r + dir, c) && !_getPiece(r + dir, c)) {
addMove(r + dir, c);
// Forward 2 from start
if (r === startRow && !_getPiece(r + 2 * dir, c)) {
addMove(r + 2 * dir, c);
}
}
// Captures
[-1, 1].forEach(dc => {
if (_isValid(r + dir, c + dc) && _isOpponent(r + dir, c + dc, color)) {
addMove(r + dir, c + dc);
}
});
// En passant
const lastMove = moveHistory[moveHistory.length - 1];
if (lastMove && _getPiece(lastMove.to[0], lastMove.to[1])?.type === 'p' && Math.abs(lastMove.from[0] - lastMove.to[0]) === 2) {
if (r === lastMove.to[0] && Math.abs(c - lastMove.to[1]) === 1) {
moves.push({ from: [r, c], to: [r + dir, lastMove.to[1]], enPassant: true });
}
}
break;
case 'r': addSlidingMoves([[0, 1], [0, -1], [1, 0], [-1, 0]]); break;
case 'b': addSlidingMoves([[1, 1], [1, -1], [-1, 1], [-1, -1]]); break;
case 'q': addSlidingMoves([[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]]); break;
case 'n':
[[1, 2], [1, -2], [-1, 2], [-1, -2], [2, 1], [2, -1], [-2, 1], [-2, -1]].forEach(([dr, dc]) => addMove(r + dr, c + dc));
break;
case 'k':
[[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]].forEach(([dr, dc]) => addMove(r + dr, c + dc));
// Castling
if (!piece.hasMoved) {
// Kingside
const rRook = _getPiece(r, 7);
if (rRook?.type === 'r' && !rRook.hasMoved && !_getPiece(r, 5) && !_getPiece(r, 6)) {
if (!_isSquareAttackedBy(r, 4, color === 'w' ? 'b' : 'w') && !_isSquareAttackedBy(r, 5, color === 'w' ? 'b' : 'w')) {
moves.push({ from: [r, c], to: [r, 6], castling: 'kingside' });
}
}
// Queenside
const lRook = _getPiece(r, 0);
if (lRook?.type === 'r' && !lRook.hasMoved && !_getPiece(r, 1) && !_getPiece(r, 2) && !_getPiece(r, 3)) {
if (!_isSquareAttackedBy(r, 4, color === 'w' ? 'b' : 'w') && !_isSquareAttackedBy(r, 3, color === 'w' ? 'b' : 'w')) {
moves.push({ from: [r, c], to: [r, 2], castling: 'queenside' });
}
}
}
break;
}
return moves;
};
const _isSquareAttackedBy = (r, c, attackerColor) => {
for (let i = 0; i < 8; i++) {
for (let j = 0; j < 8; j++) {
const piece = _getPiece(i, j);
if (piece && piece.color === attackerColor) {
const moves = _getPieceLegalMoves(i, j); // Simplified check, doesn't check for pins
if (moves.some(m => m.to[0] === r && m.to[1] === c)) {
return true;
}
}
}
}
return false;
};
const _findKing = (color) => {
for (let i = 0; i < 8; i++) {
for (let j = 0; j < 8; j++) {
const piece = _getPiece(i, j);
if (piece && piece.type === 'k' && piece.color === color) {
return [i, j];
}
}
}
return null;
};
const _isKingInCheck = (color) => {
const kingPos = _findKing(color);
if (!kingPos) return false;
return _isSquareAttackedBy(kingPos[0], kingPos[1], color === 'w' ? 'b' : 'w');
};
const _getAllLegalMoves = (color) => {
let allMoves = [];
for (let r = 0; r < 8; r++) {
for (let c = 0; c < 8; c++) {
const piece = _getPiece(r, c);
if (piece && piece.color === color) {
_getPieceLegalMoves(r, c).forEach(move => {
// Test move to see if it leaves king in check
const captured = _makeMove(move);
if (!_isKingInCheck(color)) {
allMoves.push(move);
}
_undoMove(move, captured);
});
}
}
}
return allMoves;
};
const _makeMove = (move) => {
const [fr, fc] = move.from;
const [tr, tc] = move.to;
const piece = { ..._getPiece(fr, fc), hasMoved: true };
const captured = _getPiece(tr, tc);
board[tr][tc] = piece;
board[fr][fc] = null;
// Pawn promotion
if (piece.type === 'p' && (tr === 0 || tr === 7)) {
board[tr][tc].type = 'q';
}
// En passant capture
if (move.enPassant) {
const capturedPawnPos = [fr, tc];
const capturedPawn = _getPiece(capturedPawnPos[0], capturedPawnPos[1]);
board[capturedPawnPos[0]][capturedPawnPos[1]] = null;
return capturedPawn; // Special return for undo
}
// Castling
if (move.castling) {
if (move.castling === 'kingside') {
board[fr][5] = board[fr][7];
board[fr][7] = null;
} else { // queenside
board[fr][3] = board[fr][0];
board[fr][0] = null;
}
}
moveHistory.push(move);
return captured;
};
const _undoMove = (move, captured) => {
const [fr, fc] = move.from;
const [tr, tc] = move.to;
const piece = _getPiece(tr, tc);
// If it was a promotion, revert it
if (move.promotion) piece.type = 'p';
board[fr][fc] = piece;
board[tr][tc] = captured; // Can be null
// Undo en passant
if (move.enPassant) {
board[tr][tc] = null;
board[fr][tc] = captured;
}
// Undo castling
if (move.castling) {
if (move.castling === 'kingside') {
board[fr][7] = board[fr][5];
board[fr][5] = null;
} else { // queenside
board[fr][0] = board[fr][3];
board[fr][3] = null;
}
}
moveHistory.pop();
};
const _getGameState = () => {
const legalMoves = _getAllLegalMoves(turn);
if (legalMoves.length === 0) {
return _isKingInCheck(turn) ? 'checkmate' : 'stalemate';
}
if (_isKingInCheck(turn)) return 'check';
return 'playing';
};
// --- Private AI Functions ---
const _evaluateBoard = () => {
let score = 0;
for (let r = 0; r < 8; r++) {
for (let c = 0; c < 8; c++) {
const piece = _getPiece(r, c);
if (piece) {
score += MATERIAL[piece.type] * (piece.color === 'w' ? 1 : -1);
}
}
}
return score;
};
const _minimax = (depth, alpha, beta, isMaximizing) => {
if (depth === 0) return _evaluateBoard();
const color = isMaximizing ? 'w' : 'b';
const legalMoves = _getAllLegalMoves(color);
if (legalMoves.length === 0) {
if (_isKingInCheck(color)) return isMaximizing ? -Infinity : Infinity; // Checkmate
return 0; // Stalemate
}
if (isMaximizing) {
let maxEval = -Infinity;
for (const move of legalMoves) {
const captured = _makeMove(move);
const evaluation = _minimax(depth - 1, alpha, beta, false);
_undoMove(move, captured);
maxEval = Math.max(maxEval, evaluation);
alpha = Math.max(alpha, evaluation);
if (beta <= alpha) break;
}
return maxEval;
} else {
let minEval = Infinity;
for (const move of legalMoves) {
const captured = _makeMove(move);
const evaluation = _minimax(depth - 1, alpha, beta, true);
_undoMove(move, captured);
minEval = Math.min(minEval, evaluation);
beta = Math.min(beta, evaluation);
if (beta <= alpha) break;
}
return minEval;
}
};
const _findBestMove = () => {
const legalMoves = _getAllLegalMoves(turn);
if (legalMoves.length === 0) return null;
let bestMove = null;
let bestValue = turn === playerColor ? -Infinity : Infinity;
for (const move of legalMoves) {
const captured = _makeMove(move);
const boardValue = _minimax(SEARCH_DEPTH - 1, -Infinity, Infinity, turn !== playerColor);
_undoMove(move, captured);
if (turn === playerColor) { // Player is maximizing
if (boardValue > bestValue) {
bestValue = boardValue;
bestMove = move;
}
} else { // AI is minimizing
if (boardValue < bestValue) {
bestValue = boardValue;
bestMove = move;
}
}
}
return bestMove || legalMoves[Math.floor(Math.random() * legalMoves.length)]; // Fallback
};
const _makeAIMove = () => {
if (gameOver || turn === playerColor) return;
_updateStatus("Computer is thinking...");
setTimeout(() => {
const bestMove = _findBestMove();
if (bestMove) {
_makeMove(bestMove);
turn = playerColor;
_drawBoard();
_checkGameState();
}
}, AI_THINK_TIME);
};
// --- Private UI Functions ---
const _createBoardUI = () => {
boardEl.innerHTML = '';
for (let r = 0; r < 8; r++) {
for (let c = 0; c < 8; c++) {
const square = document.createElement('div');
square.className = `chess-square ${(r + c) % 2 === 0 ? 'light' : 'dark'}`;
square.dataset.r = r;
square.dataset.c = c;
boardEl.appendChild(square);
}
}
boardEl.addEventListener('click', _onSquareClick);
};
const _drawBoard = () => {
document.querySelectorAll('.chess-square').forEach(sq => {
sq.innerHTML = ''; // Clear piece and dots
sq.classList.remove('selected');
});
for (let r = 0; r < 8; r++) {
for (let c = 0; c < 8; c++) {
const piece = _getPiece(r, c);
if (piece) {
const squareEl = boardEl.querySelector(`[data-r='${r}'][data-c='${c}']`);
const pieceEl = document.createElement('span');
pieceEl.className = 'chess-piece';
pieceEl.innerText = PIECES[piece.color + piece.type];
squareEl.appendChild(pieceEl);
}
}
}
};
const _updateStatus = (message) => {
statusEl.innerText = message;
};
const _checkGameState = () => {
const state = _getGameState();
let message = turn === 'w' ? "White's turn" : "Black's turn";
switch (state) {
case 'check':
message += ' - Check!';
break;
case 'checkmate':
message = `Checkmate! ${turn === 'w' ? 'Black' : 'White'} wins.`;
gameOver = true;
break;
case 'stalemate':
message = "Stalemate! It's a draw.";
gameOver = true;
break;
}
_updateStatus(message);
return state;
};
const _onSquareClick = (e) => {
if (gameOver || turn !== playerColor) return;
const square = e.target.closest('.chess-square');
if (!square) return;
const r = parseInt(square.dataset.r);
const c = parseInt(square.dataset.c);
if (selectedSquare) {
const [sr, sc] = selectedSquare;
const legalMoves = _getAllLegalMoves(playerColor).filter(m => m.from[0] === sr && m.from[1] === sc);
const move = legalMoves.find(m => m.to[0] === r && m.to[1] === c);
if (move) {
_makeMove(move);
turn = playerColor === 'w' ? 'b' : 'w';
selectedSquare = null;
_drawBoard();
if (_checkGameState() !== 'checkmate') {
_makeAIMove();
}
} else {
selectedSquare = null;
_drawBoard(); // Clear highlights
}
} else {
const piece = _getPiece(r, c);
if (piece && piece.color === playerColor) {
selectedSquare = [r, c];
_drawBoard(); // Clear old highlights
square.classList.add('selected');
const legalMoves = _getAllLegalMoves(playerColor).filter(m => m.from[0] === r && m.from[1] === c);
legalMoves.forEach(m => {
const targetSquare = boardEl.querySelector(`[data-r='${m.to[0]}'][data-c='${m.to[1]}']`);
const dot = document.createElement('div');
dot.className = 'legal-move-dot';
targetSquare.appendChild(dot);
});
}
}
};
const _startNewGame = () => {
const initialBoard = [
['br', 'bn', 'bb', 'bq', 'bk', 'bb', 'bn', 'br'],
['bp', 'bp', 'bp', 'bp', 'bp', 'bp', 'bp', 'bp'],
[null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null],
['wp', 'wp', 'wp', 'wp', 'wp', 'wp', 'wp', 'wp'],
['wr', 'wn', 'wb', 'wq', 'wk', 'wb', 'wn', 'wr'],
];
board = initialBoard.map(row => row.map(p => p ? { color: p[0], type: p[1], hasMoved: false } : null));
turn = 'w';
playerColor = 'w';
gameOver = false;
selectedSquare = null;
moveHistory = [];
_drawBoard();
_updateStatus("New game. White's turn.");
};
// --- Public API ---
const init = () => {
console.log('[DreamOS Debug] ChessApp: Initializing...');
chessWindow = document.getElementById('chess-window');
boardEl = document.getElementById('chessboard');
statusEl = document.getElementById('chess-status-bar');
newGameBtn = document.getElementById('chess-new-game-btn');
_createBoardUI();
newGameBtn.addEventListener('click', _startNewGame);
console.log('[DreamOS Debug] ChessApp: Initialized successfully.');
};
const open = () => {
console.log(`[DreamOS Debug] ChessApp: Opening...`);
if (!chessWindow) {
console.error("Chess app not initialized.");
return;
}
chessWindow.classList.remove('hidden');
_startNewGame();
};
return { init, open };
})();
/*
* Copyright (c) 2026 Nicholas Paul Wilde. All rights reserved.
* DREAMOS ADVENTURE - A data-driven text adventure game engine
*/
window.AdventureApp = (() => {
// --- DOM Elements ---
let adventureWindow, outputEl, inputEl;
let scriptCode = '';
// --- Private UI Functions ---
const _appendToOutput = (text, className = '') => {
// The interpreter might send numbers, so ensure text is a string.
text = String(text);
const line = document.createElement('div');
if (className) line.className = className;
line.innerHTML = text.replace(/\n/g, '<br>');
outputEl.appendChild(line);
outputEl.scrollTop = outputEl.scrollHeight;
};
const _handleScriptOutput = (text) => {
_appendToOutput(text);
};
const _handleScriptPrompt = (promptMsg) => {
_appendToOutput(promptMsg, 'command-echo');
inputEl.disabled = false;
inputEl.focus();
};
const _handleScriptEnd = () => {
_appendToOutput("\n[The adventure has ended. Reload the window to play again.]", "command-echo");
inputEl.disabled = true;
};
const _onInput = (e) => {
if (e.key === 'Enter') {
const command = inputEl.value;
_appendToOutput(`> ${command}`, 'command-echo');
inputEl.value = '';
inputEl.disabled = true;
// Resume the interpreter with the user's command
DreamScriptInterpreter.resume(command);
}
};
const _startNewGame = () => {
outputEl.innerHTML = '';
_appendToOutput("Loading DreamScript Adventure...");
DreamScriptInterpreter.run(scriptCode, _handleScriptOutput, _handleScriptPrompt, _handleScriptEnd);
};
// --- Public API ---
const init = () => {
console.log('[DreamOS Debug] AdventureApp: Initializing...');
adventureWindow = document.getElementById('adventure-window');
outputEl = document.getElementById('adventure-output');
inputEl = document.getElementById('adventure-input');
if (!adventureWindow || !outputEl || !inputEl) {
console.error("AdventureApp Error: A required DOM element is missing.");
return;
}
inputEl.addEventListener('keydown', _onInput);
// Load the adventure script from the VFS
const scriptFile = Kernel.readFile("C:\\inetpub\\wwwroot\\adventure.ds");
if (scriptFile.success) {
scriptCode = scriptFile.content;
} else {
scriptCode = `PRINT "Error: Could not load adventure.ds from VFS."`;
}
console.log('[DreamOS Debug] AdventureApp: Initialized successfully.');
};
const open = () => {
console.log(`[DreamOS Debug] AdventureApp: Opening...`);
if (!adventureWindow) {
console.error("Adventure app not initialized.");
return;
}
adventureWindow.classList.remove('hidden');
WindowManager.focusOrRestore('adventure-window');
_startNewGame();
inputEl.focus();
};
return { init, open };
})();
/*
* Copyright (c) 2026 Nicholas Paul Wilde. All rights reserved.
* DREAMOS SHELL - User Interface & Terminal Controller
*/
console.log('[DreamOS Debug] Shell: Starting initialization.');
const input = document.getElementById('command-input');
const output = document.getElementById('output');
const clock = document.getElementById('clock');
const startBtn = document.getElementById('start-btn');
const startMenu = document.getElementById('start-menu');
const vddOverlay = document.getElementById('vdd-overlay');
const vddStatus = document.getElementById('vdd-status');
const promptText = document.getElementById('prompt-text');
const terminalWindow = document.getElementById('terminal-window');
const taskbarAppsContainer = document.getElementById('taskbar-apps');
const mainFrame = document.getElementById('main-frame');
console.log('[DreamOS Debug] Shell: DOM elements cached.');
// Initialize App Modules
console.log('[DreamOS Debug] Shell: Initializing EditApp...');
EditApp.init();
console.log('[DreamOS Debug] Shell: EditApp initialized.');
console.log('[DreamOS Debug] Shell: Initializing DreamScriptApp...');
DreamScriptApp.init();
console.log('[DreamOS Debug] Shell: DreamScriptApp initialized.');
console.log('[DreamOS Debug] Shell: Initializing ChessApp...');
ChessApp.init();
console.log('[DreamOS Debug] Shell: ChessApp initialized.');
console.log('[DreamOS Debug] Shell: Initializing AdventureApp...');
AdventureApp.init();
console.log('[DreamOS Debug] Shell: AdventureApp initialized.');
console.log('[DreamOS Debug] Shell: Initializing HelpApp...');
HelpApp.init();
console.log('[DreamOS Debug] Shell: HelpApp initialized.');
console.log('[DreamOS Debug] Shell: Initializing WindowManager...');
WindowManager.init();
console.log('[DreamOS Debug] Shell: WindowManager initialized.');
// --- INITIALIZATION ---
const updateClock = () => {
const now = new Date();
clock.innerText = now.getHours().toString().padStart(2, '0') + ':' +
now.getMinutes().toString().padStart(2, '0');
};
updateClock();
setInterval(updateClock, 1000);
console.log('[DreamOS Debug] Shell: Clock setup complete.');
// --- Cluster Initialization with Password ---
console.log('[DreamOS Debug] Shell: Starting cluster initialization...');
// We ask for a password once. A loop is avoided to prevent the UI from freezing
// if the prompt is blocked by the browser or the user enters an empty string.
const passwordPromptMessage =
'Welcome to the DreamOS Cluster!\n\n' +
'Please enter a shared password. This will be used to create a private network.\n' +
'All nodes you want to connect MUST use the exact same password.';
let encryptionKey;
try {
// This can be blocked by the browser when loaded over http, sometimes throwing an error.
encryptionKey = prompt(passwordPromptMessage);
} catch (e) {
console.error("The password prompt was blocked by the browser, causing an error:", e);
encryptionKey = null; // Ensure key is null on error so the script can continue.
}
// An empty string or null (from cancel/block) are both invalid for the key.
// The `if (encryptionKey)` check correctly handles null, undefined, and "" as falsy.
if (encryptionKey) {
console.log('[DreamOS Debug] Shell: Password provided. Initializing DreamCluster.');
DreamCluster.init(encryptionKey, (status) => {
if (!status.connected) {
appendToOutput(`[Cluster] ${status.message}`);
}
});
} else {
appendToOutput("[Cluster] Initialization skipped: No valid password provided.");
console.log('[DreamOS Debug] Shell: No password. Skipping cluster initialization.');
}
console.log('[DreamOS Debug] Shell: Cluster initialization finished.');
const refreshVDD = () => {
const status = HAL.getPowerStatus();
vddOverlay.innerText = `VDD_STAT: ${status.gpu} | ${status.vram} | ${status.status}`;
vddStatus.innerText = `WDDM:${status.status}`;
};
refreshVDD();
setInterval(refreshVDD, 5000);
console.log('[DreamOS Debug] Shell: Setting up background music...');
// --- Background Music (Shuffle Mode) ---
// As I cannot browse your website, I've created a placeholder playlist.
// Please replace these with the actual URLs of your MP3 files.
const musicPlaylist = [
'https://nicholaswilde.net/rewind.mp3',
'https://nicholaswilde.net/badbrain.mp3',
'https://nicholaswilde.net/ballpark.mp3',
'https://nicholaswilde.net/country.mp3',
'https://nicholaswilde.net/dcs.mp3',
'https://nicholaswilde.net/death.mp3',
'https://nicholaswilde.net/hack.mp3',
'https://nicholaswilde.net/haha.mp3',
'https://nicholaswilde.net/paranoia.mp3',
'https://nicholaswilde.net/sd.mp3',
'https://nicholaswilde.net/stars.mp3',
'https://nicholaswilde.net/stc.mp3',
'https://nicholaswilde.net/worry.mp3'
];
const backgroundMusic = new Audio();
backgroundMusic.loop = false; // Explicitly disable looping for shuffle to work
// Set volume (optional, default is 1.0)
// backgroundMusic.volume = 0.5;
// Function to play the next random song
const playNextRandomSong = () => {
// Remove any lingering interaction listeners before we start
document.removeEventListener('click', playNextRandomSong);
document.removeEventListener('keydown', playNextRandomSong);
if (musicPlaylist.length === 0) {
console.warn("Music playlist is empty.");
return;
}
const randomIndex = Math.floor(Math.random() * musicPlaylist.length);
backgroundMusic.src = musicPlaylist[randomIndex];
const promise = backgroundMusic.play();
if (promise !== undefined) {
promise.catch(error => {
// Autoplay was prevented. We'll wait for a user interaction.
console.warn("Autoplay prevented by browser. Click or press a key to start music.");
// Add listeners that will try to play again on the first interaction.
document.addEventListener('click', playNextRandomSong, { once: true });
document.addEventListener('keydown', playNextRandomSong, { once: true });
});
}
};
// When a song finishes, play the next random one.
backgroundMusic.addEventListener('ended', playNextRandomSong);
// Delay the initial playback attempt until 5 seconds after the OE fully loads
setTimeout(playNextRandomSong, 5000);
// Expose music controls to the Kernel via the window object
window.musicControls = {
play: () => backgroundMusic.play(),
pause: () => backgroundMusic.pause(),
skip: playNextRandomSong
};
console.log('[DreamOS Debug] Shell: Background music setup complete.');
input.focus();
console.log('[DreamOS Debug] Shell: Focused command input.');
// --- Global Click Handler for Start Menu ---
console.log('[DreamOS Debug] Shell: Attaching global click listener for start menu.');
document.addEventListener('click', (e) => {
// If the click is outside the start menu and not on the start button, hide the menu.
if (!startMenu.contains(e.target) && e.target !== startBtn) {
startMenu.classList.add('hidden');
}
});
// --- Terminal Window Focus Logic ---
console.log('[DreamOS Debug] Shell: Attaching terminal focus listener.');
// When the terminal window itself is clicked, ensure the input field gets focus.
terminalWindow.addEventListener('click', (e) => {
// If the click is inside the terminal window but not on the header, focus the input.
if (!e.target.closest('.window-header')) {
console.log('[DreamOS Debug] Shell: Terminal window clicked, focusing input.');
input.focus();
}
});
// --- INPUT HANDLING ---
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
console.log('[DreamOS Debug] Shell: Enter key pressed in command input.');
const cmd = input.value.trim();
if (cmd) {
const currentPrompt = promptText.innerText;
appendToOutput(`<span class="prompt">${currentPrompt}</span> ${cmd}`);
const result = Kernel.execute(cmd);
// Handle special signals from the kernel for UI actions
if (typeof result === 'object' && result !== null && result.signal) {
if (result.signal === 'KERNEL_SIGNAL_OPEN_DREAMSCRIPT_IDE') {
DreamScriptApp.open();
} else if (result.signal === 'KERNEL_SIGNAL_OPEN_ADVENTURE') {
AdventureApp.open();
} else if (result.signal === 'KERNEL_SIGNAL_OPEN_CHESS') {
ChessApp.open();
} else if (result.signal === 'KERNEL_SIGNAL_OPEN_EDITOR') {
EditApp.open(result.path, result.content); // Call the new EditApp module
} else if (result.signal === 'KERNEL_SIGNAL_OPEN_HELP') {
HelpApp.open();
}
// No text output for signal commands, so we don't fall through
} else if (result === "KERNEL_SIGNAL_CLS") {
output.innerHTML = '';
} else if (result) {
appendToOutput(result);
}
promptText.innerText = VFS.getPath() + ">";
}
input.value = '';
const container = terminalWindow.querySelector('.window-content');
container.scrollTop = container.scrollHeight;
}
});
console.log('[DreamOS Debug] Shell: Attaching start button click listener.');
startBtn.addEventListener('click', (e) => {
console.log('[DreamOS Debug] Shell: Start button clicked.');
e.stopPropagation();
startMenu.classList.toggle('hidden');
});
// --- Start Menu Item Click Handlers ---
console.log('[DreamOS Debug] Shell: Attaching start menu item listeners.');
// We set these up programmatically to ensure all scripts are loaded first.
document.getElementById('start-menu-nwhome').addEventListener('click', () => {
mainFrame.src = 'http://nicholaswilde.net/index.php';
startMenu.classList.add('hidden');
});
document.getElementById('start-menu-fleagrass').addEventListener('click', () => {
mainFrame.src = 'http://fleagrass.com/';
startMenu.classList.add('hidden');
});
document.getElementById('start-menu-dalnet').addEventListener('click', () => {
mainFrame.src = 'https://www.dal.net/webchat/';
startMenu.classList.add('hidden');
});
document.getElementById('start-menu-console').addEventListener('click', () => {
WindowManager.focusOrRestore('terminal-window');
startMenu.classList.add('hidden');
});
document.getElementById('start-menu-notepad').addEventListener('click', () => {
EditApp.open();
startMenu.classList.add('hidden');
});
document.getElementById('start-menu-dreamscript').addEventListener('click', () => {
DreamScriptApp.open();
startMenu.classList.add('hidden');
});
document.getElementById('start-menu-chess').addEventListener('click', () => {
ChessApp.open();
startMenu.classList.add('hidden');
});
document.getElementById('start-menu-adventure').addEventListener('click', () => {
AdventureApp.open();
startMenu.classList.add('hidden');
});
document.getElementById('start-menu-reboot').addEventListener('click', () => location.reload());
console.log('[DreamOS Debug] Shell: All start menu item listeners attached.');
function appendToOutput(text) {
const line = document.createElement('div');
line.innerHTML = String(text).replace(/\n/g, '<br>');
output.appendChild(line);
}
console.log('[DreamOS Debug] Shell: Initialization complete. System is ready.');
</script>
</body>
</html>
Comments
Post a Comment