Game

0 in apps19 in games

Game-type apps ship with a built-in settings overlay: the panel players open to change window mode, resolution scale, monitor, and volume without you building a settings screen. You configure it in the dashboard's Settings Overlay section; the game namespace is how your game's own code drives it.

For a regular (non-game) app, every method resolves with success: false and a reason; nothing throws, so shared code can call these unconditionally.

What game builds include

Game builds run a lighter runtime than regular apps. You use the same window.deskifier calls; a few that games rarely need are left out. Your game still loads from its URL or its uploaded files, whichever you chose.

It keeps game builds more compatible across platforms and easier through store review; the introduction explains why.

Available in gamesNot available in games
Windows, webviews, tray, dock and taskbar (except dropped files, dragging files out, running code in another window, listing other apps' windows, and back/forward)Printers (printers)
Menus, notifications, message boxesGlobal shortcuts (shortcuts)
Camera and microphone (browser prompt)The local WebSocket server (webSocket)
Deep links, auto-updateControl of other apps (applications)
Steam, Discord, the settings overlay, savesThe open filesystem module and path-returning file dialogs (filesystem, dialog)
Platform and display infoLive CPU and memory, idle time, the cursor outside the window (system)
The game data folder, player-picked files, device ID and hardware (below)DevTools in production builds

Throughout these docs, pages and calls that game builds don't include are marked Apps only; everything unmarked works in both. Calling one from a game resolves with { success: false, reason: 'unavailable-in-games' } instead of throwing. Multiplayer is unaffected: WebSocket and fetch work in your game's page as they do in a browser; only the app-hosted WebSocket server is left out.

Open the overlay from your game

Players can open the overlay with the corner gear button, the keyboard shortcut, or a controller button; Start/Menu by default, rebindable in the dashboard with a press-to-capture picker. All three are configurable. The call below is the entrance that's yours: wire it to your pause menu's "Settings" item, and it works even when every other entrance is turned off:

await window.deskifier.game.openOverlay();

Close and toggle

await window.deskifier.game.closeOverlay();

const { open } = await window.deskifier.game.toggleOverlay();
console.log(open ? 'now showing' : 'now hidden');

Check state

Useful for pausing the game loop while the player is in settings:

const { open } = await window.deskifier.game.isOverlayOpen();
if (open) pauseGameLoop();

The overlay blurs and sits over your game while open, but it does not stop your render loop; pause it yourself if your game shouldn't run behind the settings panel.

What players can change

The overlay's rows are configured per-app in the dashboard (Settings Overlay section): window mode (fullscreen / borderless / windowed), resolution scale, monitor, volume, and a check-for-updates action. A Quit button is always present; a fullscreen game with no menu bar must always offer a way out. Player choices persist across launches on their machine.

Save durability

Browser games keep their saves in localStorage/IndexedDB, files buried in the app's data directory, invisible to players and lost on uninstall. Game apps protect them automatically: the app snapshots that storage to a visible GameSaves folder every few minutes and on quit, and restores it whenever storage comes back empty (a reinstall, a reset). No code required.

The manual handles, when you want them:

const { path, hasSnapshot, snapshotAt } = await window.deskifier.game.getSavesInfo();

await window.deskifier.game.snapshotSaves();   // e.g. right after a level completes
await window.deskifier.game.exportSaves();     // save-dialog → a zip the player keeps
await window.deskifier.game.importSaves();     // open-dialog → confirm → restart with imported saves

Steam Auto-Cloud

The GameSaves folder, and the game data folder below, sit at stable paths, which makes Steam Auto-Cloud configuration one root path per OS in the Steamworks partner site:

OSRootPath
WindowsWinAppDataRoaming<app-folder>/GameSaves and <app-folder>/GameData
macOSMacAppSupport<app-folder>/GameSaves and <app-folder>/GameData
LinuxLinuxHome.config/<app-folder>/GameSaves and .config/<app-folder>/GameData

<app-folder> is your app's name as set in the Deskifier dashboard, lowercased, with each run of spaces or symbols turned into a hyphen: "Orbit Racer" becomes orbit-racer.

Game data folder

A private folder for your game's own files: settings, save slots, downloaded levels. Your game reads and writes by relative name only; nothing outside the folder is reachable, and it's capped at 1 GB. Writes are atomic, so a crash mid-save never leaves half a file.

const files = window.deskifier.game.files;

await files.write('saves/slot1.json', JSON.stringify(state));
const { data } = await files.read('saves/slot1.json');
const state = JSON.parse(data);

// Binary data travels as base64
await files.write('replays/last.bin', base64Data, 'base64');

const { entries } = await files.list('saves');      // [{ name, isDirectory, size, modifiedAt }]
const { exists, size } = await files.stat('saves/slot1.json');
await files.delete('saves/slot1.json');
const { bytes, capBytes } = await files.usage();
await files.reveal();                                // open the folder, e.g. from a support screen

Paths like ../secrets.txt or /etc/hosts are refused with success: false.

Files the player picks

To bring a file in (a level, a mod) or hand one out (a replay, a screenshot), the player chooses it in a system dialog. Your game gets the contents, never the path.

const picked = await window.deskifier.game.pickFile({ extensions: ['json', 'lvl'] });
if (picked.success) loadLevel(picked.name, atob(picked.data));   // base64 by default
else if (picked.canceled) { /* the player closed the dialog */ }

await window.deskifier.game.saveFileAs('my-replay.json', JSON.stringify(replay));

Picked files are capped at 200 MB.

Device ID and hardware

getDeviceId returns an ID for the player's machine that stays the same across launches and reinstalls, for bans or per-device limits. It's different in every game, so two games can't match their players up.

const { deviceId } = await window.deskifier.game.getDeviceId();   // 32 hex characters

A determined player can change their machine's ID, so treat a device ban as a strong deterrent, not a guarantee. If you collect device IDs, mention it in your privacy policy (Apple's App Store privacy labels call this "Device ID").

getHardware returns a coarse summary for picking default graphics settings or attaching to crash reports:

const { os, cpu, memoryGB, gpus } = await window.deskifier.game.getHardware();
// { platform: 'darwin', arch: 'arm64', release }, { model: 'Apple M1', cores: 8 }, 8, ['Apple M1 ...']