I Built a Real OS Inside the Browser (No Shortcuts)
Most "web OS" projects are just draggable windows with local state.
I wanted to see what would happen if the browser had to obey real operating system rules.
So I built WebOS: a fully simulated operating system inside the browser with:
- A modular kernel architecture
- Queue-based process management
- Round Robin CPU scheduling
- First-Fit memory allocation (with fragmentation)
- Block-based virtual disk
- A Unix-inspired inode file system
- Strict Kernel → Store → UI control flow
Built using React, Vanilla JavaScript, Zustand, GSAP, and react-rnd.
This isn't just a UI skin. It's a constraint-driven system model running entirely inside a browser runtime.
The Architecture: Kernel → Store → UI
Most web apps follow this pattern: UI → State → Render
WebOS enforces: Kernel → Store → UI
The UI has zero authority over system resources. It cannot allocate memory. It cannot spawn processes. It cannot write to disk. Everything goes through the kernel first.
The kernel is composed of independent subsystems:
- ProcessManager (PIDs, lifecycle, coordination)
- MemoryManager (First-Fit allocation, fragmentation)
- Scheduler (Round Robin, time quanta, CPU tracking)
- FileSystem (inode model, directory structure)
- StorageSystem (raw block allocation)
All resource arbitration happens here.
Zustand acts as an authoritative synchronisation layer between the kernel and React. When launching an app:
- UI triggers
createApp() - Kernel validates memory + CPU availability
- PID is allocated
- Memory block assigned
- Scheduler registers process
- Store syncs confirmed state
- React renders
If allocation fails, nothing renders. The UI reacts to system state, it does not create it.
Round Robin CPU Scheduling That Actually Works
The Scheduler implements:
- Fixed time quanta
- Context switching
- CPU usage tracking
- Usage decay when idle
- Overload protection
If total CPU usage approaches a defined threshold, the kernel throws CPU_OVERLOAD and rejects new processes. System stability is enforced at the kernel level.
You get live CPU graphs showing real scheduling behaviour. Multiple apps run simultaneously with independent PIDs and per-process resource tracking.
Memory Fragmentation in the Browser
The MemoryManager uses First-Fit allocation and treats memory as contiguous blocks. It merges only adjacent free segments. This simulates external fragmentation.
You can create real "Swiss cheese" memory states. Even if total free memory is technically sufficient, a process may fail if no contiguous block is large enough.
This introduces realistic allocation constraints inside a browser environment that normally hides them. The memory graph shows downwards growth with real-time allocation and deallocation.
The Inode File System (Core Highlight)
Instead of storing files as simple path-based objects, WebOS implements a Unix-inspired inode model.
Each file has:
- A unique inode ID
- Logical size
- File type
- A list of allocated disk blocks
Directories do not store file data. They store: name → inodeId
This creates three distinct layers:
- Namespace (directory structure)
- Identity (inode)
- Physical storage (disk blocks)
Because identity is decoupled from path:
- Renaming a file does not change its inode
- Moving a file across directories does not reallocate storage
- Recursive directory deletion is deterministic
- Disk exhaustion properly blocks file growth
- Directory relinking simulates Unix-style behaviour
Below the file system sits a simulated disk with fixed-size blocks, explicit allocation and deallocation, and no awareness of filenames or directories. The disk only understands raw blocks. All higher-level structure is built above it.
The StorageSystem manages raw blocks. The FileSystem manages structure and identity. The Kernel enforces constraints.
Modelling this inside JavaScript required extremely clean abstraction boundaries.
Error Simulation and System Resilience
WebOS enforces realistic failure cases:
OUT_OF_MEMORYCPU_OVERLOADOUT_OF_STORAGE- File system related errors
Errors originate in the kernel and propagate upward. The UI reacts, it never simulates failure independently. This preserves architectural integrity.
The hardest part wasn't building UI. It was maintaining invariant rules across independent subsystems: memory consistency, scheduler fairness, file system integrity, correct resource cleanup. If one invariant breaks, the illusion collapses.
What's Next
- Terminal emulator
- App installer system
- Access control simulation
- Expanded kernel APIs
- UI overhaul after feature freeze
This project blurred the line between frontend engineering and systems design. It's not WebAssembly syscalls or a Linux WASM port like Container2WASM or WebVM, but it's a constraint-driven system model that makes the browser runtime behave like an actual operating system.
Check out the GitHub repo to see how deep the rabbit hole goes.