Skip to content
Build with Fungi

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.

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:

TERMINAL
pnpm --filter @fungi.computer/maosaico build

MaosaicoRoot 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.

TSX
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.

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.

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.