Skip to content

Repository files navigation

BW Build Overlay Suite

CI Latest release License: MIT

An always-on-top desktop overlay that shows StarCraft: Brood War / Remastered build orders from a bundled release-time catalog. Native bundles for Windows, macOS, and Linux. Covers all three races (Terran, Protoss, Zerg) and all nine matchups.

Overlay screenshot placeholder

Run StarCraft in Windowed (Fullscreen) mode. True/exclusive fullscreen hides every other window — including this overlay. In Options > Graphics, set the display mode to Windowed (Fullscreen) (sometimes labelled "Borderless Windowed"). The overlay then sits on top of the game correctly.

Highlights

  • All 9 matchups (TvT/TvP/TvZ, PvT/PvP/PvZ, ZvT/ZvP/ZvZ) with race-themed colors.
  • Build orders shown as a clean paginated list — no per-step "click next".
  • Bundled Liquipedia-derived catalog generated by maintainers at release time.
  • Manual builds with personal notes and favorites.
  • Search, favorites, compact mode, opacity slider, click-through overlay mode, global hotkeys.
  • Built on Tauri 2 + Rust: native installers under ~10 MB. WebView2 / WKWebView / WebKitGTK provide the UI runtime.
  • Custom app icon, auto-opening DevTools in dev mode, F12 / Ctrl+Shift+I toggle anywhere.

Table of contents


For end users

Just want to use the overlay? You don't need any toolchain.

Download

Open the latest release and pick the right file for your OS:

OS Recommended Alternative
Windows BW-Build-Overlay_<version>_x64-setup.exe (NSIS) BW-Build-Overlay_<version>_x64_en-US.msi
macOS BW-Build-Overlay_<version>_universal.dmg (Intel + ARM) BW-Build-Overlay.app.tar.gz
Linux BW-Build-Overlay_<version>_amd64.AppImage bw-build-overlay_<version>_amd64.deb (needs libwebkit2gtk-4.1-0)

Launch the app. The overlay window stays on top of StarCraft and ships with a bundled build catalog. Open Manager to edit builds, choose favorites, or add your own manual builds.

Set StarCraft to Windowed (Fullscreen). In SC:R, open Options > Graphics and set Display Mode to Windowed (Fullscreen) (a.k.a. Borderless Windowed). True/exclusive fullscreen will hide the overlay; Windowed (Fullscreen) looks identical and lets the overlay stay on top.

Platform notes

  • Windows. WebView2 is pre-installed on Windows 10 21H2+ and Windows 11. The installer bundles the WebView2 bootstrapper for older systems. SmartScreen may warn the first time you run the EXE because it isn't code-signed — click "More info" → "Run anyway".
  • macOS. The .app is not code-signed or notarized. Gatekeeper will refuse the first launch. Right-click the app → OpenOpen in the dialog, or run xattr -d com.apple.quarantine /Applications/"BW Build Overlay.app" once.
  • Linux. The AppImage is self-contained — chmod +x and run. The .deb requires libwebkit2gtk-4.1-0 (sudo apt install libwebkit2gtk-4.1-0).

Hotkeys

Hotkey Action
Ctrl+Alt+1 / 2 / 3 Player race: Terran / Protoss / Zerg
Ctrl+Alt+Q / W / E / R Opponent: Terran / Zerg / Protoss / Random
Ctrl+Alt+B Next build in current matchup
Ctrl+Alt+Shift+B Previous build
Ctrl+Alt+PgDn / PgUp Next / previous page of long builds
Ctrl+Alt+0 Jump to page 1
Ctrl+Alt+F Toggle favorite on current build
Ctrl+Alt+C Toggle compact mode
Ctrl+Alt+L Toggle overlay mouse click-through
Ctrl+Alt+K Toggle overlay reposition mode
Ctrl+Alt+H Hide / show overlay
/ (in overlay) Focus the build search
F12 / Ctrl+Shift+I Toggle DevTools (debug log)

Build Manager

