meowsoot.nvim

July 19, 2026 · View on GitHub

CI

A pink–cyan–lavender Neovim colorscheme. Strings are yellow, functions are pink, types are lavender — and green never reaches code.

Pure Lua. Zero runtime dependencies. Authored in HSL, AAA contrast on the night variant.

meowsoot.nvim

Why meowsoot

  • No green in code. Most schemes use green for strings or comments. meowsoot reroutes the chroma — strings are yellow, types are lavender, functions are pink, keywords are cyan. The result is a syntax surface that's immediately recognisable in any screenshot. The invariant is structural, not stylistic — green isn't on the c table that group files can see, so a regression would fail loudly at load time. Green still appears in the only places that need it: diff add, git add, success states, the ANSI terminal slot.
  • Six chromatic accents, tuned together. Anchored at 190° · 208° · 275° · 328° · 20° · 50° — cyan, blue, lavender, pink, peach, yellow. Warm-biased. Three lightness tiers per accent (ANCHOR / STANDARD / QUIET) so the visual hierarchy of the syntax tree comes through without arbitrary highlight noise.
  • Pure Lua, zero dependencies. ~50-line HSL → hex engine. No plenary, no required treesitter, no lush.nvim. Loads fast, caches compiled highlights, easy to fork.
  • 22 plugin integrations, auto-detected via lazy.nvim. Telescope, fzf-lua, Snacks, Gitsigns, nvim-cmp, blink.cmp, mini.*, noice, which-key, trouble, render-markdown, treesitter-context, flash, lazy.nvim, nvim-tree, indent-blankline. Bundled lualine theme.
  • Ecosystem in the box. Matching configs for Ghostty, Kitty, Alacritty, WezTerm, Tmux, Fish, and fzf live in extras/, regenerated from the same palette. Your editor identity carries through to your shell.

Showcase

The full editor surface. File tree, split buffers, lualine — all keyed to the same six-hue chromatic system.

editor surface

Markdown via render-markdown.nvim. The rainbow heading wash, fenced code blocks, badges, inline links — all in palette.

markdown rendering

Pickers. Fuzzy file search floating over a code buffer.

picker over code

Git surface. Log view with an inline commit diff. The only place green is allowed to appear — for add lines and nothing else.

git log and inline diff

Moon — cool dark variant. The same buffer as the hero up top, neutrals rotated to a calm blue.

moon variant

Dawn — light variant. The same buffer on warm cream — same hue identity, tier-inverted for readability.

dawn variant

Terminal ecosystem. Ghostty, Kitty, Alacritty, WezTerm, Tmux, and Fish all themed via the extras/ configs, regenerated from the same palette.

ghostty, tmux, fish

Palette

All three variants are resolved from the same HSL source of truth (lua/meowsoot/palette.lua). The tables below are regenerated whenever the palette changes — run just extras to refresh. Hex values are real text, so you can select and copy them.

Full swatch tables — Night · Moon · Dawn (click to expand)

Night

Accents

SwatchNameHexRole
pink#eaa4c9functions, methods, headings
lavender#cca6e7types, classes, modules
cyan#96d8e3keywords, imports, tags, builtins
peach#e3b096constants, booleans
blue#96bddfANSI 4/12, diff-change, info
yellow#dfd286strings, regex

Neutrals

SwatchNameHexRole
bg_deep#100f0fdarkest panel
bg_0#171616editor background
bg_1#201f1dpanel
bg_2#282625active line
bg_3#353331selection
bg_4#454240border
indent#484542indent guides
fg_faint#85807agutter, punctuation, operators
comment#837d77comments
fg_mute#b1ada9docs, folds, diagnostics, statusline
fg#e2e0dfforeground

Moon

Accents

SwatchNameHexRole
pink#eaa4c9functions, methods, headings
lavender#cca6e7types, classes, modules
cyan#96d8e3keywords, imports, tags, builtins
peach#e3b096constants, booleans
blue#96bddfANSI 4/12, diff-change, info
yellow#dfd286strings, regex

Neutrals

