Desktop application
The desktop build is on the download page for Linux, Windows and macOS, free like the rest of lapstack. The browser app is the same application with nothing to install.
The desktop build is the browser app in an Electron window. Nothing about the application changes: the same interface, the same engine, the same files. What changes is the shell around it.
Everything in the browser app section of this manual applies here unchanged.
Why it exists
Electron carries its own Chromium, and WebGPU runs in it on Linux, Windows and macOS with the switches already applied. So the desktop build removes the one genuinely annoying thing about the browser app:
- No browser profile to set up, and no launcher script on Linux.
- Native folder pickers and Save As dialogs, granted through Electron's permission handlers rather than depending on which browser you happen to use.
- It opens like Zerene Stacker or Helicon Focus do — one application in the dock.
(Tauri would have been lighter, but its WebKitGTK backend has no WebGPU on Linux.)
Installing
There is nothing to install yet. The packages planned for the first release, and what each is waiting on, are on the desktop and CLI page:
| Platform | Package | Status |
|---|---|---|
| Linux | AppImage, or a .deb | Builds and runs here; wider testing pending |
| Windows | NSIS installer | Not yet built; code signing pending |
| macOS | Disk image | Not yet built; notarization pending |
Until then, run it from source or use the browser app.
How it runs
main.js is the whole of it — a couple of hundred lines.
The page is served, not opened from disk. WebGPU needs a secure context and a file:// page
cannot fetch its WebAssembly, so the main process runs a small static HTTP server over the web
directory, bound to 127.0.0.1 on a port the system picks. Localhost is a secure context. It
serves GET and HEAD, keeps paths inside the directory, sets the MIME types the app needs, sends
Cache-Control: no-store, and applies a Content-Security-Policy that allows the page, its
WebAssembly, blobs and data URLs, and nothing from the network.
Nothing listens for anyone but the window.
The window is one BrowserWindow, shown once the page has painted, with Node integration
off, context isolation and the sandbox on, and no preload script — the page has no reason to
reach Node. Links that would open a new tab (the dust map preview's larger view) are refused.
The menu bar is hidden; Alt shows it, with the usual reload and developer tools. A second launch
brings the running window to the front rather than opening another.
Permissions. The app opens folders and saves files through the File System Access API and
copies the log to the clipboard. Electron asks the main process before granting any of that, and
a handler that says nothing denies. main.js grants fileSystem, clipboard-read and
clipboard-sanitized-write and nothing else. It answers allow to the
file-system-access-restricted event — Chromium otherwise refuses the Downloads folder and a
few system paths, and a stack sitting in Downloads is a normal thing. The app's download
fallback goes through a Save As dialog starting in Downloads.
Linux specifics
On Linux the app passes the same switches the Chrome launcher script does:
--enable-unsafe-webgpu, the Vulkan trio
(Vulkan,VulkanFromANGLE,DefaultANGLEVulkan), --ignore-gpu-blocklist, and
--ozone-platform=x11.
The last one has to be on the real command line: appending a switch from main.js reaches
the GPU process but not the browser process, which has already chosen its platform. So on Linux
the app relaunches itself once with --ozone-platform=x11. A Wayland window with an X11
Vulkan surface never maps — it stays blank — so the window runs on XWayland in a Wayland
session, whatever the desktop.
LAPSTACK_SWITCHES replaces the Linux switches, for troubleshooting.
Windows and macOS have WebGPU on by default, and the Linux switches are not passed there.
Running from source
cd desktop
npm install # Electron and electron-builder
npm start # run the app in a window
npm run smoke # a hidden window, the WebGPU adapter, the 8-frame test stack, exit 0 or 1
npm run dist # package for this platform (dist:linux | dist:mac | dist:win)The WebAssembly must be built first — ./web/build.sh, or just build-web — because the app
serves web/pkg and web/pkg-cc as they are.
Verified here on NixOS with KDE on Wayland and an RTX 3060: the smoke test passes on
the NVIDIA adapter with nixpkgs' Electron, the official Electron binary, the unpacked build
and the AppImage, and the window maps and presents. NixOS needs the FHS environment in
desktop/nix-fhs.nix for the npm Electron binary and electron-builder's tools.
The native pickers, the Save As dialog, and the Windows and macOS builds have not yet been exercised. Please report what you find.