v0.9.2 stops maintaining two parallel UIs. The macOS app now embeds the live web companion (this page) for every data tab — Overview, Characters, Ascensions, Top Relics, Cards, Recent Runs, Co-op, Community Highlights, News. Same backgrounds, same character art, same animations, same hover states, same modals, same share-cards. One UI, one source of truth, no drift.
What changed
Stats tabs are the cloud, rendered inside the app
We replaced the macOS native versions of every data panel with a WKWebView that loads the same page you'd open in Chrome. The native sidebar drives the embedded view via a small window.SpireVault bridge. Click a tab, the web flips. Click an in-page link inside the embedded panel, the native sidebar follows along.
Your runs stay local — and show up instantly
VaultCore still parses your STS2 saves natively. The desktop pipes the parsed runs into the embedded page via the bridge so the web sees your real history (your actual win-rate, your actual best floor) instead of the demo set — without uploading anything you didn't already opt into uploading.
Native pieces stayed native
Beta and Settings stayed in SwiftUI: Run Coach needs an NSPanel with sharingType=.none and a Keychain-backed API key (a browser can't replicate either), and Settings needs NSOpenPanel for save folder linking. The menu bar (About, Check for Updates, Help) is still native. The slim toolbar above each panel still has Rescan / Export / Open Saves Folder.
Community Highlights now actually loads
An old typo had the desktop hitting /api/highlights while the worker exposes /highlights — every desktop user was getting a 404, which is why the highlights tab looked permanently empty. Fixed in v0.9.2. If you posted a highlight, it shows up now.
The newsletter is real
Every news post that promised "weekly digest email" now has a real signup form pinned to a new POST /notify route. Plain-text, off by default, one-click unsubscribe when it ships. We're capturing intent in KV until the mailer is wired — no third party touches your address.
Why webview for the data tabs
The cloud version was getting all the love — character art, the architect, click-to-expand cards, the share-card canvas, the live recent-form chart, the run-detail modal. Reproducing all of that in SwiftUI was an entire parallel codebase that drifted further behind every web deploy. Embedding the canonical UI is what every serious cross-platform app does (Notion, Slack, Linear, Discord, Spotify) — one UI, one set of bugs, one rendering surface to QA. The desktop now ships every cloud feature the moment we deploy the web.
Streamers, no behaviour change
Run Coach is still streamer-safe. The macOS overlay is still NSPanel + sharingType=.none and stays invisible to OBS / Zoom / QuickTime. Nothing about the embedded WebView changes that — the WebView is for stats, not the overlay.
What's next
- Steam OpenID bridge — a single sign-in that covers both halves. Right now the desktop's native Steam session and the embedded page's session are independent; we want one click to seat both.
- Offline-aware fallback. If the cloud is unreachable, the desktop falls back to a slim native overview rendered from VaultCore. You should always be able to see your stats, even on a plane.
- Native context menu inside the embedded page — Copy run link, Open in browser, Inspect.
-
Wire the digest mailer once we have a meaningful signup list. There's a real
/notifyendpoint capturing emails today.
If anything in the embedded view feels off — slow, jittery, missing — file an issue and screenshot it. The webview path is new and the corner cases haven't all been swept.
— Corey
