Electron
Electron has its own manifest, lockfile, installed dependency tree, TypeScript configuration, main process, and preload bridge. It packages the same production www/ renderer as the other hosts.
Install and launch
Section titled “Install and launch”pnpm electron:installpnpm electron:startThe install target prepares the standalone shell and Electron binary. The start target builds the shared renderer, compiles the shell, applies the optional development signature, and launches it.
Validate the shell
Section titled “Validate the shell”pnpm electron:testpnpm electron:typecheckpnpm electron:verifypnpm electron:e2e:smokeUnit and type checks exercise Node-side shell code. The static verifier checks host and bridge contracts. The launched smoke journey proves a usable Electron process and renderer connection; it needs a supported machine and display.
Preserve the security boundary
Section titled “Preserve the security boundary”Renderer code uses the validated preload API, not direct Node or Electron access. IPC is protocol-versioned, sender-validated, and capability-scoped. Secure storage accepts only a usable operating-system encryption backend and keeps diagnostic payloads free of secrets.
Packaging targets produce host-specific artifacts and may require native toolchains or signing configuration. Do not describe a locally built development package as a release artifact. Release artifacts come from the release workflow; its Windows installer may be published unsigned, and Windows SmartScreen then warns about an unknown publisher on first run. Read host capabilities and desktop and native tests.
Window frame and title row
Section titled “Window frame and title row”The window is frameless by default. The renderer draws a 32px title row with the room title, the quick switcher, Report a bug (while Settings → Advanced → Keep a diagnostic log is on) and the system-status warning. On Windows and Linux the native minimise, maximise and close buttons are drawn over the row’s right end, and a ☰ button opens the application menu. Its menu bar is hidden rather than removed, so the menu keeps its keyboard accelerators. On macOS the row leaves room for the traffic lights. While the row shows, <body> has the trn-title-row class and --trinity-title-row-inset holds the row height. Global CDK overlays (dialogs, the lightbox, the widget frame) and other viewport-fixed layers start below the row, and viewport-sized panes subtract the inset. The CDK overlay container itself stays at the viewport origin, so anchored menus and tooltips keep their position. Otherwise the drag region and the native buttons would take clicks in the top 32px.
Settings → Appearance → Use system title bar brings back the operating system’s frame and menu bar. The choice is stored in window-prefs.json in the data folder and applies after Restart. Main passes the running mode to preload as --trinity-title-bar=row|system, so the first render already knows whether to draw the row. A missing or unknown value never draws it.
Application icons
Section titled “Application icons”All app, tray, notification and splash icons are generated from two sources in apps/trinity/src/assets/icon/: icon-plated.svg (the app icon) and icon.svg (the transparent mark, recoloured for single-colour variants). After editing either, run pnpm icons:generate and commit the results; scripts/generate-icons.spec.mjs fails when a committed icon no longer matches a fresh render. The operating system themes the app icon, not a Trinity setting: the macOS bundle icon is an Icon Composer source, electron/build/Trinity.icon (generated with the others), from which macOS 26 renders its Default, Dark, Clear and Tinted styles. Building it needs Xcode 26’s actool, so the macOS release job runs on macos-26. Windows and Linux show the Blurple icon; on Linux an icon theme may override the deb’s named icon.
Data and updates
Section titled “Data and updates”The desktop app stores its data in the Trinity folder under the operating system’s application-data directory (~/Library/Application Support/Trinity, %APPDATA%\Trinity, ~/.config/Trinity). The folder follows productName in electron/package.json; renaming it after a release would strand users’ sessions and encrypted keys.
There is no auto-updater. Packaged builds ask GitHub Releases for a newer release on their own line (stable builds see stable releases; -next builds also see newer prereleases), shortly after launch and then daily, and show one notification per new version that opens its release page. Help → Check for Updates… runs the same check on demand. Set TRINITY_DISABLE_UPDATE_CHECK=1 to turn the background check off; unpackaged development runs never check.