ReferenceAPI

Desktop, folders, apps, and games

Reference for dd.desktop items, dd.folders listings and icons, dd.apps launching, and dd.games, the installed game library.

Four namespaces share one design: the host enumerates, the widget gets opaque ids, and opening something means handing an id back. A widget never passes a path, so it can only ever open what the host really listed.

They also share the change-ping pattern: onChange events carry no data, they just tell you to list again.

dd.desktop

Needs the desktop permission.

dd.desktop.list()

dd.desktop.list(): Promise<{ items: DesktopItem[] }>

interface DesktopItem {
  /** Opaque host-issued id: the only handle open() accepts. */
  id: string;
  name: string;
  kind: "file" | "folder" | "shortcut" | "virtual";
  /** Filesystem path; null for virtual items (Recycle Bin, This PC, ...). */
  path: string | null;
  /** Icon PNG data URI (up to 96 px), or null when the host couldn't extract one. */
  icon: string | null;
}

Everything currently on the user's desktop (user and public folders plus visible virtual items), sorted by name. Served from a host cache the desktop watcher keeps fresh, so it is cheap to call.

dd.desktop.open()

dd.desktop.open(id: string): Promise<void>

Opens the item like a desktop double-click; a folder item opens in the file manager the user chose in Settings > General, when one is set (app 0.3.7 or newer). Accepts only ids from list; a stale id (the item disappeared since your last list) rejects NOT_FOUND, so re-list and retry. 5 opens per rolling 10 seconds, shared with folders.open.

dd.desktop.onChange()

dd.desktop.onChange(cb: () => void): () => void

Data-free ping when the desktop's item set changes (add, remove, rename, icon refresh): call list again. Changes are debounced around 400 ms.

dd.folders

Needs the folders permission. All methods take settingKey, the name of one of this widget's filePath settings; the host resolves the folder the user pointed it at. A blank setting value resolves to the desktop source, which additionally requires the desktop grant.

dd.folders.list()

dd.folders.list(settingKey: string): Promise<{
  items: DesktopItem[];
  total: number;
  truncated: boolean;
  error?: string;
}>

One non-recursive listing of the granted folder. Items arrive with icon: null here; fetch icons for what you actually render via icons (the desktop source inlines them instead). Listings cap at 500 items (truncated: true, total is the real count). An unreadable folder (unplugged drive, dead share) answers the last good items plus error: "unavailable" rather than rejecting. 30 calls per rolling 10 seconds.

dd.folders.icons()

dd.folders.icons(settingKey: string, ids: string[]): Promise<{
  icons: Record<string, string>;
}>

Icon PNG data URIs (up to 96 px) for up to 128 listed ids, extracted on demand and cached host-side. Unknown or extraction-failed ids are simply absent from the result, so keep a glyph fallback. 60 calls per rolling 10 seconds.

dd.folders.open()

dd.folders.open(settingKey: string, id: string): Promise<void>

Opens a listed item like a double-click in Explorer; a folder item opens in the file manager the user chose in Settings > General, when one is set (app 0.3.7 or newer). Stale ids reject NOT_FOUND (re-list). Shares desktop.open's 5 per 10 seconds launch bucket, whichever source the id lives in.

dd.folders.onChange()

dd.folders.onChange(cb: () => void): () => void

Data-free ping when a folder one of your filePath settings points at changes (the desktop, for blank settings): re-list. Delivered only to the instances whose folder actually changed. Folders that cannot be watched (network shares generally) re-enumerate on every list instead of pretending.

dd.apps

Needs the systemApps permission.

dd.apps.list()

dd.apps.list(): Promise<{ apps: SystemApp[] }>

interface SystemApp {
  /** Catalog key: the only handle launch() accepts. */
  id: string;
  name: string;
  /** Icon PNG data URI (up to 96 px), or null (render your own glyph). */
  icon: string | null;
}

The host's fixed catalog of Windows system apps (Settings, File Explorer, Recycle Bin, Task Manager, Terminal, Control Panel, Calculator, Notepad, Snipping Tool), with real icons where the host could extract them. Icons are cached host-side after the first call. 30 calls per rolling 10 seconds.

dd.apps.launch()

dd.apps.launch(id: string): Promise<void>

Launches a catalog app by key. There is no path, URI, or executable surface here; ids from list are the whole vocabulary. A shell-folder entry (the Recycle Bin) opens in the file manager the user chose in Settings > General, when one is set, handed the folder's shell id; the File Explorer entry always launches explorer.exe (app 0.3.7 or newer). Each app carries host-owned fallback launch targets; if all fail the call rejects INTERNAL naming the app, and unknown ids reject NOT_FOUND. 5 calls per rolling 10 seconds.

dd.games

Needs the games permission. App 0.3.2 and newer.

dd.games.list()

dd.games.list(): Promise<{ games: InstalledGame[]; total: number }>

interface InstalledGame {
  /** Opaque host-issued id, the only handle launch and art accept. */
  id: string;
  name: string;
  store: "steam" | "gog";
  /** Tagged host-side, because a library is often a third demos. */
  kind: "game" | "demo" | "playtest";
  /** Epoch ms, or null when the store records no play history. */
  lastPlayedMs: number | null;
  /** Total minutes played, or null when the store records none. */
  playtimeMin: number | null;
  sizeBytes: number | null;
  installedMs: number | null;
}

Every game installed on this PC that a supported launcher vouches for, most recently played first and then alphabetical.

The sources are the launchers' own records, read off disk and the registry: Steam's per-game manifests plus its local play-time config, and the GOG registry keys that both Galaxy and the offline installers write. There is no folder scan anywhere in this, by design, so nothing else the user keeps on a games drive can ever appear here.

The appid, the registry id and the install path never cross the bridge. A widget sees the fields above and nothing more. GOG records no play history that the host can read, so its games always report lastPlayedMs: null and sort below anything played.

The scan is cached host-side for 60 seconds, so calling this every time a pane opens is cheap. 20 calls per rolling 10 seconds.

dd.games.art()

dd.games.art(
  ids: string[],
  kind?: "portrait" | "header",
): Promise<{ art: Record<string, string> }>

Cover art for up to 32 listed ids, as PNG or JPEG data URIs.

It comes from the launcher's own on-disk cache, never the network. kind picks the shape you lay out for: portrait (the default, a 2:3 library capsule) or header (the wide banner). Whichever you ask for, the other fills in when a title cached only that one, so a tile is rarely empty.

Ids with no cached art are simply absent from the result, so keep a placeholder. A GOG entry answers its executable's icon, since GOG caches no art. 30 calls per rolling 10 seconds.

dd.games.launch()

dd.games.launch(id: string): Promise<void>

Starts a listed game through its own launcher, by the target the host holds for that id. As with apps.launch, ids are the whole vocabulary: there is no path or command-line surface. An id from a stale list rejects NOT_FOUND rather than starting anything. 5 calls per rolling 10 seconds.