Smooth motion animations for Neovim. Provides 60fps fluid animations for cursor movement, word navigation, text objects, and viewport scrolling — all in one plugin.
Motion coverage — animates every standard Vim motion:
| Category | Motions |
|---|---|
| Basic | h, j, k, l, 0, $ |
| Word | w, b, e, W, B, E |
| Find/Till | f, F, t, T |
| Text Objects | {, }, (, ), % |
| Line Jumps | gg, G, | |
| Search | n, N |
| Screen Lines | gj, gk |
| Viewport | <C-d>, <C-u>, <C-f>, <C-b>, zz, zt, zb |
zz/zt/zb are Normal mode only)The plugin auto-calls require("whisk").setup() on load. To disable this and call setup manually, set g:whisk_auto_setup = 0 before the plugin loads.
{
"josstei/whisk.nvim",
event = "VeryLazy",
opts = {},
}
Plug 'josstei/whisk.nvim'
require("whisk").setup()
All options with their defaults:
require("whisk").setup({
cursor = {
duration = 150,
easing = "ease-out",
enabled = true,
},
scroll = {
duration = 200,
easing = "ease-in-out",
enabled = true,
},
keymaps = {
cursor = true,
scroll = true,
},
performance = {
enabled = false,
disable_syntax_during_scroll = true,
ignore_events = { "WinScrolled", "CursorMoved", "CursorMovedI" },
reduce_frame_rate = false,
frame_rate_threshold = 60, -- not currently read by any code path
auto_enable_on_large_files = true,
large_file_threshold = 5000,
},
})
Easing options: linear, ease-in, ease-out, ease-in-out
| Command | Description |
|---|---|
:WhiskEnable |
Enable all animations |
:WhiskDisable |
Disable all animations |
:WhiskToggle |
Toggle all animations |
:WhiskEnableCursor |
Enable cursor animations |
:WhiskDisableCursor |
Disable cursor animations |
:WhiskEnableScroll |
Enable scroll animations |
:WhiskDisableScroll |
Disable scroll animations |
:WhiskPerformanceEnable |
Enable performance mode |
:WhiskPerformanceDisable |
Disable performance mode |
:WhiskPerformanceToggle |
Toggle performance mode |
local whisk = require("whisk")
whisk.enable()
whisk.disable()
whisk.toggle()
whisk.enable_cursor()
whisk.disable_cursor()
whisk.enable_scroll()
whisk.disable_scroll()
whisk.toggle_performance()
whisk.reset() -- tear down keymaps, stop animations, clear registries, remove lifecycle autocmds
local performance = require("whisk.performance")
performance.enable()
performance.disable()
performance.is_active()
performance.get_current_fps()
performance.get_frame_interval()
performance.should_ignore_event(event)
For custom keymaps, use the orchestrator directly:
local orchestrator = require("whisk.engine.orchestrator")
orchestrator.execute("basic_j", { count = 5, direction = "j" })
orchestrator.execute("word_w", { count = 3, direction = "w" })
orchestrator.execute("find_f", { char = "x", count = 1, direction = "f" })
| Category | IDs |
|---|---|
| Basic | basic_h, basic_j, basic_k, basic_l, basic_0, basic_$ |
| Word | word_w, word_b, word_e, word_W, word_B, word_E |
| Find | find_f, find_F, find_t, find_T |
| Text Object | text_object_{, text_object_}, text_object_(, text_object_), text_object_% |
| Line | line_gg, line_G, line_| |
| Search | search_n, search_N |
| Screen | screen_gj, screen_gk |
| Scroll | scroll_ctrl_d, scroll_ctrl_u, scroll_ctrl_f, scroll_ctrl_b, position_zz, position_zt, position_zb |
require("whisk").setup({
keymaps = { cursor = false, scroll = false },
})
local orchestrator = require("whisk.engine.orchestrator")
vim.keymap.set("n", "j", function()
orchestrator.execute("basic_j", { count = vim.v.count1, direction = "j" })
end)
require("whisk").setup({
cursor = { duration = 100, easing = "linear" },
scroll = { duration = 400, easing = "ease-out" },
})
require("whisk").setup({
cursor = { duration = 100, easing = "linear" },
scroll = { duration = 150, easing = "linear" },
performance = { enabled = true },
})
When enabled, performance mode:
disable_syntax_during_scroll is set (default: on)reduce_frame_rate = true)BufEnter/BufWinEnter for files larger than large_file_threshold lines (default: 5000)ignore_events list (default: WinScrolled, CursorMoved, CursorMovedI) for callers to check via should_ignore_event()Toggle at runtime with :WhiskPerformanceToggle or require("whisk").toggle_performance().
normal! motion behavior.BufDelete), the window is closed (WinClosed), or the buffer is left (BufLeave).gg with a count (e.g., 5gg) goes to line N. | with a count (e.g., 5|) goes to column N.| Feature | whisk.nvim | neoscroll.nvim | vim-smoothie |
|---|---|---|---|
| Cursor movement | Yes | No | No |
| Scroll movement | Yes | Yes | Yes |
| Word navigation | Yes | No | No |
| Find/Till | Yes | No | No |
| Text objects | Yes | No | No |
| Search navigation | Yes | No | No |
| Visual mode | Yes | Scroll only | Scroll only |
| Count prefixes | Yes | Scroll only | Scroll only |
whisk.nvim was previously published as nvim-luxmotion. A deprecation shim is included:
require("luxmotion") forwards to require("whisk") with a warning.:LuxMotion* commands forward to their :Whisk* equivalents.g:luxmotion_auto_setup forwards to g:whisk_auto_setup.Update your config to use whisk directly — the shim will be removed in a future release.
MIT — see LICENSE.