SwatchNameHexRole
bg_deep#101218darkest panel
bg_0#171921editor background
bg_1#20222cpanel
bg_2#272935active line
bg_3#353746selection
bg_4#404454border
indent#434656indent guides
fg_faint#797e96gutter, punctuation, operators
comment#797e9acomments
fg_mute#a0a5badocs, folds, diagnostics, statusline
fg#d9dbe8foreground

Dawn

Accents

SwatchNameHexRole
pink#911256functions, methods, headings
lavender#6a2c96types, classes, modules
cyan#187a8bkeywords, imports, tags, builtins
peach#a34414constants, booleans
blue#25659dANSI 4/12, diff-change, info
yellow#917112strings, regex

Neutrals

SwatchNameHexRole
bg_deep#e8e3dedarkest panel
bg_0#f9f6f1editor background
bg_1#e6e0dbpanel
bg_2#f2eee9active line
bg_3#d7cac1selection
bg_4#b0998dborder
indent#cec9c5indent guides
fg_faint#9c948bgutter, punctuation, operators
comment#897a6ccomments
fg_mute#7e7063docs, folds, diagnostics, statusline
fg#3c312aforeground

The night variant is the main act. moon is a cool, blue-tinted dark counterpart — same accents, neutrals rotated to a calm blue (H≈230°) for a Rosé-Pine-Moon mood. dawn is a complementary light counterpart with the same hue identity, tier-inverted for readability on cream.

The story

A fusion of two ideas. The charcoal background is inspired by Susuwatari — the wandering soot sprites from Studio Ghibli films. The pink and peach accents are inspired by Nyan Cat's pop-tart palette. The rest of the colors — cyan, lavender, yellow, blue — were tuned to round out the chromatic system.

The dawn variant carries the same hue identity onto a warm cream background: the same soot sprites, woken up at sunrise.

Install

Requires Neovim 0.9+. No external dependencies.

lazy.nvim

{
  "marekh19/meowsoot.nvim",
  lazy = false,
  priority = 1000,
  config = function()
    vim.cmd.colorscheme("meowsoot")
  end,
}

Local development

{
  dir = "/path/to/meowsoot",
  lazy = false,
  priority = 1000,
  config = function()
    vim.cmd.colorscheme("meowsoot")
  end,
}

Configuration

All options are optional. Defaults shown.

require("meowsoot").setup({
  style = "night",                -- "night" (warm dark) | "moon" (cool dark) | "dawn" (light)
  transparent = false,            -- transparent backgrounds
  terminal_colors = true,         -- set vim.g.terminal_color_0..15

  styles = {
    comments  = { italic = true },
    keywords  = {},
    functions = {},
    variables = {},
    sidebars  = "dark",           -- "dark" | "transparent" | "normal"
    floats    = "dark",
  },

  -- Plugin highlight groups. Auto-detected via lazy.nvim if `auto = true`.
  plugins = {
    all  = false,
    auto = true,
    -- Force-enable / disable individual plugins:
    -- telescope = true,
    -- gitsigns = false,
  },

  cache = true,                   -- cache compiled highlights to disk

  on_colors = function(c) end,    -- mutate the color table
  on_highlights = function(hl, c) end, -- mutate the highlight table
})
vim.cmd.colorscheme("meowsoot")

Variants

Two ways to pick a variant:

require("meowsoot").setup({ style = "moon" })
vim.cmd.colorscheme("meowsoot")

Or skip setup entirely and use the per-variant entry point:

:colorscheme meowsoot          " night (warm dark, default)
:colorscheme meowsoot-moon     " moon (cool dark)
:colorscheme meowsoot-dawn     " dawn (warm light)

To flip variants with :set background=light / dark, wire an autocmd:

vim.api.nvim_create_autocmd("OptionSet", {
  pattern = "background",
  callback = function()
    vim.cmd.colorscheme(vim.o.background == "light" and "meowsoot-dawn" or "meowsoot")
  end,
})

Lualine

Use the bundled lualine theme:

require("lualine").setup({ options = { theme = "meowsoot" } })

It reads the active variant (vim.g.meowsoot_style, falling back to vim.o.background) and re-resolves on every :colorscheme switch, so it stays in sync.

Plugins covered out of the box

