Build a desktop-style window manager in React
Arrange floating and tiled React panes with Maosaico, add shell services with Nacre, and see the finished desktop in Tourtois.
A desktop-style interface has several separate jobs: arranging panes, mounting App windows, dispatching commands and deciding which Apps may open. Use Maosaico for React geometry, Nacre for the shell client, and Tourtois as a finished example. None of the layout APIs grants an App permission.
Start with panes in a measured container
Section titled “Start with panes in a measured container”Maosaico is a React tiling window manager for content inside your own container, not an operating-system window manager. It supports React 17 or newer. From the repository root:
pnpm --filter @fungi.computer/maosaico buildMaosaicoRoot owns the layout for one root. Pass the current container size as
bounds. With no tiling prop, panes use floating frames; with tiling, the
layout arranges registered panes.
Illustrative: these fixed bounds make the example small. A responsive host must measure its container and supply updated bounds, styling and controls.
import { MaosaicoRoot, useMaosaicoItem } from "@fungi.computer/maosaico";
function Pane({ id }: { id: string }) { const pane = useMaosaicoItem({ id, frame: { x: 0, y: 0, width: 320, height: 240 }, minima: { width: 180, height: 120 }, });
return ( <section hidden={!pane.visible} {...pane.props} style={{ position: "absolute", left: pane.frame.x, top: pane.frame.y, width: pane.frame.width, height: pane.frame.height, }} > Pane content stays mounted here. </section> );}
export function Workspace() { return ( <div style={{ position: "relative", width: 1000, height: 600 }}> <MaosaicoRoot bounds={{ width: 1000, height: 600 }} tiling={{ gap: 8 }}> <Pane id="chat" /> <Pane id="files" /> </MaosaicoRoot> </div> );}The item binding supplies the current frame, visibility, active state, pointer
props and focus, snap and restore actions. Keep hidden panes mounted with
stable keys and use hidden={!pane.visible} so they leave input and
accessibility navigation. Remove a pane from the mounted list to close it.
Choose the layout and own the presentation
Section titled “Choose the layout and own the presentation”Tiling supports main-left, main-top, columns, rows and grid.
main-left is the default; the first pane is the main pane and companions stack
beside it. The main layouts expose one divider and clamp the preferred
mainSize to minima and available space.
Equal-cell layouts ignore mainSize. When panes cannot all fit, overflow shares
a tab group; the host renders tabs from tabGroups. Hidden content stays
mounted. useMaosaicoLayout() supplies tile order, focus and swap commands,
zoom/restore, divider interaction and pending snap information.
The host still owns pane content, styling, keyboard policy and DOM focus. Measurements must be finite and nonnegative. Maosaico keeps layout state only for the mounted root’s lifetime; persist frames yourself if you need them after a reload.
For shell overlays, MaosaicoLayers supplies chrome, popover, dialog,
toast and tooltip roots. Put windows in a MaosaicoRegion layer="windows"
and merge each binding’s stackingStyle into its window. The host loads Stipe’s
stylesheet. Choosing a layer does not implement positioning, light-dismiss or
focus trapping.
Add shell services with Nacre
Section titled “Add shell services with Nacre”Nacre is a browser desktop shell client library, independent of Oyster’s server. Its focused entries cover:
| Entry | Job |
|---|---|
/window-manager |
Window generations, visibility, navigation, cancellation and disposal. |
/commands |
Window, App picker and command palette declarations over host callbacks. |
/keys |
DOM key dispatch and shared chord matching. |
/command-host |
Admission of mounted commands against verified Release declarations. |
/app-directory |
App addresses, reusable rows and catalog metadata. |
Supply a mount adapter to createWindowManager. It receives the container,
launch descriptor, cancellation signal and navigation callbacks; the returned
handle owns visibility, reconfiguration and disposal. The manager serializes
changes to a window and disposes stale mounts. It does not pick Apps or grant
capabilities.
Directory metadata is not launch authority. The host must admit each mount. Likewise, mounted commands must match verified Release declarations.
Use Tourtois as the finished example
Section titled “Use Tourtois as the finished example”Tourtois is the web desktop for self-hosted Apps on Oyster: a launcher, tiled or floating windows, menus and settings. Minimizing an App keeps it running; restoring it does not reload it.
Tourtois is a trusted shell, running in the host’s own page with your permissions there. The Apps it opens remain in separate sandboxed, cross-origin frames. Pick a shell you trust: ordinary App isolation does not make the shell itself untrusted code.
- Run your own Oyster for the App host.
- Customize your dashboard for the Team-hosted dashboard path.
- Maosaico for geometry and React APIs.
- Nacre source and README and Tourtois source and README for the shell contracts.