lapstack

Desktop application

Note

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:

PlatformPackageStatus
LinuxAppImage, or a .debBuilds and runs here; wider testing pending
WindowsNSIS installerNot yet built; code signing pending
macOSDisk imageNot 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

shell
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.

Note

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.

Source: sites/lapstack/content/docs/desktop.md