Changelog
The library is pre-1.0. Treat every release as potentially breaking; the entries below name the breaking changes explicitly.
Unreleased
Section titled “Unreleased”- Windows taskbar and Start menu, to the Windows 11 reference. The
"bar"dock gains the Windows 11 taskbar pieces, each behind an optionalchrometoken:showDesktopButton(the thin “Show desktop” sliver in the far corner; one click minimizes every window on the active workspace, a second restores them),taskViewButton(a Task View button beside Start that opens the windows overview),taskbarContextMenu(right-click the empty taskbar for “Taskbar settings”, which jumps straight to a dedicated Taskbar section in Settings via the exportedrequestSettingsSection), anddockAutoHide(the bar tucks off the edge and slides back only while the pointer is at that edge or over it, reserving no work area). Under center alignment the launcher run now centers Start and Task View with the app icons (Windows 11) instead of pinning them to the corner. The"menu"launcher opens above the Start button, tracking a centered or left-aligned taskbar, and is rebuilt on the Windows 11 layout: a search field, a Pinned grid with an All-apps list toggle, a Recommended section (recently focused apps), and an account-plus-power footer. Windows exposes the alignment and the item toggles in the new Taskbar settings section. Non-breaking: every token is optional and off by default. - Per-platform chrome sizing. The taskbar, dock, and top bar were one shared metric set, so Windows and Ubuntu were forced to the same size (Ubuntu’s dock was far too thin). Three optional
chrometokens size each clone to its reference:dockTileSize(a"bar"dock derives its thickness from the tile, so a larger-icon dock is a wider bar),dockIconScale(the icon as a fraction of the tile), andmenuBarHeight. macOS keeps its 56px floating tiles, Windows gets 24px icons in a 48px taskbar, and Ubuntu gets ~46px icons in a ~64px dock with a 30px top bar. Non-breaking: un-tokenized themes keep the previous viewport metrics, and compact viewports still shrink the tiles. - Theme-aware app and system icons. One app can carry a platform-native icon per clone.
App.icons(andSystemWindowDef.icons) map a theme’schrome.iconStyle("fluent","macos","gnome") to an icon component, resolved by the exportedresolveAppIcon; anything missing falls back to the singleicon. The example apps ship a Fluent variant for Windows (Microsoft Fluent System Icons, MIT) and keep their Lucide glyphs for macOS; the playground demos the colorful Ubuntu Yaru icons for the"gnome"style; and the built-in Settings window resolves a Lucide gear (macOS), a Fluent gear (Windows), and the Yaru gear (Ubuntu). System windows (Settings, Recents) gain anicon, so they no longer fall back to a letter in the launcher. Non-breaking:App.icons,chrome.iconStyle, andSystemWindowDef.icon/iconsare all optional. theme.fonttoken. A theme sets its platform’s UI font stack (the SF / system stack on macOS, Segoe UI on Windows, the Ubuntu font on Ubuntu), applied at the desktop root so the chrome inherits it. The consumer loads any non-system webfont (the playground links the Ubuntu font). Non-breaking: optional, defaults to a neutral system stack.- Reduced-motion support across the desktop. Every autonomous animation now honors
prefers-reduced-motion, through one shareduseReducedMotionhook (built onuseSyncExternalStore, so it is correct on the first client render and SSR-safe). Under the setting, the wallpaper dissolve, window open / close / minimize and the maximize-snap glide, the Mission Control spread, the notification toasts and center, the Quick Settings popover, all three launcher presentations, the HUD, and the dock launch bounce collapse to instant. Direct-manipulation feedback (the app-switcher selection, dock hover magnification, sliders and toggles) keeps animating, matching the platform convention that reduced motion targets autonomous motion, not the response to a user’s own input. - Light and dark appearance, appearance-aware wallpapers, and a wallpaper that dissolves in. Every theme now ships a light and a dark look from one object: author the base palette and supply the opposite under
appearances.{light,dark}(token overrides forpalette,elevation,wallpaper).theme.appearanceis"auto"(the default, followingprefers-color-schemelive),"light", or"dark", resolved by the desktop via the pureapplyAppearance(theme, mode). All three reference themes expose anAppearanceselect in Settings and carry a per-appearance wallpaper (the factories takedarkWallpaperSrc/lightWallpaperSrc). The wallpaper no longer pops in: each is decoded off-screen, then dissolves in over the base color, crossfading on change (the GNOME model), and honoringprefers-reduced-motion. PasswallpaperOptionsto a theme factory to expose a “Wallpaper” picker in Settings. Non-breaking:appearances,appearance, and the new factory options are all optional; a theme without them stays single-look. - Three OS-clone themes, the macOS Tahoe wallpaper, and an on-canvas theme switcher. The theme set is now exactly three platform clones: macOS (
@react-ui-os/theme-macos, now acreateMacosTheme({ wallpaperSrc })factory shipped with the macOS Tahoe wallpaper), Windows (@react-ui-os/theme-windows), and Ubuntu (@react-ui-os/theme-ubuntu). Both playgrounds gain a segmented theme switcher that swaps the whole look with a click, persists the choice, and mirrors it into?theme=. Breaking (pre-release):@react-ui-os/theme-mintablesand@react-ui-os/theme-saasare removed;@react-ui-os/theme-redmondis renamed to@react-ui-os/theme-windowsand@react-ui-os/theme-defaultto@react-ui-os/theme-macos(theircreateRedmondTheme/createDefaultThemefactories becomecreateWindowsTheme/createMacosTheme). - Launcher presentations and the
useLauncherhook. The macOS Spotlight palette is now one face of a launcher with a shared brain.chrome.launcherpicks the presentation:"spotlight"(the centered palette, default),"grid"(the GNOME Activities app grid, a full-bleed search field over a grid of large app icons), or"menu"(the Windows Start menu, raised from the dock launcher). All three draw the same results (apps, system windows,registerSpotlightSourcerows), filter the same way, and share the Cmd/Ctrl+K shortcut; Ubuntu sets"grid"and Windows sets"menu". The shared logic lives in an exporteduseLauncher()hook, so a consumer can build a fully custom launcher (its own markup, the system’s results and shortcut) by rendering it in place of<Launcher>.<Spotlight>stays exported as an alias of<Launcher>. Non-breaking:chrome.launcheris optional and defaults to"spotlight". - GNOME / Ubuntu theme, the
"gnome"window-control register, a centered clock, and Quick Settings. The Ubuntu theme,@react-ui-os/theme-ubuntu, is the first to pair a top menu bar with a left dock (the GNOME Shell arrangement): Yaru dark palette, Ubuntu orange, a left bar dock with no fisheye, and the new pieces below.chrome.windowControlsgains"gnome": minimize / maximize-restore / close as round symbolic buttons on the right, the neutral Adwaita / Yaru treatment (the close button is not reddened).chrome.menuBarClockplaces the top-bar clock"right"(the macOS default) or"center"(the GNOME placement, status indicators kept on the right).chrome.quickSettingsturns the menu-bar status cluster into one button that opens the new Quick Settings popover (the GNOME system menu, the macOS Control Center, the Windows quick settings flyout): a panel of action buttons, sliders, and toggle tiles, populated byregisterQuickSetting(...)on the same imperative-store pattern as status items. The left bar dock now adapts to a top menu bar (it drops its own clock, starts below the bar, and moves the launcher to the trailing edge), and a newchrome.dockAlign("start"|"center"|"end") packs a bar dock’s icons from the top, the GNOME / Windows 10 placement, instead of always centering them; Ubuntu sets"start"and both Ubuntu and Windows expose it in Settings (Windows 11 calls it Taskbar alignment). The workspace switcher moves to the top-left in the GNOME arrangement, andchrome.menuBarBrand(defaulttrue) lets a theme drop the macOS-style brand button so the GNOME top-left is just the workspace switcher (Ubuntu setsfalse). Non-breaking:chrome.menuBarClock,chrome.quickSettings,chrome.dockAlign,chrome.menuBarBrand, and the new control register are additive with defaults that leave existing themes unchanged. - Window-control registers, elevation and dock-magnification tokens, and the Windows theme.
theme.chrome.windowControlsnow renders all three declared registers: macOS"traffic-lights", Windows"windows"(a minimize / maximize-restore / close caption cluster, close turning red on hover, drawn from font-independent SVG glyphs at the Windows 11 metrics), and"minimal"(a single close glyph). Three new structural knobs stop the components hardcoding macOS looks:elevation(focused / unfocused window shadow, optional, falls back to the previous default),motion.dockMagnification(the dock fisheye peak; set it to 1 to turn the fisheye off), andchrome.dockStyle("floating"macOS pill vs"bar", a flat taskbar flush to the edge, full width on the bottom or full height on the left, with flat brand-colored icon buttons and an accent underline under running apps, matching the Windows 11 48px taskbar). The three existing reference themes expose the window-control style as a Settings select, and the macOS theme exposes dock magnification as a slider, so the look can be mixed live. The Windows theme,@react-ui-os/theme-windows, puts the levers together into a Windows-style desktop: caption buttons, a real bottom taskbar (dockStyle: "bar") with no fisheye, no menu bar, lighter shadows, 8px corners. Non-breaking:elevation,motion.dockMagnification, andchrome.dockStyleare optional with fallbacks, so existing themes are unchanged. - App Store:
@react-ui-os/cliand an app registry. Apps are distributed, not bundled into the library. A rootregistry.jsonlists each app (id, source files, dependencies, accent, category);npx @react-ui-os/cli add <id>copies an app’s source into the consumer’s project underos-apps/<id>/, prints the dependencies to install and how to register it with<Desktop>, and skips existing files unless--force.listshows the registry,buildinlines a registry into a single self-contained JSON to host. Third parties host their own registry and install from it with--registry <url>, so the catalog grows without pull requests to this repo. The docs gain a searchable App Store gallery and a publish guide. The seven seed apps (Notes, Calculator, Clock, Calendar, Reminders, Sketch, Terminal) moved into@react-ui-os/example-apps, which the playground and docs both consume. SliderandToggleform primitives. Themed wrappers over a real<input type="range">and<button role="switch">: keyboard arrows, Page Up/Down, screen-reader value announcements,aria-checkedsemantics all work because the native primitives are still doing the heavy lifting; only the visual layer is custom. Exported for consumer windows. Settings panelRangeControlandToggleControlnow render these instead of the prior hand-styled inputs, so the built-in Settings UI matches the rest of the desktop without per-theme styling work.registerStatusItem, menu-bar plug-in slots. Third extension point in the library (afterregisterSpotlightSourceandregisterSystemWindow). Items sit between the workspace pips and the clock; they declareicon, optionaltooltip, optionalbadge, optionalonClick, and anorderfor placement. Re-registering the same id updates in place. Live-demo’d in the playground: a green “online” dot and a clickable “ding” widget that fires a toast. The menu bar widget is a<button>with the tooltip text as itsaria-label, so keyboard-only users get the same hint as hover users.Tooltipprimitive. Replaces the nativetitle=""attribute on every dock tile, workspace pip, and the menu-bar clock; available for consumer code viaimport { Tooltip } from "@react-ui-os/desktop". Cold show ~480 ms, warm ~60 ms (a tooltip that hid in the last 800 ms makes the next one near-instant, the same cadence the macOS menu bar uses). Auto-flips placement when it would clip; final clamp keeps it on-screen. Optional shortcut hint on the right ("⌘K","F3"). Honors focus events so keyboard users see the same hint as hover users.- Workspaces (virtual desktops). Window manager now tracks an ordered list of workspaces and an active one; every window carries
workspaceId. WindowLayer filters by active workspace, so switching is a free O(n) hide rather than mount/unmount churn. Menu bar shows a pip cluster (one per workspace, active one wider and accent-colored).Ctrl + Alt + ←/→switches;Ctrl + Alt + Shift + ←/→brings the focused window with you. Window title-bar context menu gains “Move to Workspace N”. Three workspaces ship by default.useWindowManager()exposesswitchWorkspace,moveWindowToWorkspace,addWorkspace,removeWorkspace. Opening or focusing a window on another workspace pulls the user there, matching the macOS Cmd+Tab-jumps-spaces behavior. Non-breaking at the call-site level, butOpenWindownow has a requiredworkspaceId: string; persisted snapshots need a fallback. 13 new reducer tests cover the lifecycle. - HUD overlay. Transient floating indicator (
"Maximized","Snapped Left") the OS uses to confirm a momentary action. Mounted by<Desktop>, fires automatically on window snap, maximize, restore.showHud({ title, sublabel?, icon?, progress?, accent?, duration? })is exposed for consumer-driven HUDs (volume / brightness analogues). Re-firing while a HUD is visible replaces it in place so repeated taps coalesce. - Mission Control (F3 / Ctrl + ↑). Tile every open window in a grid of large preview cards (window aspect, accent stripe, traffic lights, name). Click any card to focus that window and dismiss; click empty space or press Esc to dismiss without changing focus. Minimized windows are excluded; Mission Control is “what’s on screen now,” not “what’s stashed in the dock.” Cards are representational rather than live thumbnails so the cost stays flat regardless of how much DOM each window owns.
- App switcher (Cmd/Ctrl + Tab). Centered overlay shows every running app, MRU order from window z-index, large highlighted tile on the selection. Hold the modifier and Tab cycles forward, Shift+Tab back; release commits the focus; Esc cancels. First press selects the second entry; quick tap-and-release flips you to the previous app, the Mac convention. Apps with no open window are omitted (this is a switcher, not a launcher; Cmd+1..9 and Spotlight handle launching).
- Window snapping (Aero Snap). Drag a window’s title bar toward the viewport edge: a translucent rectangle in the theme accent shows the snap target (left half, right half, top = maximize, four corners = quarters). Release in the zone and the window snaps. Activation thresholds: 24 px from an edge, 48 px from a corner. Keyboard chords:
Cmd/Ctrl + ←/→for halves,Cmd/Ctrl + Shift + ←/→for top corners,Cmd/Ctrl + ↑/↓to maximize/restore. Snap math (computeSnapZone,rectForZone) and the store (setSnapPreview,getSnapPreview,subscribeSnapPreview) are exported so custom draggable surfaces (floating panels, tool windows) get the same affordance for free. ContextMenuprimitive +DesktopBackdrop. Right-clicking the desktop background now opens a system menu (Spotlight, Notifications, Settings, Show Desktop); right-clicking a dock tile shows the per-app menu (Open / Minimize / Close / Mark notifications as read); right-clicking a window title bar shows Restore / Minimize / Close. Two contribution paths: imperativeopenContextMenu({ x, y, items })from any event handler, or<ContextMenuAnchor items={...}>to wrap a region declaratively. Items supportlabel,icon,shortcut,onSelect,disabled,danger, andseparator. Keyboard navigation, flip-to-stay-in-viewport positioning, and Esc / scroll / blur dismissal all handled by the renderer. Existing in-FileExplorer right-click menu kept; the new primitive is what every other surface uses.- Notification subsystem. New
notify({ title, body, appId?, level?, duration?, actions? })in@react-ui-os/core, plus<NotificationToasts>and<NotificationCenter>in@react-ui-os/desktop. One call drives four surfaces at once: a top-right toast stack, a right-edge Notification Center sheet, per-app dock badges, and a menu-bar accent dot. Levels (info | success | warn | error) carry defaults: errors stick until dismissed, warnings linger, success/info auto-expire. Re-injecting the same id updates a running toast (progress-bar pattern). Snapshot exposed viauseNotifications(). Reducer-free, vanilla store, callable from any code.-registerSpotlightSource(id, source): third contribution path for the Cmd-K palette. A source is a function(query) => SpotlightResult[]; each result owns its ownonActivate, so activations can navigate, open URLs, or dispatch events without going throughopenWindow. Sources are called inside a try/catch so a misbehaving source contributes zero rows rather than killing the palette. Use it for docs pages, bookmarks, recents, or anything that is not a window. SystemWindowArgs: the system variant ofWindowPayloadnow accepts an optionalargsrecord of string/number/boolean primitives.windowIdOfserializes the args into the id so two system windows with distinct args coexist as distinct windows (one per “Component: Window” / “Component: Spotlight” pair). Backward compatible: omitting args keeps the single-slot behavior.SystemWindowDef.namecan be a(args) => stringfunction for per-instance titles. NewresolveSystemWindowName(def, args)helper.<Desktop children>: children now render inside the provider alongside the default surfaces. Lets consumers mount headless companions (URL sync, analytics, deep-link activators) with access touseWindowManager().
- Generated prop / field tables.
apps/docs/scripts/extract-types.mjsparses interface and type-alias declarations from each package’s source with the TypeScript Compiler API and emitsapps/docs/src/data/types.json. A new<TypeTable name="..." />Astro component renders the rows with the actual JSDoc comments, the optional flag, and a link back to the source file. Used today onStorageAdapter,SpotlightResult,SpotlightSource,OsTheme, andOsThemeChrome. Runs as part ofdev,build, andtypecheckso the JSON cannot drift from source. - Pivoted
apps/docsto Astro Starlight. Standard left-nav, right TOC, search, theme toggle. Replaced the “docs are windows” prototype with proper component reference pages. <LivePreview>Astro component embeds/playground?demo=<key>iframes in component pages so each one opens with the relevant feature focused.- Per-feature deep-link demos:
?demo=spotlight,?demo=settings,?demo=window,?demo=dock,?demo=menubar,?demo=recents. - The playground registers a Spotlight source listing every docs page; activating a row escapes the iframe and navigates the parent docs frame, so Cmd-K finds content as well as windows.
- OG / Twitter card meta tags so shared URLs render a social preview. Uses the desktop wallpaper as the stand-in card until a branded render replaces it.
Infrastructure
Section titled “Infrastructure”- CI at
.github/workflows/ci.yml: typecheck, test, build on every push and PR. - Pages deploy at
.github/workflows/docs.yml: auto-deploysapps/docson push to main.
Earlier work
Section titled “Earlier work”The full repo history lives at github.com/saschb2b/react-ui-os/commits/main. High-level milestones:
- Phase 4:
FileExplorerprimitive with full macOS-Finder interaction model (multi-select, Shift-range, right-click context menu, F2 rename, sidebar). State-earned desktop folders viaSystemWindowDef.appearsAsDesktopIcon. - Phase 3: First branded theme. Chrome variants real (
dockPosition: "left",menuBar: "none"). Wallpaper parallax. - Phase 2b: Settings as a system window. The
customizableschema onOsTheme. Effective-theme overlay. - Phase 2a: Resize handles, global keyboard shortcuts, Spotlight.
- Phase 1: Window manager, default theme, playground demo.
Roadmap
Section titled “Roadmap”- Expand
<TypeTable>coverage to every remaining hand-written field table (Settings, useWindowManager, useTheme, thecustomizablefield variants). - A branded social card render to replace the wallpaper stand-in (title, logotype, accent stripe).
- First
1.0.0release once the API stops moving.