MCPcopy Create free account
hub / github.com/VirtCode/hypr-dynamic-cursors

github.com/VirtCode/hypr-dynamic-cursors @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
147 symbols 251 edges 40 files 24 documented · 16% updated 10d ago★ 66618 open issues

Browse by type

Functions 122 Types & classes 25
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

hypr-dynamic-cursors

This plugin makes your cursor more realistic by simulating how it would behave if it was an actual object being dragged across your screen. This means that your cursor can change based on how it is used, e.g. tilt in the direction you are moving or straight out rotate towards it.

Why did I implement this again?

Inspired by KDE, it also supports shake to find, to enlarge the cursor when it is shaken, so it is easier to find it. It can be enabled separately or together with one simulation mode.

simulation modes

rotate

In this mode, the cursor is simulated as a stick which is dragged across the screen on one end. This means it will rotate towards the movement direction, and feels really realistic.

https://github.com/VirtCode/hypr-dynamic-cursor/assets/41426325/ccd6d742-8e2b-4073-a35e-318c7e19705c

tilt

In this mode, the cursor is tilted based on the x direction and speed it is moving at. It was intended to simulate how an object would be affected by air drag, but implemented is only a rough approximation. This mode can also be customized extensively with different activation functions, and is enabled by default.

https://github.com/VirtCode/hypr-dynamic-cursors/assets/41426325/ae25415c-e77f-4c85-864c-2eedbfe432e3

stretch

This mode tries recreating the stretching and squishing that is done to moving object in comic animations. It stretches your cursor in the direction you are moving based on the speed. Yes, this is not at all realistic.

https://github.com/VirtCode/hypr-dynamic-cursors/assets/41426325/7b8289e7-9dd2-4b57-b406-4fa28779a260

shake to find

The plugin supports shake to find, akin to how KDE Plasma, MacOS, etc. do it. It can also be extensively configured and is enabled by default. It also supports using hyprcursor for high resolution cursor images. The magnification can also be triggered as a dispatcher instead of on shake. If you only want shake to find, and no weird cursor behaviour, you can disable the above modes with the mode none.

https://github.com/user-attachments/assets/1346101e-4e62-4ba2-a1df-5940e0706514

state

This plugin is still very early in its development. There are also multiple things which may or may not be implemented in the future:

  • [X] software cursor rendering
  • [X] hardware cursor rendering
  • [X] stick simulation
  • [X] air drag simulation
  • [ ] pendulum simulation
  • [X] per-shape length and starting angle (if possible)
  • [X] cursor shake to find
  • [X] overdue refactoring (wait for aquamarine merge)
  • [X] hyprcursor magnified shape

If anything here sounds interesting to you, don't hesitate to contribute.

Please note that this plugin was created more or less as a joke. I mainly wanted to see how using a rotating or tilted cursor was like. So I will not guarantee any future updates and bugfixes. The only useful feature, shake to find, was implemented more or less as an afterthought.

installation

Note that this plugin is only supported on x86_64 architectures, see compatibility for more info. If you don't know what this means, you're probably fine.

Installation is officially supported via hyprpm. Supported Hyprland versions are v0.41.2 and upwards and the latest commit on this main branch generally tries to target Hyprland's main branch (aka -git).

To install the plugin run the following. For more info and how to keep loading the plugin on startup, refer to hyprpm's section in the wiki.

hyprpm add https://github.com/virtcode/hypr-dynamic-cursors
hyprpm enable dynamic-cursors

distribution specific

Some Linux distributions have a package manager sophisticated enough to properly package and manage hyprland plugins with. While hyprpm is distribution agnostic, these mechanisms usually offer a better and more stable user experience. Below are some distributions which have packages for dynamic-cursors and how to install them.

NixOS

This plugin has special support for NixOS by either using the flake in this repo or a version from nixpkgs. Depending on how you manage your system, you can choose from either of them.

Nixpkgs

There is a Nix package in nixpkgs for this plugin. If you are using a release version of hyprland, it is recommended to use this version. Note however that this package is maintained by other people and might not be up-to-date.

To install the plugin from nixpkgs, add it to your Hyprland plugins list in your home-manager config:

