A tiny, beautiful ambient animation plugin for Neovim: soft twinkling stars drift and shimmer in the empty space around your code, and shooting stars occasionally streak down the window leaving a fading trail.
Stars never sit on top of your text. Every spawn/movement is checked against the actual buffer content for each visible line — stars only appear in indentation whitespace, blank lines, or the empty margin past the end of a line, with a configurable safety margin. As you type, resize, or scroll, placement is re-checked live.
- 🌌 Ambient twinkling stars that fade in/out through a glyph + color ramp
- 🌧️ Gentle vertical falling stars with a fading comet trail
- 🌟 Rare golden shooting stars that streak diagonally across the whole window, fast, with their own fading gold tail
- 🪟 Works across every normal split/window in the current tab at once
- 🚫 Automatically skips pickers, trees, dashboards, help, etc.
- ⚡ Pure
vim.uv/vim.looptimer + extmarks — no external dependencies - 🧩 Two simple commands:
:StarfallStart/:StarfallStop(plus:StarfallToggle)
nvim-starfall.mp4
- Neovim >= 0.9 (uses
nvim_buf_set_extmarkwithvirt_text_win_col)
{
"RedEye-Developers/starfall.nvim",
cmd = { "StarfallStart", "StarfallStop", "StarfallToggle" },
opts = {
-- see "Configuration" below; {} for all defaults
},
}Because the plugin is registered with cmd = {...}, lazy.nvim will lazy-load
it automatically the first time you run one of the commands — nothing is
loaded at startup.
If you'd rather call setup() yourself:
{
"RedEye-Developers/starfall.nvim",
cmd = { "StarfallStart", "StarfallStop", "StarfallToggle" },
config = function()
require("starfall").setup({
density = 20,
falling_stars = 3,
})
end,
}| Command | Effect |
|---|---|
:StarfallStart |
Start the animation in all eligible windows |
:StarfallStop |
Stop the animation and clear every star instantly |
:StarfallToggle |
Convenience: start if stopped, stop if running |
Map them if you like:
vim.keymap.set("n", "<leader>ss", "<cmd>StarfallToggle<CR>", { desc = "Toggle starfall" })All fields are optional; pass only what you want to override to setup() /
opts.
require("starfall").setup({
density = 16, -- ambient stars alive per window at once
falling_stars = 2, -- gentle vertical falling stars alive per window at once
fps = 10, -- animation ticks per second
twinkle_chars = { "·", "‧", "✦", "✧", "✩", "★", "✩", "✧", "✦", "‧", "·" },
colors = { "#eaeaea", "#ffe9a8", "#a8d4ff", "#ffc9de", "#c9ffb0", "#d8c2ff" },
falling_char = "★",
falling_color = "#ffffff",
trail_chars = { "·", "✦" },
fall_speed = 2, -- lower = falls faster (ticks per row moved)
trail_length = 3, -- how many glyphs long the comet trail is
-- Golden diagonal shooting star -- rare, fast, cross-screen streak.
shooting_stars = 1, -- max concurrent per window
shooting_max_per_minute = 3, -- hard cap: at most this many spawns per rolling 60s
shooting_spawn_chance = 0.05, -- per-tick attempt chance, gated by the cap above
shooting_char = "★",
shooting_color = "#ffd700",
shooting_trail_chars = { "·", "✧", "✦" },
shooting_trail_length = 4,
shooting_move_every = 1, -- 1 = moves every tick (fastest)
shooting_speed_col = { 2, 3 }, -- random sideways step per move
min_life = 30, -- ambient star minimum lifetime, in ticks
max_life = 70,
twinkle_spawn_chance = 0.5,
falling_spawn_chance = 0.06,
margin = 2, -- min blank columns kept clear around real text
ignore_filetypes = {
"TelescopePrompt", "TelescopeResults", "NvimTree", "neo-tree",
"lazy", "mason", "help", "dashboard", "alpha", "starter",
"notify", "noice", "trouble", "qf", "fugitive",
},
})This is a separate, rarer effect from the gentle vertical falling stars:
- Enters from the left or right edge near the top of the visible area and streaks diagonally (down + sideways every tick) all the way across the window, exiting off the opposite side, off the bottom, or into the blank canvas below your file.
- Rendered in gold (
shooting_color, default#ffd700) with its own fading gold tail (StarfallShootingHead/StarfallShootingTrail1-3). - Hard-capped at
shooting_max_per_minutespawns per rolling 60 seconds (default3), on top ofshooting_starsmax concurrent (default1). The per-tickshooting_spawn_chancejust adds organic timing jitter within that budget -- it can't push the total above the per-minute cap. - Still respects the same text-avoidance rules -- if its path would cross over a character, the streak ends cleanly rather than jumping around it.
Want it more/less often? Tune shooting_max_per_minute. Want it
faster/slower? Tune shooting_speed_col (bigger range = steeper, faster
diagonal) or shooting_move_every (higher = slower).
- Want a calmer sky? Lower
density/falling_starsand raisemin_life/max_life. - Want a busier, more magical field? Raise
density, lowerfall_speedisn't what you want for speed — instead raisefalling_spawn_chanceand lowerfall_speedfor faster comets. - Colors are just hex strings fed straight into highlight groups
(
StarfallColor1,StarfallColor2, ...), so they'll respecttermguicolors.
For every visible buffer line, the plugin computes:
- The leading-whitespace width (columns 0 → indent) — safe if wider than
margin. - The blank area past the last visible character on that line — safe if it
leaves at least
margincolumns before the window edge. - Fully blank lines are entirely safe.
Stars are only ever placed inside these ranges, recalculated every animation tick, so live edits, scrolling, and resizing are all handled automatically — a star will quietly step aside (or gracefully despawn) rather than ever covering a character of your code.
Neovim can only attach decorations to real buffer lines, so a naive implementation only twinkles across however many lines your file has — a 20-line file gets 20 lines of sky, a 3-line file gets 3. That's not what "twinkle everywhere while coding" means.
To fix this, starfall.nvim renders the blank ~ area below your last line
as one shared virtual canvas (via virt_lines), sized to exactly fill the
rest of the window. Ambient stars are spawned across real lines and that
canvas proportionally, and falling stars fall straight through your code and
keep going into the blank space below it, all the way to the bottom of the
window — so even a one-line file gets a full screen of sky.
MIT