gitsigns · telescope · nvim-cmp · blink.cmp · lazy.nvim · flash.nvim · nvim-tree · indent-blankline · treesitter-context · snacks.nvim · mini.icons / mini.files / mini.statusline / mini.indentscope / mini.diff / mini.notify / mini.pick · noice · which-key · trouble · render-markdown · fzf-lua

Extras (terminal / multiplexer / shell)

Pre-generated configs live in extras/, one file per palette variant. Night is the canonical default — it keeps the unsuffixed filename; moon and dawn add a -<variant> suffix.

ToolNight (default)MoonDawn
Ghosttyextras/ghostty/meowsootextras/ghostty/meowsoot-moonextras/ghostty/meowsoot-dawn
Kittyextras/kitty/meowsoot.confextras/kitty/meowsoot-moon.confextras/kitty/meowsoot-dawn.conf
Alacrittyextras/alacritty/meowsoot.tomlextras/alacritty/meowsoot-moon.tomlextras/alacritty/meowsoot-dawn.toml
WezTermextras/wezterm/meowsoot.tomlextras/wezterm/meowsoot-moon.tomlextras/wezterm/meowsoot-dawn.toml
Tmuxextras/tmux/meowsoot.tmuxextras/tmux/meowsoot-moon.tmuxextras/tmux/meowsoot-dawn.tmux
Fishextras/fish/meowsoot.fishextras/fish/meowsoot-moon.fishextras/fish/meowsoot-dawn.fish
fzfextras/fzf/meowsoot.confextras/fzf/meowsoot-moon.confextras/fzf/meowsoot-dawn.conf

WezTerm loads schemes by internal name, so the variant files declare meowsoot-moon / meowsoot-dawn (matching the filename) — set config.color_scheme accordingly. Every other tool loads by file path.

These are output artifacts — don't edit by hand, they get overwritten on regeneration.

Regenerating

After tuning lua/meowsoot/palette.lua:

just extras

Built by a small Lua generator (lua/meowsoot/extras/) using only headless Neovim — no external build dependencies. The README palette tables and swatches (static/swatches/) are regenerated by the same target.

Hacking the palette

Authored in HSL ({h, s, l}) for ergonomic tuning on the color wheel, resolved to hex at load time via lua/meowsoot/hsl.lua. Edit lua/meowsoot/palette.lua to shift hues / saturation / lightness; the rest of the theme follows automatically.

No green in code — enforcement

Green never reaches a syntax group. The chokepoint is lua/meowsoot/colors.luagreen is intentionally not exposed as a top-level key on the resolved colors table. Code-shaped group files (groups/base.lua syntax section, groups/treesitter.lua, groups/semantic_tokens.lua, groups/kinds.lua) cannot reach it. Green leaks only through the semantic aliases c.git.add, c.diff.add, c.ok, c.terminal.green, and the mini.icons UI category.

Recipes

RecipeWhat it does
just checkHeadless smoke-test: load the colorscheme, fail on errors
just extrasRegenerate everything under extras/ plus static/palette.svg
just fmtRun stylua over lua/ and colors/
just check-fmtVerify stylua formatting (exits non-zero if dirty)
just cache-cleanDrop the compiled-highlights cache

Architecture

Inspired by tokyonight.nvim.

lua/meowsoot/
  init.lua            -- setup(opts) / load()
  config.lua          -- defaults + user-merge
  theme.lua           -- orchestrator: colors → groups → nvim_set_hl
  util.lua            -- blend / darken / lighten / template / cache
  hsl.lua             -- HSL ↔ hex (~50 lines, no dependencies)
  palette.lua         -- HSL palette (single source of truth, all variants)
  colors.lua          -- HSL → hex + semantic alias layer ("no green in code" chokepoint)
  groups/
    init.lua          -- aggregator: cache, plugin auto-detect via lazy
    base.lua          -- editor UI + native Syntax/* + diff/git UI
    treesitter.lua    -- @* groups
    semantic_tokens.lua  -- @lsp.*
    kinds.lua         -- LSP kind helper
    plugins/          -- per-plugin overrides
  extras/             -- ghostty / kitty / alacritty / wezterm / tmux / fish / fzf / palette-md generators