Modern OS

A tiling desktop that runs in a browser tab.

Windows arrange themselves into a BSP layout, five workspaces sit behind Ctrl+Shift+1..5, and the start screen is a wall of live tiles that update while you look at them — all on a headless kernel with a pure reducer and a scoped keymap.

event bus

window.tile

A new window splits the focused one along its longer axis. No title bars — the layout owns the geometry.

tile.feed

Nineteen live feeds, one scheduler, at most two updates a tick — so the board reads as things happening, not a wave.

notification.new

A feed posts once: the tile, its taskbar badge and the notification panel all read the same count.

36apps, all with real content
19live tile feeds
5workspaces on $mod+1..5
5tile animations

Live

Boot it here.

The real thing, running in the page. Click a tile to open an app, press Ctrl+Shift+←→ to move focus between tiled windows, hold Ctrl+Shift to see every binding, or open the notification panel from the taskbar status cluster. Nothing is recorded and nothing is saved to a server — it is all running in your browser.

modern os not started

best on a wide screen open full screen ↗

app.launch

Tiles are alive.

There are no icons. Every app is a colored tile carrying its own state — CPU load, disk usage, query rate, unread count, download progress — and it animates when that changes. Updates speak a small vocabulary: flip when something is replaced, slide for the next item in a sequence, roll for a number that should count rather than cut, and an attention ring for the few that genuinely want you. The board fills downward and grows to the right; type to filter it.

start screen 1600 × 1000
Start screen of live tiles showing CPU load, disk usage, query rates, unread counts and download progress

tile.longPress

A tile is a format, not a decoration.

The tile configurator treats a tile as a layout problem with a budget. Pick a span and it reports the exact geometry; the span buys a number of widget slots, and each widget spends them. A 1×1 tile has no slots and says so. Clocks, progress bars, a media player and a task list are all fitted against the same accounting.

tile configurator 4×2 span · media player
The tile configurator showing a 4 by 2 tile preview with a media player widget, a size grid, and the widget library
grid
6 flexible columns, 96px rows
1×1 tile
193 × 96px, 169 × 72 content
4×2 tile
797 × 200px, 8 widget slots
padding
12px, all four sides

window.tile

Tiling by default, floating when you say so.

The first window owns the viewport; each new one splits the focused window along its longer axis. There are no title bars in tile mode — the layout owns the geometry, so a drag handle would be a lie and the space goes to the app. The tiling engine is a pure function from a workspace's window list to rectangles, called inside the reducer.

workspace 1 3 windows · dwindle
Three windows tiled in a BSP layout: Terminal on the left, Browser and Notes stacked on the right, none with title bars

Snapping or dragging by hand implies floating, because you cannot drag something the layout is positioning for you. Ctrl+Shift+V pops a window out, and it grows a title bar on the way.

placement tiled × floating
The same layout with the Browser floated out above the tiled windows, carrying a title bar

notification.new

A panel, not a takeover.

Notifications group by app, so twelve of them read as three sources rather than a wall. Each one dismisses on its own, unread is an accent edge that survives a dense list, and the times are real and tick while the panel is open. It is a column beside your work, not a sheet over it — on a tiling desktop, the thing it would cover is the layout you were reading.

notification panel grouped · dismissable
The notification panel open beside two tiled windows, with notifications grouped under Messages, Email, Calendar and Downloads

keymap

The keyboard is the interface.

$mod is Ctrl+Shift, because Windows swallows Super+digit before a browser tab ever sees it. Bindings are data in one registry with a scope stack, and a dev-time audit warns when a chord resolves to something the browser or the OS takes first. Hold Ctrl+Shift and the current bindings appear, read from the live keymap rather than a written-down copy, so the sheet cannot drift from what the desktop does.

hold to remember read from the live keymap
The hold-to-remember cheatsheet showing three columns of bindings grouped into Workspaces, Windows and Desktop
$mod+1..5
switch workspace
$mod+arrows
focus that way
$mod+Alt+arrows
move the window
$mod+S
resize mode

Under the shell

The apps are tenants. The system is the project.

Most of the code is not in the apps — it is in the layer they sit on. The rule the layering enforces: UI dispatches actions and reads selectors; it never mutates window state directly. That is what let the tiling engine drop in as a pure function without a single component learning it existed.

Kernel

src/kernel/

Observable store, pure reducer, typed actions, memoised selectors — the single source of truth for every window.

Window machine

kernel/windowState.js

Placement (tiled/floating) × display (normal/minimized/fullscreen) as a total transition table that refuses rather than invents.

Tiling engine

kernel/layout/bsp.js

A binary tree per workspace. tree => Map<windowId, rect>, pure, called after anything that changes the set.

Keymap

src/services/keymap.js

Chord parsing, a scope stack so a modal shadows the desktop, hold detection, and an audit for chords the browser takes first.

Theme + motion

src/services/theme.js

Colour, shape, depth and motion tokens. Every animation asks permission: reduced drops decorative movement, none stops it.

Tile feeds

src/features/tiles/

Nineteen simulated sources, the animation vocabulary, and one scheduler that keeps them from all moving at once.

Run it

Clone, install, boot.

Vite dev server on port 5173. No backend, no accounts, no build step beyond the bundler.

# get it running locally
git clone https://github.com/monstercameron/Modern_os.git
cd Modern_os
npm install
npm run dev

# rebuild this site's live demo
npm run build:pages

Status

What's finished and what isn't.

The shell is the mature half, and it is now most of the way there. The gaps that are left are named rather than hidden.

Working

  • BSP tiling with floating opt-out
  • Five workspaces, keymap and cheatsheet
  • Live tiles: 19 feeds, 5 animations
  • Notification panel, grouped and dismissable
  • Per-app and desktop agents
  • All 36 apps render real content

Known gaps

  • Taskbar and start screen ignore theme tokens
  • Unhide is last-in-first-out with no picker
  • No control over split direction
  • Settings: only Personalization is wired

Next

  • Theme tokens through the whole shell
  • A window picker for hidden windows
  • Split-direction control before opening
  • Drag-to-swap between tiled panes