A tiny Neovim plugin that adds subtle animations to various operations.
Do not forget to enable animations on operations you want to animate ! A lot of operations are disabled by default.
[!WARNING] This plugin is still in beta. It is possible that some changes will break the plugin.
https://github.com/user-attachments/assets/1bb98834-25d2-4f01-882f-609bec1cbe5c
https://github.com/user-attachments/assets/1578d19f-f245-4593-a28f-b7e9593cbc68
https://github.com/user-attachments/assets/6bc98a8f-8b7e-4b57-958a-74ad5372612f
Built-in animation styles:
fade
: Smooth fade in/out transitionreverse_fade
: Reverse fade effect with outBack easingbounce
: Bouncing highlight effectleft_to_right
: Linear left-to-right sweeppulse
: Pulsating highlightrainbow
: Rainbow color transitioncustom
: Define your own animation logicUsing lazy.nvim:
{
"rachartier/tiny-glimmer.nvim",
event = "VeryLazy",
opts = {
-- your configuration
},
}
Using packer.nvim:
use {
'rachartier/tiny-glimmer.nvim',
config = function()
require('tiny-glimmer').setup()
end
}
Here's the default configuration:
require('tiny-glimmer').setup({
enabled = true,
-- Disable this if you wants to debug highlighting issues
disable_warnings = true,
refresh_interval_ms = 8,
overwrite = {
-- Automatically map keys to overwrite operations
-- If set to false, you will need to call the API functions to trigger the animations
-- WARN: You should disable this if you have already mapped these keys
-- or if you want to use the API functions to trigger the animations
auto_map = true,
-- For search and paste, you can easily modify the animation to suit your needs
-- For example you can set a table to default_animation with custom parameters:
-- default_animation = {
-- name = "fade",
--
-- settings = {
-- max_duration = 1000,
-- min_duration = 1000,
--
-- from_color = "DiffDelete",
-- to_color = "Normal",
-- },
-- },
-- settings needs to respect the animation you choose settings
--
-- All "mapping" can be set in 2 ways:
-- 1. A string with the key you want to map
-- Example:
-- paste_mapping = "p"
-- 2. A table with the key you want to map and its actions
-- Example:
-- paste_mapping = {
-- lhs = "p"
-- rhs = "<Plug>(YankyPutAfter)"
-- }
yank = {
enabled = true,
default_animation = "fade",
},
search = {
enabled = false,
default_animation = "pulse",
-- Keys to navigate to the next match
next_mapping = "nzzzv",
-- Keys to navigate to the previous match
prev_mapping = "Nzzzv",
},
paste = {
enabled = true,
default_animation = "reverse_fade",
-- Keys to paste
paste_mapping = "p",
-- Keys to paste above the cursor
Paste_mapping = "P",
},
undo = {
enabled = false,
default_animation = {
name = "fade",
settings = {
from_color = "DiffDelete",
max_duration = 500,
min_duration = 500,
},
},
undo_mapping = "u",
},
redo = {
enabled = false,
default_animation = {
name = "fade",
settings = {
from_color = "DiffAdd",
max_duration = 500,
min_duration = 500,
},
},
redo_mapping = "<c-r>",
},
},
support = {
-- Enable support for gbprod/substitute.nvim
-- You can use it like so:
-- require("substitute").setup({
-- on_substitute = require("tiny-glimmer.support.substitute").substitute_cb,
-- highlight_substituted_text = {
-- enabled = false,
-- },
--})
substitute = {
enabled = false,
-- Can also be a table. Refer to overwrite.search for more information
default_animation = "fade",
},
},
-- Animations for other operations
presets = {
-- Enable animation on cursorline when an event in `on_events` is triggered
-- Similar to `pulsar.el`
pulsar = {
enabled = false,
on_events = { "CursorMoved", "CmdlineEnter", "WinEnter" },
default_animation = {
name = "fade",
settings = {
max_duration = 1000,
min_duration = 1000,
from_color = "DiffDelete",
to_color = "Normal",
},
},
},
},
-- Only use if you have a transparent background
-- It will override the highlight group background color for `to_color` in all animations
transparency_color = nil,
-- Animation configurations
animations = {
fade = {
max_duration = 400,
min_duration = 300,
easing = "outQuad",
chars_for_max_duration = 10,
from_color = "Visual", -- Highlight group or hex color
to_color = "Normal", -- Same as above
},
reverse_fade = {
max_duration = 380,
min_duration = 300,
easing = "outBack",
chars_for_max_duration = 10,
from_color = "Visual",
to_color = "Normal",
},
bounce = {
max_duration = 500,
min_duration = 400,
chars_for_max_duration = 20,
oscillation_count = 1,
from_color = "Visual",
to_color = "Normal",
},
left_to_right = {
max_duration = 350,
min_duration = 350,
min_progress = 0.85,
chars_for_max_duration = 25,
lingering_time = 50,
from_color = "Visual",
to_color = "Normal",
},
pulse = {
max_duration = 600,
min_duration = 400,
chars_for_max_duration = 15,
pulse_count = 2,
intensity = 1.2,
from_color = "Visual",
to_color = "Normal",
},
rainbow = {
max_duration = 600,
min_duration = 350,
chars_for_max_duration = 20,
},
-- You can add as many animations as you want
custom = {
-- You can also add as many custom options as you want
-- Only `max_duration` and `chars_for_max_duration` is required
max_duration = 350,
chars_for_max_duration = 40,
color = hl_visual_bg,
-- Custom effect function
-- @param self table The effect object
-- @param progress number The progress of the animation [0, 1]
--
-- Should return a color and a progress value
-- that represents how much of the animation should be drawn
-- self.settings represents the settings of the animation that you defined above
effect = function(self, progress)
return self.settings.color, progress
end,
},
hijack_ft_disabled = {
"alpha",
"snacks_dashboard",
},
},
virt_text = {
priority = 2048,
},
})
For each animation, you can configure the from_color
and to_color
options to customize the colors used in the animation. These options should be valid highlight group names, or hexadecimal colors.
Example:
require('tiny-glimmer').setup({
animations = {
fade = {
from_color = "DiffDelete",
to_color = "DiffAdd",
},
bounce = {
from_color = "#ff0000",
to_color = "#00ff00",
},
},
})
[!WARNING] Only
rainbow
animation does not usesfrom_color
andto_color
options.
You can use the following easing functions in fade
and reverse_fade
:
Each animation type has its own configuration options:
max_duration
: Maximum duration of the animation in millisecondschars_for_max_duration
: Number of characters that will result in max durationlingering_time
: How long the animation stays visible after completion (for applicable animations)oscillation_count
: Number of bounces (for bounce animation)pulse_count
: Number of pulses (for pulse animation)intensity
: Animation intensity multiplier (for pulse animation):TinyGlimmer enable
- Enable animations:TinyGlimmer disable
- Disable animations:TinyGlimmer <animation>
- Switch animation stylerequire('tiny-glimmer').enable() -- Enable animations
require('tiny-glimmer').disable() -- Disable animations
require('tiny-glimmer').toggle() -- Toggle animations
--- Change highlight
--- @param animation_name string|string[] The animation name. Can be a string or a table of strings.
--- If a table is passed, each animation will have their highlight changed.
--- If a string is passed, only the provided animation have their highlight changed.
--- You can pass 'all' to change all animations.
--- @param hl table The highlight configuration
-- Examples:
-- require('tiny-glimmer').change_hl('fade', { from_color = '#FF0000', to_color = '#0000FF' })
-- require('tiny-glimmer').change_hl('all', { from_color = '#FF0000', to_color = '#0000FF' })
-- require('tiny-glimmer').change_hl({'fade', 'pulse'}, { from_color = '#FF0000', to_color = '#0000FF' })
require('tiny-glimmer').change_hl(animation_name, hl)
-- When overwrite.search.enabled is true
require('tiny-glimmer').search_next() -- Same as `n`
require('tiny-glimmer').search_prev() -- Same as `N`
require('tiny-glimmer').search_under_cursor() -- Same as `*`
-- When overwrite.paste.enabled is true
require('tiny-glimmer').paste() -- Same as `p`
require('tiny-glimmer').Paste() -- Same as `P`
-- Undo operations (requires undo.enabled = true)
require('tiny-glimmer').undo() -- Undo changes
require('tiny-glimmer').redo() -- Redo changes
You should disable your own TextYankPost
autocmd that calls vim.highlight.on_yank
Set the transparency_color
option to your desired background color.
MIT