An assistant app and extended mod for Star Trek Fleet Command, built on top of the STFC Community Mod by netniV and contributors.
This project would not exist without the work of netniV,
tashcan, and the entire STFC Community Mod team. The mod code in stfc-mod/
is imported from netniV/stfc-mod and kept as close to upstream
as practical, so that improvements can be shared with the community.
Project Daystrom picks up where the Community Mod leaves off. The mod already provides essential quality-of-life improvements — hotkeys, UI tweaks, zoom presets, data sync, and more. Project Daystrom builds on that foundation and adds:
- A native app (Tauri 2 + Vue 3) that runs alongside the game on macOS and Windows
- A cross-platform launcher replacing the platform-specific launchers (Swift on macOS, proxy DLL on Windows) with a single unified solution that handles entitlement patching, mod injection, and game launch
- Game update detection via the Scopely update API, with in-app update prompts
- Process monitoring that automatically detects game and launcher activity
- System tray integration with minimize-to-tray and quit protection
- Dashboard, alerts, and advisor plugins (planned) for live fleet overview, event notifications, and upgrade recommendations
The mod code lives in stfc-mod/ and is kept in sync with the upstream Community Mod. Improvements and bug
fixes flow both ways — anything useful to the broader community gets contributed back.
- Tauri 2 (Rust backend)
- Vue 3 + Vite (frontend)
- @mburchard/bit-log (structured logging)
project-daystrom/
├── package.json # Workspace root (orchestrating scripts)
├── pnpm-workspace.yaml # Workspace config (members: app, scripts)
├── eslint.config.js # Shared ESLint config (lints entire project)
├── tsconfig.base.json # Shared TypeScript base config
├── scripts/ # Build and tooling scripts
│ ├── build.ts # Mod + app build orchestration
│ └── package.json # Script dependencies
├── stfc-mod/ # STFC Community Mod (from netniV/stfc-mod)
│ ├── mods/ # Mod patches (C++23, IL2CPP hooks)
│ ├── macos-launcher/ # Original Swift launcher (being replaced)
│ ├── macos-dylib/ # macOS injection helper
│ ├── win-proxy-dll/ # Windows proxy DLL loader
│ └── xmake.lua # Build configuration
├── app/ # Project Daystrom app (Tauri 2 + Vue 3)
│ ├── modules/
│ │ ├── app/ # Vue 3 frontend
│ │ ├── backend/ # Tauri/Rust backend
│ │ └── plugins/ # Feature plugins (dashboard, alerts, advisor)
│ ├── resources/ # Shared assets (logo, icons)
│ └── package.json # App dependencies + app-local scripts
└── README.md
- Node.js >= 24
- pnpm >= 10
- Rust (stable)
- XMake (for building the mod)
- CMake (required by xmake to build C++ dependencies like spud)
- Apple Silicon — local development assumes arm64; the CI handles universal builds
- Xcode Command Line Tools (
xcode-select --install)
- Visual Studio Build Tools 2022 (or VS Community) — workload "Desktop development with C++" including a Windows SDK (not installed by default!)
- xmake:
irm https://xmake.io/psget.text | iexin PowerShell - Rust: standard installation via rustup-init.exe (option 1 selects MSVC toolchain)
nvm use
pnpm installAll commands run from the workspace root unless noted otherwise.
The mod code lives in stfc-mod/ and produces a shared library that gets injected into the game
(libstfc-community-patch.dylib on macOS, stfc-community-patch.dll on Windows).
pnpm build:modThis configures xmake for the current platform, builds only the mod target (stfc-community-patch),
and copies the result to app/resources/mod/. The full xmake build would also try to build the
original Swift launcher, which we don't need — Project Daystrom replaces it.
| Script | Description |
|---|---|
pnpm install:all |
Force-install all workspace dependencies |
pnpm lint |
Run ESLint across the entire project |
pnpm lint:fix |
Run ESLint with auto-fix |
pnpm typecheck |
TypeScript + Rust type checks |
pnpm test |
Run all tests (frontend + backend) |
pnpm test:app |
Run all app tests (frontend + backend) |
pnpm test:app:frontend |
Run frontend tests only (vitest) |
pnpm test:app:backend |
Run backend tests only (cargo test + ts-rs bindings) |
pnpm test:app:frontend:watch |
Run frontend tests in watch mode |
pnpm test:app:frontend:coverage |
Run frontend tests with v8 coverage |
pnpm test:app:backend:coverage |
Run backend tests with llvm-cov coverage |
pnpm build |
Build everything (mod dylib → Tauri app) |
pnpm build:mod |
Build mod dylib and copy to app/resources/mod/ |
pnpm build:app |
Build mod dylib + Tauri app bundle |
pnpm icons |
Generate Tauri icons from resources/daystrom.png |
pnpm dev |
Build mod + start Tauri app with hot reload |
| Alias | Resolves to |
|---|---|
@app/* |
modules/app/src/* |
@generated/* |
modules/app/src/generated/* |
@resources/* |
resources/* |
The GitHub workflow supports optional code signing for the NSIS installer. It requires a self-signed code signing certificate and two repository secrets.
New-SelfSignedCertificate -Type CodeSigningCert -Subject "CN=Your Name, Code Signing" `
-CertStoreLocation Cert:\CurrentUser\My -NotAfter (Get-Date).AddYears(5)The thumbprint is shown when creating the certificate. You can also find it via:
Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert$cert = Get-ChildItem Cert:\CurrentUser\My\<thumbprint>
$pw = Read-Host -AsSecureString "PFX password"
Export-PfxCertificate -Cert $cert -FilePath daystrom.pfx -Password $pwcertutil -dump daystrom.pfxEncode the PFX as Base64 and copy to the clipboard.
Note that PowerShell resolves relative paths from the user's home directory, not from the current working directory.
Use an absolute path to avoid surprises.\
[Convert]::ToBase64String([IO.File]::ReadAllBytes("<path-to-pfx>")) | Set-ClipboardThen set these repository secrets in GitHub:
| Secret | Value |
|---|---|
WINDOWS_PFX_BASE64 |
Base64-encoded PFX (clipboard) |
WINDOWS_PFX_PASSWORD |
The password from the export |
Shared types between Rust backend and TypeScript frontend are auto-generated by
ts-rs. Rust structs annotated with #[derive(TS)] produce
TypeScript interfaces in app/modules/app/src/generated/ whenever pnpm test:app:backend runs.
Rust doc comments are carried over as JSDoc.
#[derive(Serialize, TS)]
#[ts(export)]
pub struct GameStatus { /* ... */ }import type {GameStatus} from '@generated/GameStatus';Plugins live in modules/plugins/ and are loaded by the main app. The architecture is
intentionally modular so that individual plugins can be developed and published independently.
| Variable | Default | Description |
|---|---|---|
DAYSTROM_DEVTOOLS |
1 |
Set to 0 to suppress DevTools in debug builds |
This project is licensed under the GNU General Public License v3.0.