Click Manager to edit the catalog and app behavior. Tabs:

  • Edit - manually create or edit a build (id, race, opponent, difficulty, tags, steps, notes). Saving marks edited builds as customEdited so future bundled catalog refreshes won't overwrite your changes.
  • Settings - compact mode, window opacity, game-safe click-through, overlay snap-to-corner controls, app update checks/install, page size, default race, and the bundled catalog's last sync date.

Debug mode

If something looks broken (overlay frozen, click does nothing, data not loading, etc.), open DevTools to see what's happening:

  • Press F12 or Ctrl+Shift+I anywhere in the app — DevTools toggles in any build.
  • Set the env var BW_DEVTOOLS=1 before launching to auto-open DevTools on startup. Useful when filing bug reports:
    # Windows
    $env:BW_DEVTOOLS = "1"
    & "$env:ProgramFiles\BW Build Overlay\BW Build Overlay.exe"
    # macOS / Linux
    BW_DEVTOOLS=1 "BW Build Overlay"
  • The Console tab shows logs ([bw-overlay] renderer booted confirms the renderer started).
  • If the renderer fails to boot, a red banner appears at the top of the overlay window with the error.

When filing a bug, please attach the DevTools console output as a screenshot or copy-paste.

Data location

Your builds, settings, and backups live in your OS-specific user-data folder. Tauri uses the bundle identifier (com.local.bwbuildoverlay) for the directory name:

OS Path
Windows %APPDATA%\com.local.bwbuildoverlay\
macOS ~/Library/Application Support/com.local.bwbuildoverlay/
Linux ~/.local/share/com.local.bwbuildoverlay/ (or $XDG_DATA_HOME/...)

Each folder contains:

  • builds.json — your build library.
  • settings.json — overlay opacity, rate limit, default race, etc.
  • builds-backup-*.json — timestamped backups produced by Manage > Backup builds.json.

App updates replace the application binaries but keep this user-data directory intact. Your manual builds, customEdited entries, favorites, and personal notes remain in place across updates.

Use Manage > Open data folder to open the directory in your file manager.


For developers

Prerequisites

  • Node 24 LTS (the repo includes a .nvmrc; nvm use will pick the right version on systems with nvm or nvm-windows).
  • npm 11+ (ships with Node 24).
  • Rust 1.85+ via rustup — the rust-toolchain.toml at the repo root pins stable and adds clippy + rustfmt automatically on first cargo invocation.
  • OS-specific Tauri build deps:
    • Windows: Microsoft Visual C++ Build Tools (Workload "C++ build tools" — installed by rustup-init on Windows when prompted). WebView2 is pre-installed on Win10 21H2+ and Win11.
    • macOS: Xcode Command Line Tools (xcode-select --install).
    • Linux: libwebkit2gtk-4.1-dev, libgtk-3-dev, libsoup-3.0-dev, libjavascriptcoregtk-4.1-dev, libayatana-appindicator3-dev, librsvg2-dev. See the Tauri prereqs page for the apt/dnf/pacman one-liner.

Verify:

node --version   # v24.x
npm --version    # 11.x or newer
rustc --version  # 1.85 or newer
cargo --version

Quick start

git clone https://github.com/Etra-0/starcraft-build-overlay.git
cd starcraft-build-overlay
npm install
npm run dev

npm run dev (which is just npm run tauri:dev):

  1. esbuild --watch rebuilds the renderer bundle into dist-frontend/ on every src/renderer/ change.
  2. npx tauri dev builds and launches the Rust backend with BW_DEVTOOLS=1 so DevTools auto-opens.

Renderer changes hot-reload on save. Rust changes trigger a recompile + relaunch (Tauri handles this automatically).

Available scripts

