# Using the Game Kits on the desktop (the native player) Make a game that starts with a double click on Linux or Windows — no browser, no Rust, no Node on the player's machine. Readable offline: `grip-forge docs desktop`, or the MCP tool `gripforge_docs` (topic `desktop`). ## What it is for `gripforge game-export --target desktop` makes a folder from a game: the **prebuilt native player** and the game as data. The player is the Bevy player of the web, built for the desktop; it loads `libgfkits`, the Rust logic of the Game Kits, and `libgfpresent`, the library of the kits' presentation modules — the files the Godot addon uses. One source per kit and per module: compiled to WebAssembly for the web page, to native code here — the same rules, the same drawing commands, no interpreter in between. Exporting a game compiles nothing: the same player opens any game. ## Prerequisites - The GripForge CLI. - A game (`gkp_…`), or its web export (`gripforge game-export `). - On the player's machine: Linux x86-64 or Windows x86-64 (10 and later) with a Vulkan driver. See *Platforms*. ## Install Nothing to install beside the CLI, 0.3.53 or later (`gripforge update` gives the current one). The player is fetched by the export: about 30 MB per platform the first time, then from the cache. ## First run: export a game ```sh gripforge game-export gkp_1234 my-game --target desktop my-game/play.sh # Linux; on Windows: my-game\play.cmd ``` The command downloads the web export of the game under `my-game/.gripforge/web`, takes the prebuilt player, and writes: | Path | What | |---|---| | `play.sh`, `play.cmd` | The launcher: starts the player of the machine's platform with the game of the folder. | | `bin//gripforge-player` | The prebuilt player. | | `bin//libgfkits.so` | The logic of the kits (the kit host behind `gfkits.h`), native code (`gfkits.dll`, `libgfkits.dylib`). Without it the player stops with `kit_library_missing`. | | `bin//libgfpresent.so` | The presentation modules of the kits, native code (`gfpresent.dll`, `libgfpresent.dylib`). | | `game/game.json` | The game: its project, its lockfile and its game schema — the documents the web page runs. | | `game/present.json` | Where the files of the model and texture slots are, and the clips of each model. | | `game/assets/` | Models, textures, sounds. | | `export.json` | What was exported: the player version, the platforms, the sha256 of every file. | Options: | Option | Effect | |---|---| | `--from-web ` | Use a web export you already have instead of downloading one (offline). | | `--runtime ` | Take the player from a local folder instead of the published release (offline, or a player you built). | | `--platforms a,b` | Only these platforms: `linux-x86_64`, `windows-x86_64` (default: every platform of the player package). | | `--bundle-web-engine` | Put the browser engine of the interface in the folder: the game never downloads it (see *HUD and menus*). | | `--webui-engine-when first-load\|install` | When the engine is installed when it is not in the folder: the first time the game starts (default), or only by `./play.sh --prepare`. | | `--webui-engine-url ` | The address the game downloads its engine from (default: the site of GripForge). | | `--check` | Say what would change, write nothing. | | `--force` | Replace files of the folder you edited. | | `--json` | The report as JSON. | Run the export again on the same folder to update it. A file you edited stops the update unless `--force` is given. ## Where the player comes from The CLI carries the catalogue of one player package: its version and, per platform, the sha256 of the archive and of every file in it. The archive is downloaded from `https://gripforge.ai/cli/gripforge-player//` (the assets of the release `gripforge-player-v`; `GRIPFORGE_DESKTOP_PLAYER_URL` names another base that holds `/`), checked against that catalogue before anything is unpacked, and kept in `~/.grip-forge/cache/gripforge-player-native/`. Nothing is trusted from the server. ## Errors The export stops with a named code when it cannot have the player: | Error code | Meaning | What to do | |---|---|---| | `desktop_player_not_catalogued` | This CLI carries no player catalogue. | Update the CLI, or pass `--runtime `. | | `desktop_player_version_not_published` | The release of that version is missing. | Update the CLI, or pass `--runtime`. | | `desktop_player_unreachable` | The download failed. | Check the network, or pass `--runtime`. | | `desktop_player_integrity` | A file differs from the catalogue. Nothing is kept. | Run again; report it if it persists. | | `desktop_player_platform_not_available` | `--platforms` names a platform that is not available yet (macOS). | Export for the other platforms. | | `desktop_player_platform_unknown` | `--platforms` names a platform the package does not have. | Use a listed platform. | | `webui_engine_no_archive` | `--bundle-web-engine` was asked and this CLI carries no engine for that platform. | Update the CLI, or export without it. | | `webui_engine_not_found`, `webui_engine_unreachable` | The engine could not be downloaded. | Check the network and run again: the download resumes where it stopped. | | `webui_engine_checksum` | The file downloaded is not the engine of this CLI. Nothing is kept. | Check `--webui-engine-url`. | A folder given to `--runtime` holds either the files of a release (the archives) or the unpacked platforms with their `manifest.json`. When the CLI has no catalogue, the manifest of the folder is used and the report says the player was not checked against a published release. ## Platforms | Platform | State | |---|---| | `linux-x86_64` | Available: played on screen (NVIDIA, Vulkan), with the HUD. | | `windows-x86_64` | Not available yet: its player was only replayed without a window under Wine, never run on Windows; no HUD. The launcher `play.cmd` is written when a package has it. | | `macos-universal` | Not available yet: `--platforms macos-universal` answers `desktop_player_platform_not_available` (« macOS: not yet available »). | | Android, iOS | Not supported yet. | ## What the native window shows - The models of the game, their clips, the camera, the lights, the scenery and the effects: everything the kits draw through their presentation modules, with the same module host as the web player. - The export warns about a kit the web draws through a module the player does not link. - **HUD and menus**: the fragments of the kits (`ui.webui`), the same page as the web, drawn over the game by the `ui.webui` module of the library (Linux). The export copies them into `game/` (`present-modules.json`, `modules/*.ui.mjs`). See *HUD and menus* below and *Known limits*. - Keyboard and mouse buttons go to the input actions of the kits; the kits ask for full screen and pointer lock through their display settings. - **Which kits run**: every kit whose logic is in the native library runs here with the rules of the web. The catalogue says it (`gripforge kit api `, section *Targets*: `rust: native (libgfkits)`) and names what is still missing on the desktop: a view of a kit drawn on the web page only (*to provide by a ui.webui fragment*), a fragment not yet in the published player, or a part of the network core (below). ### HUD and menus (the browser engine) The interface of a game is made of web fragments (`ui.webui`). Its native form needs a browser engine embedded in the game — never the browser of the machine: about 133 MB to download on Linux (308 MB once unpacked), 153 MB on Windows, 127 MB (Apple silicon) or 135 MB (Intel) on macOS. It is a dependency installed once into a cache shared by every game of the user, at one of three moments: - **the first time the game starts** (default): the game loads and plays meanwhile, the band at the top of the window shows the download, and the HUD appears when the engine is ready. A download cut in the middle is tried again, then resumed where it stopped at the next start; - **when the game is installed**: `./play.sh --prepare` installs it with no window and exits (0 = ready); an installer or a machine without network at play time runs it once. `gripforge webui-engine prepare` does the same without any game. Export with `--webui-engine-when install` for a game that must never download while it plays; - **in the game**: `--bundle-web-engine` puts it in the exported folder; nothing is downloaded, ever. The file downloaded is checked against the sum the game carries before anything is unpacked: the address can be changed (`--webui-engine-url ` at export, `--webui-engine-url=` or `GRIPFORGE_WEBUI_ENGINE_URL` when the game starts, a local folder as `file:///…/`), the engine cannot. Where the engine is looked for, in order: `webui-engine/-/` beside the player, the folder named by `GRIPFORGE_WEBUI_ENGINE_DIR` (or `--webui-engine-dir=`) or else the cache of the user, then a download; `--no-webui-engine-download` forbids the download. The cache of the user is `~/.cache/gripforge/webui-engine/` on Linux (`$XDG_CACHE_HOME/gripforge/…` when set), `%LOCALAPPDATA%\GripForge\webui-engine\` on Windows and `~/Library/Caches/GripForge/webui-engine/` on macOS; the engine of a version lives in its own folder there, `-/` (for example `154.0.34-1-macos-aarch64/`). An archive of the engine has no folder at its top: to install one by hand, unpack it INTO that folder (`mkdir -p /- && tar xzf -C /-`), or let `gripforge webui-engine prepare` do it. **No interface is never silent.** When the module, the host page or the engine is missing, or the engine cannot be fetched, the game starts and goes on, and the named reason (`webui-module-missing`, `webui-host-page-missing`, `webui-engine-no-archive`, `webui-engine-offline`, `webui-engine-checksum`…) is written in the log and shown in a band at the top of the window, with where the engine was looked for. While the engine is fetched the band shows the progress. The picture of the interface is a GPU texture the browser shares with the game: nothing is copied by the processor. On a machine where the browser cannot share one (a single NVIDIA card today), the module falls back to pictures copied through memory and says so in the log: `[ui.webui] FALLBACK cef-copy: no-shared-picture`. ## Checking an export ```sh my-game/bin/linux-x86_64/gripforge-player --replay my-game/game/game.json --reference reference.json ``` No window is opened: the game is played through the operations of a parity document `{ fixture, trace }` and its trace is compared with the reference trace — the one the web host and the Godot addon are held to. It prints `replay ok: N frames identical to the reference`, or the first difference and exits 1. `GRIPFORGE_STATS=2 my-game/play.sh` prints the frame rate every two seconds. `GRIPFORGE_CAPTURE=shot.png GRIPFORGE_CAPTURE_AFTER=8 my-game/play.sh` saves what the window shows after eight seconds and exits. `gripforge-player --about` prints the version, the presentation ABI, the library it loads and the kits it has a module for. `GRIPFORGE_PRESENT_LIBRARY=` loads another build of the library. ## Versions | Part | Version | |---|---| | Desktop export | CLI 0.3.48 and later; the HUD and `libgfkits` beside the player: CLI 0.3.50; the player downloaded by itself: CLI 0.3.53 | | Player package | `gripforge-player-native/1`, player 0.1.0 | | Presentation ABI | `gripforge:present@1` (v1.5), 61 modules in `libgfpresent` | | Kit logic | `libgfkits`, C interface 1.3 | | Engine | Bevy 0.18.1, Rust 1.99.0 | ## Known limits - The HUD and the menu of `ui.menu` (title screen, pause, Options) are web fragments; a click on one of their buttons becomes the command of its kit, as on the web (an event no module declared is refused by name in the log). Kits without a fragment are drawn as UI trees of their modules. The HUD of the car football and of the kart race is made of fragments too: the scoreboard and its banners (`sport.ball`), the objective (`input.actions`), the key prompts (`ui.prompts`), the end of the match (`ui.endscreen`), the race panel, item, speed and results (`race.kart`) and the mini-map (`hud.minimap`). The start screen of the race (shown by the web page while it holds the game) is not shown here: the race starts when the title screen closes. - The browser engine of the interface is built for Linux x86-64, Windows x86-64 (pictures copied through memory) and macOS (pictures copied through memory). It was run on screen on Linux; on Windows only under Wine; never on a Mac. - The player itself: Linux and Windows x86-64 today; macOS is not available yet (see *Platforms*). - Sound: the audio kit runs (its state is in the game), but the native window plays no sound yet. - Gamepads are not read by the native window yet. - Network kits (`net.*`): the network core is served natively (TCP+UDP, then the WebSocket bridge); WebRTC and the shared physics of `net.physics` are not, and are refused by name. - Saves: the kit host keeps them in memory; they are not written to the disk yet. - A game holds at most 128 model files and 256 MB of models.