Architecture
How the published package, the internal @filedom/* packages, the reconciler, and the native runtime fit together.
filedom is one published package (filedom) that bundles a set of internal
@filedom/* workspace packages. It is easiest to read as a stack of layers,
from the React tree down to Finder.
Layer map
React app
-> filedom (public entry points: filedom, filedom/system, filedom/sound)
-> @filedom/components (StageProvider, Stage, Sprite, Text, Score, overlays, hooks, layout)
-> @filedom/reconciler (React tree -> filesystem + Finder operations)
-> @filedom/host (TypeScript bridge to the Swift binaries)
-> Swift controllers (IconController, InputListener, AudioController)
-> Finder / desktop state
@filedom/types is the shared contract underneath all of them. @filedom/assets
bakes icons and text, @filedom/file-pool recycles file handles for the Stage,
@filedom/bridge owns filesystem operations and the Desktop hide journal, and
@filedom/sound adds game audio on top of the host’s audio primitives.
Responsibilities
Public entry points: filedom
The published package re-exports the public surface through three entry points:
filedom (reconciler, components, hooks, assets, and game controls),
filedom/system (host bridge and filesystem), and filedom/sound (audio). In
the monorepo these resolve to TypeScript source, so apps track the live API
without a build step; publishConfig swaps them to the bundled dist at pack
time.
Shared types: @filedom/types
Defines the virtual desktop model: node types for files, folders, and desktop
roots, the icon and background descriptors, SystemMetrics, and enums such as
VirtualNodeType, IconColor, and ViewOptionsArrangement. Every other
package depends on this contract.
Components and hooks: @filedom/components
The renderable building blocks: Wallpaper, the Stage/Sprite/Score/Text
and overlay system, layout helpers (createGrid, distribute), and hooks
(useBounds, useViewOptions, useDesktopDrag, useKeypress, and others).
Components produce custom element types for the reconciler instead of DOM
nodes. The file and folder elements that Stage emits are internal to this
package and not exported.
Reconciler: @filedom/reconciler
Turns React updates into desktop side effects: creating and deleting files and
folders, batching Finder mutations, applying icon positions and custom icons,
changing the wallpaper, and reading and restoring view options. createRoot,
render, and the startSession lifecycle live here.
Host bridge: @filedom/host
The macOS integration layer. It exposes TypeScript functions for Finder
operations and hands native work to the Swift binaries: long-lived Finder
control through IconController, keyboard and mouse capture through
InputListener, and audio through AudioController.
Filesystem bridge: @filedom/bridge
Filesystem operations and file ownership are kept apart from Finder automation.
The Desktop hide journal is a TypeScript state machine that drives a
filesystem-only StashController helper. The helper holds an advisory lock on
the Desktop, publishes synced journals atomically, and sets or clears
UF_HIDDEN through a descriptor opened relative to the locked directory,
re-checking the inode’s identity on that descriptor before the flag changes.
Files are never moved, so nothing can collide or be overwritten, and the helper
never starts Finder or input services. Recovery validates identities and stops
on anything ambiguous. A journal in the old move format also stops recovery and
is left for inspection.
Why this split exists
A React commit requests work; Finder may not have applied it yet. The reconciler coalesces positions per file and waits for file creation and icon preparation. Stage starts its paint allowance only after the native unhide is confirmed.
Stacking repairs wait for revocable placement acknowledgements through a host-installed driver. They work on connected groups of overlapping sprites within one Stage, validate the exact selection and native targets, and track gesture cleanup through shutdown. A component whose repair failed and has not changed stays suppressed on its own, without affecting others. A posted gesture updates a ledger of the believed order; Finder offers no z-order readback.
Each root has one exclusive RendererRuntime. It owns the position and
visibility queues, Finder batches, the serialized filesystem lane, the async and
native-gesture ledgers, expected-position baselines, and wallpaper and view
state. root.dispose() drains that runtime and unregisters its drivers;
session.close() also restores session resources without exiting the process.
Late async work stays with the root that started it and never passes to a later
root.
Cleanup failures are still reported at disposal after their tasks settle. Ordinary interrupted repairs and recoverable live updates are tracked separately and do not fail cleanup. The native daemon, input services, name registries, and durable caches are shared across roots. Only one root or session can be active at a time, so FileDOM does not run concurrent Finder sessions. Explicit ordering across Stages, beyond creation order and user drags, is open work listed in the repository status notes.
Keeping the layers separate lets each one be documented from two sides: how to use it from React, and how it works underneath. This page connects the two.