Offline-first Rust desktop converter with global hotkeys, cursor-anchored egui UI, and redb-cached fiat/crypto rates.
Quick Facts
- Role: Rust Systems / Desktop Tooling
- Project Type: Personal Productivity / System Utility
- Tech Stack: Rust 2024, egui/eframe, tokio, redb
- Platform: Windows (native; hotkeys, clipboard, tray)
Overview
I developed Clippy Converter—a lightweight background unit and currency converter that turns highlighted text into instant conversions. A global hotkey captures the selection, parses value and unit, and opens a borderless floating UI at the mouse cursor so you never leave your current workflow.
Built for zero-friction conversions without opening a browser or pasting into a search bar.
The Problem
Converting units or currencies mid-work usually means: select text → copy → open a browser → type a query → wait for a page. That flow breaks focus, depends on network latency for every lookup, and often overwrites whatever was already on the clipboard.
The Solution
I built a single-instance Rust desktop daemon that lives in the system tray. On hotkey, it simulates a copy, restores the previous clipboard contents, parses the captured string, and renders conversion results in an always-on-top egui overlay at the cursor. Fiat and crypto rates refresh in background tokio workers and land in a local redb cache, so conversions stay offline-first after the first successful sync.
Key Features
- Global hotkey capture: Configurable system-wide shortcut (default
Shift+Alt+C) triggers selection capture via simulatedCtrl+C/Cmd+Cwithout permanently clobbering the clipboard. - Cursor-anchored floating UI: Borderless, always-on-top egui window positioned at mouse coordinates for immediate read/filter/favorite actions.
- Smart parsing: Splits captured strings into numeric values and unit/currency tokens (including leading symbols like
$and scientific notation). - Offline-first conversions: Static physical units (length, weight, temperature, time) plus dynamic rates stored in embedded
redb; no network round-trip at conversion time. - Background rate workers: Fiat rates from Fawaz Ahmed’s currency API (default daily) and crypto tickers from Binance USDT pairs (default hourly), normalized toward EUR.
- Favorites, history & tray: Pin preferred units, reopen recent conversions with retention, and control the app from a system tray menu—with a single-instance lock to protect the database.
Tech Stack
| Category | Technologies Used |
|---|---|
| Language | Rust (Edition 2024) |
| GUI | egui / eframe 0.34, egui_extras |
| Async Runtime | tokio |
| Storage | redb, bincode, directories |
| System Integration | global-hotkey, arboard, enigo, tray-icon, single-instance |
| Networking | reqwest, serde / serde_json, chrono |
Project Architecture
Modular Rust crate with clear ownership boundaries:
clipboard.rs— selection capture via Enigo + Arboard with marker-based readiness and clipboard restoreparser.rs/converter.rs— input splitting and conversion engine (aliases, metric prefixes, currency multipliers)db.rs— thread-saferedbwrapper for units, rates, and aliasesworkers.rs/api.rs— periodic fiat/crypto refresh into the local cacheui.rs/theme.rs— egui state machine, floating overlay, tray menuhistory.rs/hotkey.rs/models.rs— retention logging, hotkey parsing, JSON config
“Why?”: Overcoming Technical Challenges
Challenge: Capturing selection without destroying the user’s clipboard
A naive Ctrl+C would overwrite whatever the user had copied. Clipboard updates are also asynchronous at the OS level, so reading too early returns stale data.
Solution:
I implemented a capture pipeline that (1) snapshots the original clipboard text, (2) writes a unique marker, (3) releases held modifiers so the hotkey chord doesn’t leak into the simulated copy, (4) injects Ctrl+C/Cmd+C, (5) polls until the marker is replaced, then (6) restores the original clipboard contents.
Challenge: Instant conversions while keeping rates fresh Currency and crypto prices change continuously, but blocking the UI on HTTP would defeat the “instant overlay” goal—and offline use had to keep working.
Solution:
I separated concerns: the conversion path only reads redb. Dedicated tokio workers refresh fiat (daily by default) and Binance crypto (hourly by default), writing normalized EUR-based factors into the same store. Intervals are read from shared config each loop so settings apply without restarting the process.
Results and Impact
- Frictionless workflow: Highlight → hotkey → convert in place, without leaving the active application.
- Offline resilience: Static units and cached rates keep conversions available without network access.
- Lean desktop footprint: Single background process with tray control and a single-instance lock to avoid
redbcontention.
Development Plans
- Broader OS polish beyond the current Windows-first validation path
- Richer unit coverage and improved ambiguous-parse handling
- Optional packaging / installer for easier distribution