wayland.windowManager.hyprland = {
    enable = true;
    plugins = [ pkgs.hyprlandPlugins.hypr-dynamic-cursors ];
};
With Flakes

If you daily-drive the development version of hyprland, it is recommended to use the flake included with this plugin. Note that using a mismatched/unsupported Hyprland release will fail to build or load the plugin if you update.

Add the following flake to your inputs:

inputs = {
    hyprland.url = "github:hyprwm/Hyprland"; # follows development branch of hyprland
    hypr-dynamic-cursors = {
        url = "github:VirtCode/hypr-dynamic-cursors";
        inputs.hyprland.follows = "hyprland"; # to make sure that the plugin is built for the correct version of hyprland
    };
};

Then, in your home-manager config, add the plugin:

wayland.windowManager.hyprland = {
    enable = true;
    plugins = [ inputs.hypr-dynamic-cursors.packages.${pkgs.system}.hypr-dynamic-cursors ];
};

Gentoo

The plugin is packaged for Gentoo in the Hyproverlay portage overlay containing the entire Hypr-* ecosystem, and as such, also Hyprland itself.

To install Hyprland itself, Hyproverlay should already be enabled but if it isn't, it can be enabled as follows:

eselect repository enable hyproverlay
emerge --sync hyproverlay

By nature of how the Hyprland plugin ecosystem works, Hyprland plugins are usually packaged as -9999 live ebuilds. As such, unmasking them with ** is required. This can be done by adding the following to a /etc/portage/package.accept_keywords list:

hyprland-plugin/dynamic-cursors **

From there, dynamic-cursors can be installed as

emerge --ask hyprland-plugin/dynamic-cursors

This installs the plugin to /usr/lib/hyprland-plugins/dynamic-cursors.so, from where it can be loaded by Hyprland by adding the following to your hyprland.lua config:

hl.plugin.load("/usr/lib/hyprland-plugins/dynamic-cursors.so")

Note: This does not need Hyprland to be compiled with the hyprpm USE flag, as that USE flag only controls the inclusion of the plugin manager, and not the plugin mechanism itself. As such, no hyprpm update is required to update plugins after a Hyprland update.

Portage should rebuild plugins automatically whenever it updates Hyprland, but this may fail for certain edgecases. In this case a rebuild must be triggered manually as: bash emerge --ask --oneshot hyprland-plugin/dynamic-cursors

If you think your distro has good packages for dynamic-cursors but it is not listed here, MRs are welcome!

configuration

Still using hyprlang configuration? Don't worry, this plugin currently supports configuration via both hyprlang and lua. Click here to expand the section about configuring with hyprlang.


variables (hyprlang)

This plugin can be configured in its dedicated configuration section (plugin:dynamic-cursors). The default values are shown below.

