- JavaScript 73.7%
- CSS 21.3%
- HTML 4.7%
- Dockerfile 0.3%
| css | ||
| doom | ||
| gallery | ||
| images | ||
| js | ||
| pinball | ||
| sounds/aol_sounds | ||
| .dockerignore | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| index.html | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| server.js | ||
eldr.wtf
A Windows XP–themed web desktop — a nostalgic, browser-based recreation of the XP experience, complete with a boot screen, draggable windows, a working Start menu and taskbar, screensavers, and a small arcade of built-in apps.
It ships with its own backend: Eldr Instant Messenger, an MSN-style chat server with accounts and encrypted history, plus a contact form that delivers messages by email.
Features
The desktop
- Authentic XP boot screen, desktop, taskbar, and Start menu
- Draggable, resizable, focus-aware windows (
window-manager.js) - Desktop icons, a volume mixer, and idle screensavers
Built-in apps
- 🎮 Doom — playable in-browser via js-dos
- 🕹️ 3D Pinball: Space Cadet — the WebAssembly port
- 💣 Minesweeper and 🃏 Solitaire
- 🎨 Paint / Oekaki drawing app
- 🎵 Media Player with an XP-style skin
- 🖼️ My Pictures gallery
- 🌐 Internet Explorer & a mock search page
- 📝 About Me, Blog, Recycle Bin, and a Contact form
Eldr Instant Messenger (the backend)
A WebSocket chat server (server.js) styled after MSN Messenger:
- Accounts stored in SQLite with bcrypt-hashed passwords
- Worldwide chat, group chats, and private messages
- Custom display names and presence
- Encrypted message history (AES-256-GCM at rest)
- Per-user history wipe requests
Tech stack
- Frontend: vanilla HTML / CSS / JavaScript (no framework)
- Backend: Node.js
ws— WebSocket chat serverbetter-sqlite3— account & history storagebcryptjs— password hashingnodemailer— contact-form emaildotenv— configuration
The same Node process serves the static site and the WebSocket server on a single port.
Configuration
Create a .env file in the project root:
# HTTP + WebSocket port (default: 8765)
PORT=8765
# Persistent key for encrypting chat history (32-byte hex).
# If omitted, a temporary key is generated each run and history won't survive a restart.
CHAT_ENCRYPTION_KEY=<64-hex-characters>
# Contact-form email delivery (nodemailer SMTP)
EMAIL_SERVER=smtp.example.com
EMAIL_ACCOUNT=you@example.com
EMAIL_PASSWORD=your-smtp-password
EMAIL_RECEIVER=where-contact-messages-go@example.com
Tip: generate an encryption key with
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Data & persistence
All persistent data lives in the data/ directory (the SQLite database,
data/accounts.db). This folder is git-ignored and is the volume that Docker
persists across restarts. Override its location with the DATA_DIR environment
variable if needed.
Running with Docker (recommended)
With Docker and Docker Compose:
# Make sure a .env file exists first (see Configuration above)
docker compose up -d --build
Then open http://localhost:8765.
- The database is persisted to
./dataon the host via a bind mount, so your accounts survivedocker compose downand rebuilds. - To change the published port, edit the
portsmapping indocker-compose.yml(e.g."3000:8765"). - View logs with
docker compose logs -f; stop withdocker compose down.
Running locally (without Docker)
Prerequisites
- Node.js (v18+ recommended)
npm install
npm start
Then open http://localhost:8765.
Project structure
.
├── index.html # The desktop shell
├── server.js # HTTP static server + Eldr Instant Messenger (WebSocket)
├── Dockerfile # Container image build
├── docker-compose.yml # One-command run + persistent data volume
├── data/ # Persistent data (accounts.db) — git-ignored
├── css/ # Per-app and per-component XP styling
├── js/
│ ├── window-manager.js # Window dragging / focus / z-order
│ ├── taskbar.js # Start menu + taskbar
│ ├── boot-screen.js # XP boot sequence
│ ├── screensaver.js # Idle screensavers
│ └── content/ # Individual app logic (msn, paint, doom, …)
├── images/ # Icons, wallpapers, UI sprites
├── sounds/ # System & AOL/MSN sounds
├── gallery/ # My Pictures images
├── doom/ # js-dos Doom bundle
└── pinball/ # Space Cadet Pinball (WASM)
Notes
data/(the chat database) and.envare git-ignored — never commit them. Set a stableCHAT_ENCRYPTION_KEYin production so encrypted history persists across restarts.