Skip to content
filedom
Esc
↑↓navigate↵open⌘Jpreview
On this page

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.

Was this page helpful?