plugin:dynamic-cursors {

    # enables the plugin
    enabled = true

    # sets the cursor behaviour, supports these values:
    # tilt    - tilt the cursor based on x-velocity
    # rotate  - rotate the cursor based on movement direction
    # stretch - stretch the cursor shape based on direction and velocity
    # none    - do not change the cursor's behaviour
    mode = tilt

    # minimum angle difference in degrees after which the shape is changed
    # smaller values are smoother, but more expensive for hw cursors
    threshold = 2

    # override the mode behaviour per shape
    # this is a keyword and can be repeated many times
    # by default, there are no rules added
    # see the dedicated `shape rules` section below!
    shaperule = <shape-name>, <mode> (optional), <property>: <value>, ...
    shaperule = <shape-name>, <mode> (optional), <property>: <value>, ...
    ...

    # for mode = rotate
    rotate {

        # length in px of the simulated stick used to rotate the cursor
        # most realistic if this is your actual cursor size
        length = 20

        # clockwise offset applied to the angle in degrees
        # this will apply to ALL shapes
        offset = 0.0
    }

    # for mode = tilt
    tilt {

        # controls how powerful the tilt is, the lower, the more power
        # this value controls at which speed (px/s) the full tilt is reached
        limit = 5000

        # relationship between speed and tilt, supports these values:
        # linear             - a linear function is used
        # quadratic          - a quadratic function is used (most realistic to actual air drag)
        # negative_quadratic - negative version of the quadratic one, feels more aggressive
        # see `activation` in `src/mode/utils.cpp` for how exactly the calculation is done
        activation = negative_quadratic

        # time window (ms) over which the speed is calculated
        # higher values will make slow motions smoother but more delayed
        window = 100

        # full tilt for each side (°)
        full = 60
    }

    # for mode = stretch
    stretch {

        # controls how much the cursor is stretched
        # this value controls at which speed (px/s) the full stretch is reached
        # the full stretch being twice the original length
        limit = 3000

        # relationship between speed and stretch amount, supports these values:
        # linear             - a linear function is used
        # quadratic          - a quadratic function is used
        # negative_quadratic - negative version of the quadratic one, feels more aggressive
        # see `activation` in `src/mode/utils.cpp` for how exactly the calculation is done
        activation = quadratic

        # time window (ms) over which the speed is calculated
        # higher values will make slow motions smoother but more delayed
        window = 100
    }

    # configure shake to find
    # magnifies the cursor if its is being shaken
    shake {

        # enables shake to find
        enabled = true

        # controls how soon a shake is detected
        # lower values mean sooner
        threshold = 6.0

        # magnification level immediately after shake start
        base = 4.0
        # magnification increase per second when continuing to shake
        speed = 4.0
        # how much the speed is influenced by the current shake intensity
        influence = 0.0

        # maximal magnification the cursor can reach
        # values below 1 disable the limit (e.g. 0)
        limit = 0.0

        # time in milliseconds the cursor will stay magnified after a shake has ended
        timeout = 2000

        # show cursor behaviour `tilt`, `rotate`, etc. while shaking
        effects = false

        # enable ipc events for shake
        # see the `ipc` section below
        ipc = false
    }

    # use hyprcursor to get a higher resolution texture when the cursor is magnified
    # see the `hyprcursor` section below
    hyprcursor {

        # use nearest-neighbour (pixelated) scaling when magnifying beyond texture size
        # this will also have effect without hyprcursor support being enabled
        # 0 / false - never use pixelated scaling
        # 1 / true  - use pixelated when no highres image
        # 2         - always use pixelated scaling
        nearest = true

        # enable dedicated hyprcursor support
        enabled = true

        # resolution in pixels to load the magnified shapes at
        # be warned that loading a very high-resolution image will take a long time and might impact memory consumption
        # -1 means we use [normal cursor size] * [shake:base option]
        resolution = -1

        # shape to use when clientside cursors are being magnified
        # see the shape-name property of shape rules for possible names
        # specifying clientside will use the actual shape, but will be pixelated
        fallback = clientside
    }
}

shape rules (hyprlang)

Shape Rules can be used to override the mode or its behaviour on a per-shape basis. They can be defined with the keyword shaperule in the config file, preferably in the plugin:dynamic-cursors section.

Note: Shape rules only apply to server side cursor shapes. Sadly, not everyone supports server side cursors yet, which means shape rules won't work in some applications.

A shape rule usually consists of three parts:

shaperule = shape-name, mode (optional), property: value, property: value, ...
  • shape-name: This is the name of the shape, this rule will apply to. Should be one of those specified in the protocol. You can use the special shape clientside to apply your rule to ALL client side cursors. Also note that

Core symbols most depended-on inside this repo

Shape

Method 99
Function 23
Class 21
Enum 4

Languages

C++100%

Modules by API surface

src/cursor.cpp16 symbols
src/main.cpp15 symbols
src/config/ShapeRule.cpp8 symbols
src/render/CursorPassElement.cpp7 symbols
src/highres.cpp7 symbols
src/config/ConfigManager.cpp7 symbols
src/render/CursorPassElement.hpp5 symbols
src/config/cache/VariantValue.cpp5 symbols
src/other/Shake.cpp4 symbols
src/mode/ModeTilt.cpp4 symbols
src/mode/ModeStretch.cpp4 symbols
src/mode/ModeRotate.cpp4 symbols

For agents

$ claude mcp add hypr-dynamic-cursors \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page