Imperator FreeGames
Polls a feed of games that are currently free to keep, notifies you when a new one shows up, and lists them all in a menu bar panel.
README.md
// Overview
A macOS menu bar watcher for game giveaways. It polls a public feed of games that are currently free to keep on Steam, Epic and GOG, notifies you when a new one shows up, and lists them all in a menu bar panel.
// Install
Download the latest zip from
Releases,
unzip, and move Imperator FreeGames.app to /Applications.
The app is signed with a self-signed certificate and is not notarized, so Gatekeeper blocks the first launch. Right-click the app and choose Open, or clear the quarantine flag:
xattr -dr com.apple.quarantine "/Applications/Imperator FreeGames.app"Requires macOS 13 or later, Apple silicon. Built and tested on macOS 27 only — older versions are expected to work but have not been verified.
Building needs Swift 6.4 or later, because Package.swift declares
swift-tools-version:6.4. That is a build requirement only; the app itself
still runs on macOS 13.
Install at your own risk. The app is not notarized and carries no Apple Developer signature, so macOS cannot vouch for it. It is provided as is, with no warranty, under the MIT license.
// Permissions
No Accessibility, Input Monitoring, or Automation grants. The app declares no
NSUsage keys and reads nothing on your machine.
Two system integrations:
| Integration | What it does |
|---|---|
| Notifications | On first launch the app asks for notification permission through UNUserNotificationCenter. Decline it and everything still works — you just lose the alerts and keep the badge dot. |
| Open at Login | The footer toggle calls SMAppService.mainApp.register(), which adds the app to Login Items in System Settings. Turning it off unregisters it. |
Network access is one outbound HTTPS request every 30 minutes to
https://www.goranimperator.com/data/free-games.json. Nothing is sent — no
identifiers, no telemetry, no account. Clicking a game opens its store page in
your default browser.
// Use
Click the menu bar icon to open the panel. Games are grouped by platform with a count per section; each row shows the title, the regular price it was before the giveaway, release year, developer and a short description. Click a row to open the store page.
A red dot on the menu bar icon means something new arrived since you last looked. Opening the panel clears it, and the new titles keep a red NEW pill until then.
The panel is drawn by the app, in MenuBarPanel.swift, rather than by
NSPopover, whose radius cannot be set and never matches the one macOS 27
draws in the menu bar. It carries the system's .popover material with a
17.5pt corner, the same surface every Imperator menu bar app draws, with no
arrow and no open or close animation.
The footer holds the controls:
| Control | What it does |
|---|---|
| Open at Login | Register or unregister the login item |
| Website | Open the full free-games page in a browser |
| About | Version, build and copyright panel |
| Quit | Terminate the app |
The refresh arrow in the header forces a fetch instead of waiting for the next 30-minute tick.
State lives in
~/Library/Application Support/Imperator FreeGames/state.json: the IDs already
seen, capped at the 50 most recent per platform. The first fetch after a fresh
install seeds that list silently, so installing the app does not fire a
notification for every game already on offer.
// Build from source
make installBuilds release, bundles, codesigns, installs to /Applications, and launches.
Other targets:
make runmake cleanSigning uses the self-signed Imperator Dev identity by default. Override it:
make build CODESIGN_IDENTITY=-Ad-hoc signing (-) mints a new code hash on every build, which drops the
login-item registration on update. Fine for local iteration, wrong for a
release.
AppKit decides which generation of a control to draw from the SDK field in the
binary's LC_BUILD_VERSION, not from the macOS it runs on, and SwiftPM fills
that field from platforms: rather than from the SDK it compiled against. The
Makefile stamps sdk 27.0 through a linker flag instead of raising
platforms:, so the app draws current controls without locking out anything
below macOS 13.
// Release
Build a zip without touching git or the remote:
make dist VERSION=1.0.0Cut a full release — bumps Info.plist, commits, tags v1.0.0, pushes, and
publishes a GitHub release with the zip attached:
make release VERSION=1.0.0Requires the GitHub CLI (brew install gh, then
gh auth login). The working tree must be clean. Tags are plain semver
(v1.0.0); the release title carries the app name. CFBundleVersion is set
from git rev-list --count HEAD and is never edited by hand.
// Implementation note
A SwiftPM executable with no dependencies. LSUIElement is true, so there is no
Dock icon and no menu — the status item is the entire interface. Because SwiftPM
does not compile asset catalogs, the panel and menu bar icons are inline SVG
strings decoded through NSImage(data:) with isTemplate = true, so they
follow the system appearance.