A retro desktop operating system simulator built with vanilla JavaScript, HTML, and CSS.
IlluminatOS! is a browser-hosted OS simulation with:
- A complete desktop shell (boot screen, desktop, taskbar, start menu, context menus, windows)
- A virtual multi-drive filesystem with persistence
- A large app suite (42 apps spanning productivity, system tools, games, media, communication)
- A modular feature runtime (core features + plugin features)
- A unified semantic event bus with a single command registry, schema-validated events, and owner-scoped subscription tracking
- A full scripting language (RetroScript) with autoexec startup support
- Real-time multiplayer via WebSocket (PHP sidecar) with rooms, presence, game sessions, and collaborative apps
- Optional PHP backend for admin config/auth (v1 file-based) or MySQL-backed multi-user backend (v2) with real-time events, webhooks, and audit logging
index.js initializes the system in ordered phases:
- Load config (
ConfigLoader) - Initialize user session and real-time SSE connection (v2 API only)
- Register apps (
AppRegistry) - Initialize core services (
StorageManager,StateManager,WindowManager,CommandRegistry,ScriptEngine) - Sync filesystem shortcuts and installed apps
- Register and initialize features (
FeatureRegistry) - Load plugin manifest and plugin features (
PluginLoader) - Initialize all features (core + plugin)
- Initialize UI renderers
- Apply persisted settings
- Install global handlers (including
HealthMonitor) - Run
autoexec.retro
Boot health diagnostics are collected per-component and exposed at window.__OS_BOOT_HEALTH. A live runtime snapshot — subscription accounting, storage telemetry, event-bus stats, feature posture, realtime state, and the last 50 faults — is available at window.__OS_HEALTH.
core/SemanticEventBus.js: the single event bus — pub/sub with middleware, request/response, channels, async streams, schema validation, and the unified command registry (registerCommand/executeCommand). (core/EventBus.jsis a one-line re-export so old imports keep working.)core/CommandRegistry.js: wires every platform-level command handler (command:fs:*,command:window:*,command:terminal:*,command:dialog:*,command:app:*,command:setting:*, etc.), thequery:*listeners, and thetimer:*/macro:*lifecycle state into the unifiedSemanticEventBus.commandHandlersregistry. Initialised once at boot; new code callsEventBus.registerCommand/EventBus.executeCommanddirectly.core/SubscriptionManager.js: owner-scoped subscription tracker. Wraps everyEventBus.onandStateManager.subscribeagainst the active owner (window/feature/plugin/session);unsubscribeAll(ownerId)releases the lot.core/EventTopology.js: single registry of every backend event bridged to the frontend;RealtimeClientderives its allowlist from it.core/HealthMonitor.js: live runtime health snapshot — subscription accounting, storage telemetry, event-bus stats + schema coverage, feature posture, realtime state, bounded fault ring buffer. Exposed atwindow.__OS_HEALTH.core/FileSystemManager.js: virtual filesystem and file operations (with server-backed file sync)core/StateManager.js: runtime state + persistence hooks;resetVolatile()clears user-scoped in-memory state for clean user-switchcore/SessionManager.js: single owner of the logout / user-switch cascade — sequences realtime/presence/token/state teardown so subscribers never see a half-torn-down sessioncore/WindowManager.js: window lifecycle, focus/z-order, deterministic modal cleanup (no listener races on rapid close)core/FeatureRegistry.js+core/FeatureBase.js: feature lifecycle/runtime toggling; serialized enable/disable, isolated-failure dependent disable, no init reset on disablecore/PluginLoader.js: plugin manifest, dynamic load/unloadcore/ConfigLoader.js: configuration loading with backend/default fallback; session token APIcore/RealtimeClient.js: SSE real-time event bridge (v2 API)core/NarrativeStateManager.js: campaign/scene/objective/flag/clue state with multiplayer synccore/MultiplayerClient.js: WebSocket client with auto-reconnect, room/presence management; token passed viaSec-WebSocket-Protocol, never in the URLcore/PresenceManager.js: online user tracking, status, and typing indicatorscore/GameSession.js: multiplayer game lifecycle (lobby, turn management, state sync)core/TelemetryCollector.js: event capture, scene funnels, puzzle analyticscore/ReplayEngine.js: deterministic replay from telemetry streamscore/MediaAssetManager.js+core/MediaCueGraph.js: multimedia asset pipeline and cue orchestrationcore/script/*: RetroScript lexer/parser/interpreter/builtinscore/script/utils/PathValidation.js: single allowlist for script-driven file ops (also used by the SSE remote FS handler)
- Apps:
/apps/*.js, registered inapps/AppRegistry.js - Features: classes extending
core/FeatureBase.js - Plugins: manifests in
/plugins/features/<plugin>/index.js - Scripts:
.retrofiles run via Script Runner, terminal, or autoexec
.
├── index.js / index.html # boot + shell
├── apps/ # first-party apps (42 apps)
├── core/ # platform runtime systems
│ ├── script/ # RetroScript engine internals
│ └── schema/ # modular event schema definitions
├── features/ # built-in system features
├── plugins/features/ # plugin-based features
├── ui/ # desktop/taskbar/start/context renderers
├── styles/ # modular CSS
├── config/ # defaults + backend override examples
├── api/ # PHP API v1 (config/auth/save/queue)
│ └── v2/ # REST API v2 router (MySQL backend)
├── backend/ # MySQL-backed backend v2
│ ├── controllers/ # Auth, Config, User, System, Theme, Event, Webhook, Audit, File, Game, Multiplayer, Presence, Social, Message
│ ├── models/ # User, Session, Config, Theme, Event, Webhook, AuditLog, UserFile, UserStateSnapshot, Room, GameSession, GamePlayer, Leaderboard, Friendship, ChatMessage, DirectMessage
│ ├── services/ # EventService, SSEBroadcaster, WebhookDispatcher, FileStorageService
│ └── migrations/ # 19 SQL migration files
├── websocket/ # PHP WebSocket sidecar (multiplayer transport)
│ ├── server.php # WebSocket server entry point (pure PHP)
│ ├── WebSocketFrame.php # RFC 6455 frame encoding/decoding
│ ├── auth.php # Token validation against PHP API
│ ├── rooms.php # Room management logic
│ └── handlers.php # Per-message-type handlers
├── admin/ # web admin panel + component-based UI
│ └── assets/components/ # Dashboard, UserManager, ThemeCreator, etc.
├── assets/ # media resources (sounds, videos)
├── data/ # runtime data storage
├── docs/ # focused docs (terminal scripting, events, stability, assets)
├── setup.php # first-run setup wizard
├── test-backend.php # backend API test suite
├── DEVELOPER_GUIDE.md
└── SCRIPTING_GUIDE.md
python -m http.server 8000
# open http://localhost:8000php -S localhost:8000
# open http://localhost:8000# 1. Copy and configure environment
cp backend/env.example.php backend/env.php
# Edit backend/env.php with your MySQL credentials
# 2. Run migrations (CLI). Web equivalent: api/v2/migrate.php
php backend/migrate.php
# 3. Start server
php -S localhost:8000
# 4. First-run setup wizard (creates the default admin user)
# Visit http://localhost:8000/setup.php# Fetch configured CDN assets (Font Awesome + Google Fonts by default),
# localize CSS dependencies, and rewrite source file CDN URLs to local paths
python scripts/fetch_cdn_assets.pyThis workflow is driven by config/cdn-assets.json. Add any additional CDN URL + output pairs there and rerun the script.
When running with PHP, /api/queue.php provides a server-authoritative queue with:
- Atomic updates via file locking (
flock) for concurrent users - Automatic purge of timed-out queued users
- Automatic expiry/rotation of active turns
- Deterministic next-player promotion
Basic usage:
# Join queue
curl -X POST -d 'action=join&userId=user123&name=Player%201' http://localhost:8000/api/queue.php
# Keepalive heartbeat (queued or active users)
curl -X POST -d 'action=heartbeat&userId=user123' http://localhost:8000/api/queue.php
# Complete turn and promote next player
curl -X POST -d 'action=complete&userId=user123' http://localhost:8000/api/queue.php
# Read shared queue/turn state for all clients/watchers
curl 'http://localhost:8000/api/queue.php?action=status'CLAUDE.md— project instructions and conventions for contributors (and AI assistants)DEVELOPER_GUIDE.md— authoritative guide for adding apps, features, plugins, and script-driven experiencesSCRIPTING_GUIDE.md— RetroScript language, runtime, events, and patternsdocs/RETROSCRIPT_SCRIPTABLE_EVENTS.md— complete event, command, and query reference for scriptingdocs/TERMINAL_SCRIPTING.md— terminal-specific scripting built-ins and workflowsdocs/MIGRATION_ROADMAP.md— short list of deferred follow-ups and deliberate non-decisionsdocs/GREENGEEKS_RESELLER_VPS_WEBSOCKET_SETUP.md— GreenGeeks reseller VPS deployment guide for the WebSocket sidecardocs/walkthrough.md,docs/required_media.md— in-world content for the EREBUS campaign inautoexec.retroplugins/features/dvd-bouncer/README.md— concrete plugin examplebackend/env.example.php— backend v2 environment configuration templateassets/sounds/README.md,assets/music/README.md,assets/videos/README.md— media auto-discovery conventions
- Create
apps/MyApp.jsextendingAppBase - Register it in
apps/AppRegistry.js - Add styling in
styles/apps/my-app.cssand import it fromstyles/main.csswhen needed
- Create a class extending
FeatureBase - Register via
FeatureRegistry.register(...)in boot flow or via plugin - Define settings metadata if you want runtime configuration UI
- Create
plugins/features/my-plugin/ - Add manifest
index.jsexporting{ id, features, apps?, onLoad?, onUnload? } - Add plugin path to config (
config/defaults.jsonplugin list) or manifest source
- Create a
.retroscript under a virtual path (e.g.C:/Scripts) or repo root for autoexec - Use events (
on ...), built-ins (launch,emit,read,write,terminal*) and command bus integrations - Launch from Script Runner, terminal (
retro <path>), or autoexec
| Category | Apps |
|---|---|
| Productivity | Notepad, Browser, Calculator, Calendar, Clock, HyperCard |
| Communication | Inbox (email), Phone, Instant Messenger, Chat Room |
| Media | Media Player (audio + video), Paint |
| Games | Minesweeper, Solitaire, FreeCell, Snake, Asteroids, SkiFree, Zork, Doom, Tetris, DOSBox |
| Multiplayer | Game Lobby |
| System Tools | Terminal, My Computer, Recycle Bin, Task Manager, Find Files, Defrag, Run Dialog, Help System, Script Runner, Analytics Dashboard |
| Narrative/ARG | Campaign Studio, Timeline Editor, Showrunner Console |
| Settings | Control Panel, Display Properties, Sound Settings, Features Settings, Admin Panel |
| Companions | BonziBuddy |
| Feature | Description |
|---|---|
| Sound System | Centralized audio with MP3 support and synthesized fallbacks |
| Achievement System | Unlock milestones with toast notifications |
| Clippy Assistant | Context-aware paperclip assistant with personality |
| Desktop Pet | Animated companion (neko, dog, sheep) with physics |
| Screensaver | Idle screensaver (toasters, starfield, marquee) |
| Easter Eggs | Konami code, cheat codes, and hidden features |
| System Dialogs | Windows 95 style alert, confirm, prompt, file open/save, run, shutdown dialogs |
| Campaign Manager | ARG campaign lifecycle, package install/uninstall |
| Content Template Manager | Reusable narrative content templates |
| Mood Orchestrator | Atmosphere presets, adaptive scoring, CSS effects |
| Online Users | System tray presence indicator for multiplayer |
| Notifications | Toast notifications, sound alerts, taskbar flash |
| Reauth Gate | Prompts for credentials and re-runs the login screen when auth:expired fires |
| DVD Bouncer (plugin) | Bouncing DVD logo screensaver plugin |
- The project is dependency-light and buildless (native ES modules, zero external dependencies; PHP WebSocket sidecar for multiplayer).
- The PHP backend is optional; frontend works without it using defaults/fallbacks.
- Backend v2 adds MySQL-backed user accounts, real-time SSE events, webhooks, themes, announcements, file uploads, and audit logging.
- Multiplayer is provided by a PHP WebSocket sidecar that authenticates against the PHP API. When unavailable, all apps degrade gracefully to single-player mode.
- Multiplayer client defaults to same-origin
/ws(or configurablemultiplayer.websocketPath) for reverse-proxy-friendly HTTPS deployments; setmultiplayer.websocketUrlfor explicit endpoints. - WebSocket authentication is via
Sec-WebSocket-Protocol: token.<hex>; the legacy?token=query string is still accepted server-side but new clients should not use it. - User session lifecycle is unified through
SessionManager(logout()/switchUser()). Listening foruser:login/user:logout/user:switch/auth:expiredevents is the canonical hook for session-scoped resources.features/ReauthGate.jslistens forauth:expiredand re-runs the login screen. - Authenticated HTTP: all v2 API calls go through
fetchWithAuth(input, init)fromConfigLoader, which adds the bearer token and CSRF sentinel header and routes any 401 throughSessionManager.logout({ reason: 'auth_expired' }). - Owner-scoped subscriptions:
SubscriptionManager.runAs(ownerId, fn)wraps every lifecycle entry point so rawEventBus.on(...)calls insideonOpen/onMount/initialize/onLoadare auto-released when the window closes, feature disables, plugin unloads, or session ends. - Feature lifecycle:
FeatureBase.disable()does not resetinitialized. Concurrentenable()/disable()calls are serialized via a per-feature lifecycle queue. Dependent disable inFeatureRegistryisolates per-feature failures so one broken cleanup doesn't half-disable the graph. - Multi-window apps use
setInstanceState()/getInstanceState(). Every app has been audited; Terminal and Paint use property accessors that proxy to per-window state. - Modal cleanup runs synchronously inside
WindowManager.close()via a per-window callback map — no more one-shot listener races on rapid close. - Plugin loading uses a config-driven manifest generated during boot. The loader validates manifests (id format, duplicate IDs, dependency resolution, function shapes) and rolls back precisely on failure.
- RetroScript and app/plugin systems are fully integrated through the unified event + command layer; the script engine routes commands via
EventBus.executeCommand. - The event schema is modularized into domain-specific files under
core/schema/(window, app, system, UI, desktop, sound, filesystem, game, dialog, notification, feature, settings, SSE, narrative, multimedia, and user-session events). Schema coverage is enforced in CI (currently 100%). - A backend test suite (
test-backend.php), a RetroScript engine harness (scripts/test-retroscript.sh), and an aggregatedscripts/ci-gate.sh(JS syntax + PHP lint + innerHTML safety + RetroScript + schema coverage) provide automated smoke coverage. - Boot diagnostics:
window.__OS_BOOT_HEALTHcaptures the one-shot boot phase report;window.__OS_HEALTHis the live HealthMonitor snapshot for runtime triage. - Script-driven, SSE-driven, and
command:fs:*file operations share one allowlist (core/script/utils/PathValidation.js). Adding a new safe root requires only one edit. - Storage hardening:
StorageManager.set/get/setGlobal/getGlobal/hydrationSetreject payloads with__proto__/constructor/prototypekeys at any depth; UI writes are dropped during snapshot hydration; pre-login.set()writes are queued and replayed under the user scope on login with set-if-missing semantics (so a returning user's data isn't clobbered by boot-time defaults); icon coordinates are clamped to a sane range. - Desktop-icon sync is bidirectional: state → FS via
FileSystemManager.syncDesktopIconsand FS → state viaStateManager.installDesktopIconReconciler(subscribes tofilesystem:directory:changedand skips events withsource: 'syncDesktopIcons'to avoid feedback loops). - Multiplayer state sync uses a re-broadcast guard plus a version-vector conflict surface (
mp:state:conflict,story:state:conflict) so concurrent edits no longer silently clobber.
docs/MIGRATION_ROADMAP.md tracks deliberate non-decisions (e.g., the core/EventBus.js re-export); the previously-deferred F1 (CommandBus deletion), F2 (bidirectional icon sync), and F3 (pre-login storage drift) follow-ups are closed.