GitHub - michalsustr/egui-cursor

2 min read Original article ↗

egui-cursor is a small crate + demo app for drawing themed cursors inside an eframe/egui app, so app visuals and cursor position stay in sync.

Inspired by https://x.com/rsms/status/2067139891264409851 and https://tonsky.me/blog/every-frame-perfect/

Why

On some systems, the OS cursor and app content can appear slightly out of sync in high-speed motion. This crate paints the cursor in egui itself, so cursor and scene are composited on the same path.

Drawbacks. Because the cursor is rendered by your app, you need to keep app render time low. If frame time spikes, cursor responsiveness will also degrade.

Video downsampled to 1 FPS. Original
Demo

Assets

Important: this crate does not bundle cursor assets by default. The non-system theme features are optional and intended for setups that provide/generated assets themselves. This is also why this crate is not published on crates.io yet. If you know how to do this well, please let me know in the issues.

Contributions welcome

Contributions are welcome, especially for:

  • adding new cursor themes,
  • improving cursor resolution/quality across themes,
  • support for animated cursors.

Themes

Currently supported:

  • System (use OS cursor, no custom painting)
  • Aosp (generated from AOSP vectors, supersampled)
  • OpenZone* variants:
    • OpenZoneBlack
    • OpenZoneBlackSlim
    • OpenZoneWhite
    • OpenZoneWhiteSlim
    • OpenZoneIce
    • OpenZoneIceSlim
    • OpenZoneFire
    • OpenZoneFireSlim

Cargo Features

From Cargo.toml:

  • cursor-theme-aosp
  • cursor-theme-openzone
  • cursor-theme-all (enables both above)

Default features enable no custom themes.

Using in your app

Minimal integration pattern:

  1. Call set_cursor_theme_with_scale(...) when theme/scale changes.
  2. Keep your normal egui cursor icon logic (ctx.set_cursor_icon(...)).
  3. Call paint_cursor(ctx) at the very end of eframe::App::update.

The demo in examples/demo.rs shows this pattern.

Asset Download / Generation

Assets are generated by scripts in download_scripts:

  • download_scripts/download_openzone.py
  • download_scripts/download_aosp.py
  • download_all_assets.sh (runs both)

Run:

bash ./download_all_assets.sh

Script system dependencies

  • git
  • xcursorgen
  • convert (ImageMagick)
  • python3

Development

Native

cargo run --bin demo --features cursor-theme-all --release

Web (WASM)

trunk serve --port 8000 --release --features cursor-theme-all