• BETA 1.0.0-beta.6
  • WINDOWS ONLY

vStats Desktop: a read-only match companion for Windows

A Windows app that notices when your match starts and brings up match context for your lobby (ranks, who queued together and a fair-play score) as results arrive.

Role
Designed and built (Rust core, interface, release tooling, backend endpoints)
Type
Own product, Windows app
Status
Beta, 1.0.0-beta.6
Platform
Windows

The problem

vStats users wanted context about their match while it was happening: each player's rank, who had queued together, and a fair-play score. That means reading the game client's local data strictly read-only. The user's account session has to stay out of reach of web code. And the app has to update itself safely, because most people never reinstall an app by hand.

What I built

I built a Tauri 2 app with a Rust core and a React 19 + TypeScript interface. The Rust side owns the account, the connection to the local game client and every server call, and the interface only draws what it is sent. Every 3 seconds a background loop works out whether the player is in the menus, agent select or a live game, then builds the lobby roster. Results arrive from the vStats backend as a stream, one line per player, so one slow lookup never holds up the rest. Sign-in works by email or by Riot Sign-On through a protected deep link, and the session token lives in Windows Credential Manager. The app also has a tray icon, autostart, a "Match found" notification and signed automatic updates.

Highlights

  1. ARCHITECTURE

    A thin interface over a Rust core.

    21 commands connect the interface to the core, and changes in sign-in, lobby and update state are pushed to the interface as events.

  2. DETECTION

    A resilient background loop.

    Rank lookups run in parallel. A failed lookup waits before it is retried, a failed scan backs off, and party numbering stays stable when the roster reorders.

  3. READ-ONLY

    Scoped trust for the local client.

    The connection to the local game client pins Riot's root certificate. Only if that fails with a certificate error does it accept the client's self-signed certificate, and only for that one local port. It never calls anything that changes game state.

  4. STREAMING

    Results that fill in as they arrive.

    The backend answers in NDJSON, and a line buffer in Rust hands each player's row to the interface the moment it is complete.

  5. UPDATES

    Signed updates, end to end.

    The app checks shortly after launch and then every 6 hours. The server compares versions with pre-release tags handled correctly (tested: beta.10 is newer than beta.9) and accepts only releases with an HTTPS installer and a well-formed signature, which the app verifies before installing.

  6. HARDENING

    A locked-down shell.

    A strict content security policy, a navigation guard, an allow-list for external links, a single-instance lock, rustls in place of native TLS, and an optimised release build packaged as a per-user NSIS installer.

How it works

vStats Desktop streaming flowThe Rust core reads the local game client read-only, sends the lobby roster to the vStats backend, receives one result line per player as each lookup finishes, and passes each row to the interface, which fills in. The list below describes each step.Local game client(read-only)Rust corevStats backendInterface1match phase2roster3one line per player…4vStats Desktop streaming flowThe Rust core reads the local game client read-only, sends the lobby roster to the vStats backend, receives one result line per player as each lookup finishes, and passes each row to the interface, which fills in. The list below describes each step.Local gameclientRust corevStatsbackendInterface(read-only)1match phase2roster3…4
  1. The Rust core reads the local game client, read-only, to detect the match phase.
  2. When a match is found, it sends the roster to the vStats backend.
  3. The backend streams back one line per player as each lookup finishes.
  4. The core passes each row to the interface, which fills in the roster.

Stack

  • Tauri 2
  • Rust (tokio, reqwest + rustls, serde, keyring)
  • React 19
  • TypeScript
  • Vite
  • Vitest
  • Node.js/Express endpoints
  • NDJSON streaming
  • NSIS
  • signed updates

By the numbers

  • ~4,000lines of Rust in 21 files
  • 21interface-to-core commands
  • 25 + 18Rust tests + interface tests
  • 6 hupdate check interval

Outcome

In public beta for Windows (1.0.0-beta.6), with signed updates delivered from the vStats server, and backend tests covering the release and lobby flows.

Need something like this? Get a free quote.

Get a free quote

VALORANT and Riot Games are trademarks of Riot Games, Inc. This project is not affiliated with or endorsed by Riot Games.