filedom/system
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.
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)andwaitForCalibratedMetrics()stream or await the calibratedSystemMetrics(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.jsonbefore 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)andsetIconPositions(...)move one or many files.getDesktopIconPositions()reads the live positions Finder reports.setIconColor,setFileComment, andsetFileExtensionHiddenset Finder metadata.setCustomIconFromPathandsetCustomIconFromBase64set custom icon images.synthDragAt(x, y, expectedPath?)posts a synthetic drag that raises a file’s z-order.
Grid, size & selection
getDesktopIconSize/setDesktopIconSizegetDesktopGridSpacing/setDesktopGridSpacinggetDesktopGridArrangement/setDesktopGridArrangementgetFinderSelection/setFinderSelectiongetDesktopLabelVisibility/setDesktopLabelVisibility
Finder control
runFinderBatch(...)applies a batch of Finder mutations in one round-trip.restartFinder()andrefreshFinder()recover Finder when its state drifts.
Input
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.useGameControlsin the main entry point wraps it.subscribeDesktopClick,subscribeDesktopRightClick,subscribeDesktopDrag,subscribeDesktopMouseUp, andsetDesktopDragRegionshandle mouse interaction on the desktop surface.subscribeDesktopRightClickconsumes 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
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.
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).
FilePool
FilePool is the recycling handle allocator the Stage uses internally. It is
exported for code that manages files outside a stage:
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 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.