---
title: filedom/system
description: The native macOS host bridge plus filesystem operations behind the React layer.
---

`filedom/system` is the lower-level entry point. It holds the macOS host bridge
(Finder metrics, control, and input) and the filesystem operations games use to
manage the desktop files they render. Use it to work below the React layer: to
read live positions, drive Finder directly, capture input, or hide and restore
the user's Desktop items.

```tsx
import {
  getDesktopIconPositions,
  setIconPosition,
  createFile,
  hideDesktopItems,
  restoreDesktopItems,
} from 'filedom/system';
```

The host functions talk to the native Swift binaries, so they only work on
macOS.

## Metrics & lifecycle

- `subscribeToMetrics(cb)` and `waitForCalibratedMetrics()` stream or await the
  calibrated `SystemMetrics` (desktop width and height, icon size, grid spacing,
  text size, label position) that positioning depends on.
- `setupSystemUI(hide)` autohides the Dock and menu bar for a session (`true`),
  then puts back the values the user had (`false`). The originals are recorded
  in `~/Library/Application Support/filedom/system-ui.json` before anything
  changes, so the next session can still restore them after a force-quit.
- `flushPendingCommands()` waits for in-flight native commands. Call it before a
  hard process exit so pending moves and restores finish.

## Icon control

- `setIconPosition(path, x, y)` and `setIconPositions(...)` move one or many
  files.
- `getDesktopIconPositions()` reads the live positions Finder reports.
- `setIconColor`, `setFileComment`, and `setFileExtensionHidden` set Finder
  metadata.
- `setCustomIconFromPath` and `setCustomIconFromBase64` set custom icon images.
- `synthDragAt(x, y, expectedPath?)` posts a synthetic drag that raises a file's
  z-order.

## Grid, size & selection

- `getDesktopIconSize` / `setDesktopIconSize`
- `getDesktopGridSpacing` / `setDesktopGridSpacing`
- `getDesktopGridArrangement` / `setDesktopGridArrangement`
- `getFinderSelection` / `setFinderSelection`
- `getDesktopLabelVisibility` / `setDesktopLabelVisibility`

## Finder control

- `runFinderBatch(...)` applies a batch of Finder mutations in one round-trip.
- `restartFinder()` and `refreshFinder()` recover Finder when its state drifts.

## Input

```tsx
import {
  startGlobalInputListener,
  subscribeDesktopDrag,
  subscribeDesktopClick,
  checkGlobalInputPermission,
} from 'filedom/system';
```

- `startGlobalInputListener(cb)` delivers global keydown events and returns an
  unsubscribe function. It needs Accessibility permission. Under Finder Mode it
  connects to the app's key stream instead of starting its own listener.
  `useGameControls` in the main entry point wraps it.
- `subscribeDesktopClick`, `subscribeDesktopRightClick`, `subscribeDesktopDrag`,
  `subscribeDesktopMouseUp`, and `setDesktopDragRegions` handle mouse
  interaction on the desktop surface. `subscribeDesktopRightClick` consumes the
  gesture, so Finder's context menu never opens and the running game owns the
  secondary click.
- `observeDesktopRightClick(cb)` receives secondary clicks without consuming
  them, for tooling that runs beside a game; the game's own listener still gets
  the gesture. Subscribe after the game's mouse listener is up, because
  observers created earlier sit behind its consuming tap and see nothing.
- `checkGlobalInputPermission()` reports whether input capture is allowed.

## Filesystem operations

```tsx
import {
  createFile,
  createDirectory,
  writeFile,
  renameFile,
  deleteFile,
  scanDirectory,
  getFileMetadata,
  pathExists,
  nameRegistryFor,
} from 'filedom/system';
```

These are the filesystem helpers games use to manage the files they render.
`nameRegistryFor` returns the per-root name registry, the library's single
filename authority for a desktop directory. `createFile`, `createDirectory`, and
`renameFile` refuse to write over a path that filedom did not create, and
`isClobberRefusal(error)` identifies that refusal.

```ts
const names = nameRegistryFor();        // the active desktop root
const path = names.mintPath();          // a fresh, invisible, never-reused path
```

Components mint from this registry themselves: `Stage` sprites, overlays, and
banners all use it. Call it only for desktop files you place yourself outside
any component, and use it instead of inventing names. A name's shape is a
z-order input, and a path a previous run used inherits that run's stacking
([law 3](/docs/learn/rendering-model#z-is-sticky-per-path)).

## FilePool

`FilePool` is the recycling handle allocator the Stage uses internally. It is
exported for code that manages files outside a stage:

```ts
import { FilePool } from 'filedom/system';

const pool = new FilePool({ create: (type, index) => makeHandle(type, index) });
pool.prewarm(['red', 'blue']);
const h = pool.acquire('red');   // pops a warm handle, or mints one
pool.release(h);                 // back to the free list
pool.available('red');           // free count
pool.grow('red', 4);             // top up ahead of demand (front of free list)
pool.all();                      // every handle ever minted
```

`release` throws on a double release or on a handle the pool never minted.
Either mistake would put one desktop file into circulation as two logical
sprites, so the error surfaces the lifecycle bug at the call that caused it.

Grown handles join the front of the free list, and `acquire` takes from the
back, so new handles warm at the park while older warm handles are used first.

## Desktop stash & restore

- `hideDesktopItems()` sets the macOS hidden flag on the user's Desktop items so
  a game has a clean board. Nothing is moved: the files stay in `~/Desktop`,
  keep their icon positions, and Finder stops drawing them.
- `restoreDesktopItems()` clears the flag again.

Before any flag changes, `hideDesktopItems()` records each item's identity in a
journal at `~/.filedom-desktop-stash`. If a previous run crashed, its journal is
recovered before anything new is hidden. Restore reveals an item only when it
is still the same file and still carries the flag. Items the user had already
hidden stay hidden, and anything the user replaced, deleted, or revealed during
the session is left alone.

Finder still draws hidden items, dimmed and clickable, while its "show all
files" setting is on. If that setting is on, the session turns it off with
Cmd+Shift+`.` (recorded in the journal) and turns it back on afterwards.
Synthesizing that keystroke needs an Accessibility grant; if the toggle cannot
be confirmed, hiding fails before any item is hidden.

[`startSession`](/docs/reference/react-api#startsession) calls these functions by
default. Under Finder Mode (`FINDER_MODE_SUPERVISED`), the signed app hides and
restores the Desktop itself, with its own journal at `~/.finder-mode-stash`,
and the session skips this step.

## System helpers

`getDesktopPath()`, `showDesktop()`, and `showDialog(...)`. Audio is in
[`filedom/sound`](/docs/reference/sound).
