π« HudCitizen β Overlay for Star Citizen to keep eyes on FPS, webpage, trade route and more in the future...
Multiβwindow overlay for Star Citizen: shortcut dock at the bottom of the screen, movable widgets (FPS, network, kill feed, embedded browser, etc.), window pinning and a global shortcut to show or hide the overlay.
- French (100%)
- English (100%)
- German (100%)
- Spanish (100%)
- Node.js (LTS recommended, e.g. 20 or 22)
- npm (comes with Node)
- On Windows (main target of the project)
Optional for full features:
- PresentMon (FPS widget): either a bundled copy (place
PresentMon.exeinvendor/presentmon/beforenpm run electron:buildβ MIT license, seevendor/presentmon/LICENSE-PresentMon.txt), or installation in thePATH/ absolute path in Settings - Game
**Game.log** file for session time and kill feed (default path like...\StarCitizen\LIVE\Game.log)
- Activating global shortcut can be detected by windows as a keylogger
At the root of the repo:
npm installThe command first chains an initial compilation (tsc) to produce dist-electron/ without a race with Electron, then starts in parallel: watch compilation of main/preload, the Vite server, and Electron only after http://localhost:5173 responds (wait-on).
npm run electron:dev- Default shortcut to show / hide the overlay:
Ctrl+Shift+O(configurable in Settings). - The bottom dock only appears when the overlay is shown.
- A tray icon (taskbar) also offers Show / hide overlay β useful when the keyboard shortcut does not respond (see below).
If you prefer to launch the steps manually (3 terminals):
- Terminal 1:
npm run dev:mainβ wait for the first successful compilation (presence ofdist-electron/main/index.js). - Terminal 2:
npm run devβ Vite on port 5173; keep the server running. - Terminal 3:
npm run startβ this script automatically chains:
**npm run build:electron**: compiles main/preload once (ensuresdist-electron/even if terminal 1 is late);**wait-on**: waits forhttp://localhost:5173to respond (avoids blank windows if Electron starts before Vite);- launching Electron with
VITE_DEV_SERVER_URL=http://localhost:5173.
Do not: run npm start alone while Vite is not started β renderer URLs will be unreachable.
http://localhost:5173 is the Vite development server address. In this project, it is only used to serve the UI files (HTML, JS, CSS) to the Electron process during development, with fast reload.
In electron:dev mode, windows load URLs like:
http://localhost:5173/shell.htmlβ fullβscreen overlay (veil + dock)http://localhost:5173/widgets/fps.htmlβ example widgethttp://localhost:5173/settings.htmlβ settings
The root **.env** file defines VITE_PORT and VITE_DEV_SERVER_URL: they must match the actual Vite port (default 5173).
| Context | Role of localhost:5173 |
|---|---|
| Development | Serves the pages loaded by Electron (shell.html, widgets, etc.). |
Browser on / |
Nothing planned: no home page at the root. |
Production build (npm run build) |
No need for this server anymore: the app reads files from dist/ locally. |
Generates the UI in dist/ and the Electron code in dist-electron/:
npm run buildAfter npm run build:
npm run electron:buildThe result (NSIS installer) is placed in the **release/** folder (see electron-builder configuration in package.json).
βββ package.json # npm scripts, dependencies, electron-builder target
βββ eslint.config.js # ESLint (flat config, TypeScript)
βββ vite.config.ts # Multi-page build (dock, widgets, settings)
βββ tsconfig.electron.json # Main process (ESM)
βββ tsconfig.preload.json # Preload β CommonJS, renamed to `preload/index.cjs`
βββ scripts/rename-cjs.mjs
βββ src/
β βββ main/ # Electron main process
β β βββ index.ts # Entry point, services, timers
β β βββ tray.ts # Tray icon (show / hide)
β β βββ window-manager.ts # Windows: dock, widgets, visibility / pinning
β β βββ ipc-setup.ts # IPC, global shortcuts / low-level hook, external URLs
β β βββ low-level-toggle-shortcut.ts # Windows option: WinKeyServer + combo
β β βββ accelerator-to-combo.ts # Parse accelerator β detectable keys
β β βββ resolve-win-key-server-path.ts
β β βββ store.ts # Persistence (electron-store)
β β βββ types.ts
β β βββ services/ # Game.log, PresentMon, network stats
β βββ preload/ # Secure bridge exposed to renderer (`window.overlay`)
β βββ renderer/ # React UI + Vite
β βββ shell.html # Full-screen overlay (veil + dock)
β βββ shell/
β βββ dock/ # Dock component (icon bar)
β βββ settings.html # Settings window
β βββ settings/
β βββ widgets/ # One HTML entry + folder per widget (fps, kill-feed, β¦)
β βββ components/
β βββ styles/
βββ dist/ # Vite output (generated, do not version)
βββ dist-electron/ # Compiled main + preload JS (generated)
The **dist/**, **dist-electron/**, **release/** and **node_modules/** folders are normally ignored by Git (see .gitignore).
| Script | Role |
|---|---|
npm run dev |
Vite server only (web UI). |
npm run dev:main |
Continuous compilation of Electron code (tsc --watch). |
npm run electron:dev |
Full development environment (recommended). |
npm run build:electron |
Oneβoff main/preload compilation to dist-electron/. |
npm run build |
vite build + build:electron. |
npm start |
Use only if Vite is already running. |
npm run lint |
ESLint (eslint.config.js). |
npm run check |
build:electron + lint + vite build. |
npm run electron:build |
Build + installer creation in release/. |
npm run preview |
Preview the Vite build (without Electron). |
With Star Citizen in the foreground in fullscreen or borderless, the game may capture the keyboard before Windows forwards global shortcuts registered by the overlay (Ctrl+Shift+O, etc.). This is not a local configuration issue: it is a common limitation with games and the API used by Electron for hotkeys.
Ideas:
- Tray icon: left click or context menu β Show / hide overlay (works even when the shortcut doesnβt go through in game).
- Alt+Tab to desktop or another window, then use the global shortcut.
- Relaunch the overlay executable while the app is already running: the second instance is ignored and the first one reβshows the overlay (singleβinstance lock). You can bind a Windows shortcut or macro to this launch.
- Different key combo in Settings: useful if another app uses the same key; often not enough if the game blocks the whole keyboard in the foreground.
- Low-level keyboard hook (Windows, experimental): in Settings, tick the option to use the same shortcut via a small helper executable (
[node-global-key-listener](https://www.npmjs.com/package/node-global-key-listener)), similar to aWH_KEYBOARD_LLhook. Disabled by default: risk of antivirus false positives, no guarantee with antiβcheat or the game. IfWinKeyServer.exeis not found in the packaged app, the overlay automatically falls back to the standard global shortcut.
Respect RSIβs Terms of Service and their rules on thirdβparty tools. This tool does not modify the game client; it reads log files and system metrics external to the game process.


