Project Awesome project awesome

milli.nvim

Animated ASCII splash screens with bundled animations and custom image or GIF support.

Package 212 stars GitHub

milli.nvim

Animated ASCII splash screens for Neovim. Ships with 24 bundled splashes, and lets you drop in your own from any image or GIF. Works with dashboard-nvim, alpha-nvim, snacks.nvim, mini.starter, or raw VimEnter.

demo

Contents

Bundled splashes

aiface
attackontitan
aurora
badge
blackhole
cactus
catwoman
chrome
dancer
dancerramp
finger
fire
flyingcat
flyingdragon
ididnot
lighningtornado
lights
retrocircle
robot
shader
shadertwo
skeleton
skullone
skullthree
skulltwo
spaceship
spinner
vibecat
vibecattwo

Install

lazy.nvim:

{ "amansingh-afk/milli.nvim", lazy = false }

packer.nvim:

use "amansingh-afk/milli.nvim"

Quick start

-- preview any bundled splash in a scratch buffer
:MilliPreview fire

-- or wire into your dashboard
require("milli").dashboard({ splash = "fire", loop = true })

List bundled splash names:

:lua print(vim.inspect(require("milli").list()))

For dashboard-nvim / alpha-nvim / snacks.nvim / mini.starter wiring, see Dashboard integrations.

Using your own splash

Powered by milli - the ASCII engine behind this plugin. ⭐ Star it on GitHub if you find it useful.

The 29 bundled splashes are a starting point. Bring any image or GIF you want - a custom logo, mascot, anything - and it becomes a splash in four steps.

1. Install the CLI (@amansingh-afk/milli):

npm install -g @amansingh-afk/milli

2. Generate frames.lua from any image / GIF:

milli export mycat.gif ./out -t lua -w 60 --no-bg

Useful flags:

  • -w 60 - width in columns; tune to taste
  • --no-bg - drop background color (cleaner on dashboards)
  • -m braille - braille mode for higher-detail line art

3. Copy frames.lua into your Neovim config:

mkdir -p ~/.config/nvim/lua/milli/splashes
cp out/frames.lua ~/.config/nvim/lua/milli/splashes/mycat.lua

Neovim's runtimepath auto-discovers ~/.config/nvim/lua/, so this file becomes a sibling to the plugin's bundled splashes - findable by the same machinery, tab-completable in :MilliPreview.

4. Use it - same API as any bundled splash:

require("milli").dashboard({ splash = "mycat", loop = true })

Preview it first:

:MilliPreview mycat

Custom module path (advanced)

If you don't want to piggyback on the milli.splashes namespace (e.g. you organize splashes under a dotfiles module), drop the file anywhere on runtimepath and reference it by Lua module path:

-- ~/.config/nvim/lua/mydots/splashes/mycat.lua
require("milli").dashboard({ module = "mydots.splashes.mycat", loop = true })

Works with every preset - splash = "name" for bundled/user-local, module = "path.to.mod" for custom namespaces.

Dashboard integrations

Pick your dashboard plugin. Each preset (dashboard, alpha, snacks, starter, vimenter) works identically with bundled or custom splashes.

dashboard-nvim

return {
  "nvimdev/dashboard-nvim",
  event = "VimEnter",
  dependencies = { "amansingh-afk/milli.nvim" },
  opts = function()
    local splash = require("milli").load({ splash = "finger" })
    return {
      theme = "doom",
      config = {
        header = splash.frames[1],         -- seed header with frame 0
        center = {
          { icon = "  ", desc = "Find File", key = "f", action = "Telescope find_files" },
          { icon = "  ", desc = "Quit",      key = "q", action = "qa" },
        },
      },
    }
  end,
  config = function(_, opts)
    require("dashboard").setup(opts)
    require("milli").dashboard({ splash = "finger", loop = true })
  end,
}

alpha-nvim

require("milli").alpha({ splash = "fire", loop = true })

snacks.nvim

return {
  "folke/snacks.nvim",
  priority = 1000,
  lazy = false,
  dependencies = { "amansingh-afk/milli.nvim" },
  opts = function()
    local splash = require("milli").load({ splash = "fire" })
    return {
      dashboard = {
        enabled = true,
        preset = {
          header = table.concat(splash.frames[1], "\n"),
        },
        sections = {
          { section = "header", padding = 1 },
          { section = "keys",   gap = 1, padding = 1 },
          { section = "startup" },
        },
      },
    }
  end,
  config = function(_, opts)
    require("snacks").setup(opts)
    require("milli").snacks({ splash = "fire", loop = true })
  end,
}

preset.header seeds frame 0 of the splash as snacks's default header so milli's anchor-search can locate the buffer position to animate over. The splash name in preset.header and in require("milli").snacks({ splash = ... }) must match.

mini.starter

require("milli").starter({ splash = "fire", loop = true })

No plugin (raw VimEnter)

require("milli").vimenter({ splash = "fire", loop = true })

Previewing

:MilliPreview <name>

Opens a scratch buffer, plays the splash in a loop. q or <Esc> dismisses. Tab-completes against bundled splashes and any you've dropped into ~/.config/nvim/lua/milli/splashes/. Run :MilliPreview with no arg to list what's available.

API

require("milli").play(buf, opts)       -- paint/animate into buf
require("milli").load(opts)            -- return the data table
require("milli").list()                -- array of all discovered splash names

require("milli").dashboard(opts)       -- autocmd preset for dashboard-nvim
require("milli").alpha(opts)           -- alpha-nvim
require("milli").snacks(opts)          -- snacks.nvim
require("milli").starter(opts)         -- mini.starter
require("milli").vimenter(opts)        -- raw VimEnter

opts

{
  splash = "fire",     -- bundled or user-local splash name, OR
  module = "mysplash", -- require path to an external splash module, OR
  data = { ... },      -- the data table directly
  loop = true,         -- repeat forever (default: false - play once)
}

A plain string is sugar for { splash = <string> }. So require("milli").dashboard("fire") works.

Requirements

  • Neovim 0.10+ (extmarks, namespaces)
  • termguicolors enabled (vim.opt.termguicolors = true)

Why extmarks, not ANSI escapes?

Neovim buffers strip ANSI. Colors are applied via extmarks + per-color highlight groups generated on demand. The groups are keyed on quantized fg/bg so a truecolor splash doesn't blow through Neovim's highlight-group cap (E849).

License

MIT.

Back to Neovim