Script What it does
npm run dev / npm run tauri:dev Watch builds + Tauri with DevTools auto-open.
npm run dev:renderer Just the esbuild watch for the renderer bundle (writes to dist-frontend/).
npm run build:renderer One-shot renderer build → dist-frontend/renderer.js + static assets.
npm run tauri:build Production build of the renderer + Tauri bundle for the host OS.
npm run dist Alias for npm run tauri:build (NSIS/MSI on Windows, DMG/.app on macOS, AppImage/.deb on Linux).
npm run dist:win / :mac / :linux Build only the bundles for that OS family (still has to run on the corresponding host — Tauri does not cross-compile bundles).
npm run typecheck TypeScript type-only check for the renderer (tsconfig.renderer.json).
npm run lint / npm run lint:fix ESLint (flat config; eslint.config.mjs selects **/*.ts).
npm run format / npm run format:check Prettier write / check.
npm test cargo test --manifest-path src-tauri/Cargo.toml - runs Rust unit and fixture tests (storage, parser, importer, utils).
npm run scrape Maintainer-only catalog refresh. Rebuilds data/builds.json and data/scrape-coverage.json from Liquipedia with rate limiting.
npm run clean Delete dist-frontend/ and src-tauri/target/.
npm run size Print the size (MB) of the latest bundle artifacts under src-tauri/target/release/bundle/.
npm run release:patch | minor | major Bump version (package.json, Cargo.toml, tauri.conf.json), rotate CHANGELOG.md, refresh Cargo.lock, commit, and tag (see Releasing).

How the build works

src/renderer/*.ts      ──esbuild──>  dist-frontend/renderer.js  (single ESM bundle)
index.html, styles.css ─────cp─────>  dist-frontend/             (static assets)
assets/icon.png        ─────cp─────>  dist-frontend/

src-tauri/src/*.rs     ──cargo build──>  src-tauri/target/release/bw-build-overlay
src-tauri/icons/*       ──tauri bundle──>  src-tauri/target/release/bundle/
                                             ├── nsis/   (Windows .exe installer)
                                             ├── msi/    (Windows .msi)
                                             ├── dmg/    (macOS .dmg)
                                             ├── macos/  (macOS .app)
                                             ├── appimage/  (Linux .AppImage)
                                             └── deb/    (Linux .deb)

The frontendDist field in src-tauri/tauri.conf.json points at ../dist-frontend. Tauri reads HTML/JS/CSS from there at runtime in dev, and embeds them into the resulting bundle in release. There's no Chromium download — the OS-bundled WebView (WebView2 on Windows, WKWebView on macOS, WebKitGTK on Linux) renders the UI.

The renderer is bundled (rather than just transpiled) because the WebView runs the renderer in a sandboxed browser context with no Node integration — require() / import.meta.url to filesystem paths aren't available. esbuild produces one self-contained ESM file.

Cleaning and rebuilding from scratch

The dist-frontend/ and src-tauri/target/ folders are git-ignored and regenerated on every build:

npm run clean       # deletes dist-frontend/ and src-tauri/target/
npm install         # if you blew away node_modules too
npm run tauri:build

The bundle artifacts under src-tauri/target/release/bundle/<format>/ are your shippable outputs.


Releasing

Versioning follows Semantic Versioning: MAJOR.MINOR.PATCH.

Where the version lives

The single source of truth is the version field in package.json. The release script propagates it to:

  • src-tauri/Cargo.toml [package].version (and Cargo.lock).
  • src-tauri/tauri.conf.json .version.
  • The GitHub Release tag (vX.Y.Z).
  • Bundle filenames (BW-Build-Overlay_X.Y.Z_x64-setup.exe, BW-Build-Overlay_X.Y.Z_universal.dmg, etc.).
  • The default User-Agent the maintainer scrape helper sends (sourced from CARGO_PKG_VERSION at compile time).

Cutting a release

  1. Edit ## [Unreleased] in CHANGELOG.md with the user-visible changes for this version (Added / Changed / Fixed / Removed).
  2. Run one of:
    npm run release:patch   # 1.0.0 -> 1.0.1   (bug fixes)
    npm run release:minor   # 1.0.0 -> 1.1.0   (new features, backwards compatible)
    npm run release:major   # 1.0.0 -> 2.0.0   (breaking changes / data migrations)
    This script bumps package.json + Cargo.toml + tauri.conf.json, refreshes Cargo.lock, rotates the changelog (Unreleased becomes [X.Y.Z] - YYYY-MM-DD and a fresh Unreleased block is added on top), commits, and tags vX.Y.Z. Use --dry-run to see what would happen without changing anything.
  3. Push:
    git push origin main --follow-tags
  4. Ensure updater signing secrets are configured in GitHub Actions:
    • TAURI_SIGNING_PRIVATE_KEY
    • TAURI_SIGNING_PRIVATE_KEY_PASSWORD (optional when key has no password)
    • BW_UPDATER_PUBKEY (public key content used by runtime updater checks)
  5. The Release workflow is a windows-latest × macos-latest × ubuntu-latest matrix that runs tauri-apps/tauri-action@v0. Each runner produces its native bundles (NSIS/MSI on Windows, universal DMG on macOS, AppImage/.deb on Linux) and uploads them to a draft GitHub Release named BW Build Overlay <tag>. Edit the body and publish when ready.

Catalog refresh

The installed app does not contact Liquipedia. Maintainers refresh the bundled catalog before release:

npm run scrape

That command updates data/builds.json and data/scrape-coverage.json. Releases now skip scraping by default; run npm run release:patch|minor|major -- --scrape when you intentionally want a fresh Liquipedia snapshot in that release. On app launch, a newer bundled catalog is merged into the user's local builds.json while preserving favorites, personal notes, recently-used state, and builds marked customEdited.

CI runs in two stages on every PR and push to main (ci.yml):

  • A quality job (Ubuntu) runs format:check, lint, typecheck, plus cargo fmt --check, cargo clippy -- -D warnings, and cargo test.
  • A package matrix (windows-latest + macos-latest + ubuntu-latest) builds the renderer and runs cargo build --tests so platform-specific Rust regressions surface on PRs without paying for the full bundle build.

Dependency upgrades come in via Dependabot on a weekly cadence.


Project layout

src/
  shared/
    types.ts        OverlayAPI IPC contract + Build/Settings/Race types
    utils.ts        pure helpers (deriveMatchup, slugify, splitStep, ...)
  renderer/
    index.ts        renderer entry (bundled by esbuild into one ESM file)
    api.ts          @tauri-apps/api invoke/listen wrapper implementing OverlayAPI
    state.ts        in-memory state + localStorage
    dom.ts          typed element refs (Dom interface, byId<T> helper)
    toast.ts        non-blocking notifications
    overlay.ts      overlay rendering + paging
    manager.ts      Manager modal, build list
    edit-tab.ts     Edit tab form
    settings-tab.ts Settings tab UI
    hotkeys.ts      hotkey-event -> handler dispatch (typed HotkeyAction union)
src-tauri/
  Cargo.toml        Rust crate manifest, deps + release profile
  tauri.conf.json   window, identifier, bundle targets, CSP, frontendDist
  capabilities/     Tauri 2 permission manifests
  icons/            generated platform icons (don't hand-edit)
  src/
    main.rs         binary entry point (calls run() from lib.rs)
    lib.rs          Builder, plugin registration, app state, hotkey/window setup
    commands.rs     #[tauri::command] handlers — one per OverlayAPI method
    storage.rs      builds.json + settings.json I/O, schema migration
    window.rs       opacity, always-on-top keeper, devtools toggle, global shortcut registration
    types.rs        serde structs mirroring src/shared/types.ts
    utils.rs        Rust port of src/shared/utils.ts (deriveMatchup / slugify / splitStep)
    liquipedia/
      api.rs        rate-limited reqwest MediaWiki client
      parser.rs     {{build}} template parser, infobox, counters
      import.rs     release-time page import and merge logic
      updates.rs    revision check helpers used by maintainer tooling/tests
dist-frontend/      esbuild + static-asset output [git-ignored]
src-tauri/target/   cargo build output                [git-ignored]
data/builds.json    seed library (all 9 matchups), embedded as a Tauri resource
assets/icon.png     icon source (icons/ are generated from this)
scripts/            build-renderer.mjs, dev.mjs, release.mjs, report-size.mjs
index.html          entrypoint that loads ./renderer.js
styles.css
tsconfig.renderer.json  typecheck config for the renderer (ESM, DOM)
rust-toolchain.toml     pins stable + clippy + rustfmt

Maintainer catalog scraper notes

The release-time scraper parses Liquipedia's {{build|...}} template directly (it looks for *8 - Pylon style bullet lines inside the template). Supports:

  • Multi-variant pages (each section's {{build}} becomes a separate build, linked via variantOf).
  • {{Infobox strategy}} for race / matchups / creator / popularizer.
  • ==Counter To== and ==Countered By== lists (shown at the bottom of the build card).
  • Difficulty tags from Category:* Beginner/Intermediate/Advanced Strategy.
  • Per-build revisionId tracking in the checked-in catalog for auditability.

The scraper respects Liquipedia's rate-limiting (default 2300 ms between requests). Use BW_LIQUIPEDIA_USER_AGENT or npm run scrape -- --user-agent=... with a contact-able User-Agent when refreshing the checked-in catalog.

App icon

The icon source is assets/icon.png (square, ≥1024×1024). Tauri's CLI generates all platform-specific outputs from it:

npx tauri icon assets/icon.png

This regenerates everything under src-tauri/icons/ — Windows .ico, macOS .icns, multiple PNG sizes, and Android/iOS variants. Tauri picks the right one for each bundle target automatically.

Schema

Each build:

{
  "id": "pvt-1-gate-core",
  "race": "Protoss", // player race: Terran | Protoss | Zerg
  "opponent": "Terran", // Terran | Zerg | Protoss | Random
  "matchup": "PvT", // derived
  "name": "1 Gate Core",
  "variantOf": null, // parent build id when this came from a multi-variant page
  "tags": ["standard", "starter"],
  "difficulty": "beginner", // beginner | intermediate | advanced | null
  "sourceName": "Liquipedia",
  "sourceUrl": "https://liquipedia.net/starcraft/1_Gate_Core_(vs._Terran)",
  "sourcePageTitle": "1 Gate Core (vs. Terran)",
  "notes": "...", // catalog description
  "userNotes": "", // your own notes; survives bundled catalog refreshes
  "customEdited": false, // true => bundled catalog refreshes skip this build
  "favorite": false,
  "recentlyUsedAt": null,
  "revisionId": 12345, // Liquipedia revision id captured by maintainer scraper
  "lastImportedAt": "...",
  "lastCheckedAt": "...",
  "counters": ["..."],
  "counteredBy": ["..."],
  "steps": ["8 - Pylon", "10 - Gateway", "..."]
}

Schema migrations run automatically in src-tauri/src/storage.rs (SCHEMA_VERSION constant; currently 4).


Troubleshooting

Symptom Likely cause Fix
Overlay disappears the moment StarCraft starts StarCraft running in true/exclusive fullscreen Options > Graphics > Display Mode = Windowed (Fullscreen). Always-on-top windows can't sit above an exclusive-fullscreen Direct3D surface.
Overlay drops behind the Windows taskbar after clicking it Known Tauri 2 always-on-top regression The app re-applies always-on-top on focus loss; if it persists, hit Ctrl+Alt+H twice to toggle, or relaunch.
npm run tauri:dev fails with "linker link.exe not found" MSVC C++ Build Tools missing on Windows Re-run rustup-init and accept the MSVC toolchain prompt, or install Visual Studio's "Desktop development with C++" workload manually.
npm run tauri:dev fails with "webkit2gtk not found" on Linux Missing Tauri prereqs sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev (or the dnf/pacman equivalent).
macOS launch is blocked: "BW Build Overlay" can't be opened Unsigned .app quarantined by Gatekeeper Right-click → Open → Open, or xattr -d com.apple.quarantine /Applications/"BW Build Overlay.app".
Overlay opens but clicks do nothing Renderer bundle stale (rebuilt Rust but not renderer) npm run build:renderer and relaunch.
Built bundle launches and closes instantly Crash on startup Set BW_DEVTOOLS=1 and re-launch — DevTools console will show the error.
GitHub release didn't get bundles for one of the OSes One matrix runner failed Open the failed Release workflow run and read the build log for that runner.

License

MIT — see LICENSE.

Support

  • File bugs / feature requests in the GitHub issue tracker.
  • Include OS, version, reproduction steps, expected behavior, and screenshots when relevant.
  • For renderer issues, please attach the DevTools console (F12) output.

About

Always-on-top StarCraft: Brood War / Remastered build-order overlay with Liquipedia importer. Tauri 2 + Rust. Windows / macOS / Linux.

Topics

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages