A quiet, transparent Neovim that reads PDFs in a split, runs notebooks, keeps Claude in ordinary buffers
and lets the terminal's glass show through every one of its nineteen colour schemes.
Neovim 0.11 · lazy.nvim · 70 plugin specs · 7.5k lines of Lua · macOS + kitty
Most of this is a careful arrangement of good plugins. A few parts are written from scratch because nothing else did them the way I wanted: a PDF viewer drawn with kitty graphics, Claude sessions that live in buffers, terminals that remember what they ran, and a transparency system that every theme obeys. The editor itself stays out of the way, with earthy colours, one accent and no chrome you didn't ask for.
lua/pdfview/ renders PDFs inside Neovim with the kitty graphics protocol, so there's no second window to manage. The pages take on your theme: ink becomes the editor's foreground and paper becomes the terminal's glass, while raster figures keep their real colours.
LaTeX. ␣ l v opens the compiled PDF next to the source, sized to the page's aspect ratio. SyncTeX works in both directions: the cursor's line is boxed on the page, and clicking a word on the page jumps to its line. ␣ l F keeps following you as you type and recompile. VimTeX drives compilation, the first compile opens the preview, the system viewer is one key away (␣ l V), and a Castel-style snippet set handles math as you write.
Markdown. ␣ p v pipes the buffer through pandoc and typst with a GitHub-flavoured template. The page is cut to the shape of the split, so text reflows when you resize it and j k move screen to screen. It re-renders as you type. Without SyncTeX, both directions match text instead.
How a page gets to the screen
Each page is rasterised once per zoom level by pdftoppm, recoloured by ImageMagick and kept as a memory-mapped .mpc file. Every redraw only crops the visible part out of those into one PNG the size of the window, which takes about 0.15 s instead of the 0.6 s a fresh rasterise costs at retina sizes. The next view is prefetched. Search uses pdftotext -bbox word boxes, links come from pdftohtml -xml, and per-file page, zoom and spread are remembered across sessions. Any .pdf you :edit opens the same way.
lua/claude_chats/ runs claude in ordinary terminal buffers, as many as you like, side by side or in the background. Each one gets the same environment that claudecode.nvim gives its own split, so diffs, selections and diagnostics still flow through the IDE integration.
Past sessions are read straight from ~/.claude/projects/ and listed in a neo-tree tab under their own titles. Running chats are matched to their logs by a pre-assigned session id. ␣ a n starts a chat, ␣ a R resumes one and ␣ a l opens the list, while ␣ a c still toggles the classic claudecode split.
Shells start through a small ZDOTDIR wrapper that loads your real zsh config unchanged, then emits the standard OSC marks around every command. In return, lua/terminals/ knows each shell's directory, the command it's running, the last one it finished, its exit status, and exactly which rows its output occupies.
- ␣ t q last output → quickfix
- Compiler errors become a jump list, with paths resolved against that shell's directory, not Neovim's.
- ␣ t r run it again
- Re-runs the last command in the last terminal you used.
- ␣ t s pick a terminal
- Telescope with a scrollback preview. Every shell's name, command and exit code also show in its winbar and in neo-tree's Terminals tab.
- ␣ t p ␣ t N ␣ t R REPLs
- Pinned Python, Node and R. ␣ t l sends a line or selection, and Python 3.13's REPL gets bracketed paste.
Terminals are saved with the session and come back in the same directories.
.ipynb files open as Markdown through jupytext and run cell by cell in real Jupyter kernels through molten.nvim. In kitty, plots appear inline. Quarto documents get LSP inside every chunk via otter.nvim, and R runs through the same kernel machinery as Python.
␣ m i picks a kernel. ␣ r c runs the cell under the cursor, ␣ r a runs them all, and ␣ r k / ␣ r j run everything above or below. A small jkernel helper registers a project's venv as a kernel in one command. The full workflow is in docs/molten.md.
Every colour scheme draws without an editor background, so the terminal's translucent glass shows through. A single autocmd enforces it for schemes that have no transparency option of their own. Accents across the UI (the lualine blocks, the cursorline number, the dashboard clock) come from the active scheme's Function colour, so nothing is hard-coded and every theme looks deliberate.
Drawn from each scheme's real highlight groups, read out of a headless Neovim.
␣ c s picks a scheme with live preview and remembers it. The glass is the default and the point, but ␣ u b turns it solid when a scheme deserves its own background. In Alacritty the window's opacity follows along and resets when Neovim exits.
The small things
- A cursorline only where you are
- It shows in the focused file window only, never in terminals, floats or Zen mode. ␣ u c cycles it between number, underline and a blended band.
:qcloses the buffer- In the last window you get the next buffer, or the dashboard.
:qon the dashboard leaves Neovim. Unsaved buffers ask Save / Discard / Cancel. - Motion over fades
- A terminal cell is either a colour or glass, so animations move rather than fade: a stiff smear cursor, 140 ms eased scrolling, a short glimmer on yank, notifications that slide.
- A dashboard that's actually live
- The clock ticks only while the dashboard is visible. The stats line comes from one cached GitHub GraphQL call, so it never blocks startup.
- And for breaks
- ␣ f m l makes the code rain, and ␣ t y opens a typing trainer.
Plugins are one file each under lua/plugins/, and lazy.nvim imports the whole directory, so adding a plugin means adding a file. Language servers are installed by Mason and set up with Neovim 0.11's native vim.lsp.config. A single LspAttach autocmd binds the same keys for every server.
Leader is Space (written ␣ here) and localleader is \. ␣ ? searches every mapping, and ␣ k opens a cheatsheet.
| Keys | Does |
|---|---|
| ␣ f f ␣ n | Find files · toggle neo-tree |
| Tab S-Tab ␣ x | Next / previous buffer · close buffer, keep the window |
| gd gr gi gy K | Definition, references, implementation, type · peek fold, else hover |
| ␣ r n ␣ c a [d ]d | Rename · code action · previous / next diagnostic |
| C-\ ␣ t n ␣ t s | Last terminal · new shell · terminal picker |
| ␣ a n ␣ a l ␣ a c | New Claude chat · chat list · claudecode split |
| ␣ l l ␣ l v ␣ p v | Compile LaTeX · PDF preview · Markdown preview |
| ␣ m i ␣ r c ␣ r a | Start kernel · run cell · run all |
| ␣ c s ␣ u b ␣ u B | Colour scheme · transparent ↔ solid · dark ↔ light |
| ␣ z ␣ u h ␣ u f | Zen mode · inlay hints · format on save |
| ␣ d b ␣ d c ␣ d u | Breakpoint · continue · debugger UI |
| ␣ q q | Quit Neovim |
Every mapping is documented in :help nvim-keymaps.
git clone https://github.com/Lunaaaalj/nvim ~/.config/nvim
nvim # lazy.nvim bootstraps itself; Mason installs servers, formatters and debuggersWhat it expects on the machine
| For | Needs |
|---|---|
| Always | Neovim 0.11+, git, make (telescope-fzf-native), lazygit |
| PDF viewer | brew install poppler imagemagick, plus pandoc typst for the Markdown preview |
| Graphics | kitty, WezTerm or Ghostty for the PDF viewer and inline plots. Alacritty runs everything else |
| Notebooks | a ~/.virtualenvs/neovim venv with pynvim jupyter_client jupytext, then :UpdateRemotePlugins |
| R / Quarto | brew install r quarto, then IRkernel::installspec() once in R |
| Dashboard stats | gh auth login. Without it, the stats line simply doesn't appear |
| LaTeX | a TeX distribution with latexmk |
Every plugin, by job
| Job | Plugins |
|---|---|
| Core | lazy.nvim, nvim-lspconfig, mason (+ lspconfig, tool-installer), nvim-cmp, LuaSnip, conform.nvim, nvim-treesitter (+ context, textobjects) |
| Moving around | telescope (+ fzf-native), neo-tree, oil.nvim, harpoon, flash.nvim, grug-far, which-key |
| Editing | nvim-surround, Comment.nvim, mini.ai, treesj, nvim-ufo, nvim-autopairs, todo-comments |
| Interface | lualine, bufferline, noice + nvim-notify, barbecue + navic, snacks (dashboard, scroll), satellite, mini.indentscope, illuminate, rainbow-delimiters, colorizer, tiny-devicons |
| Motion | smear-cursor, tiny-glimmer, precognition |
| Git | lazygit.nvim, gitsigns, diffview, git-conflict |
| Test & debug | neotest (pytest), nvim-dap + dap-ui (Python, C/C++), trouble.nvim |
| Writing | VimTeX, render-markdown, zen-mode + twilight, hover.nvim |
| Notebooks | molten.nvim, jupytext.nvim, image.nvim, quarto-nvim, otter.nvim |
| Sessions & AI | persistence.nvim, toggleterm, claudecode.nvim |
| Schemes | kanso, evergarden, melange, everforest, gruvbox-material, kanagawa, kanagawa-paper, rose-pine, bamboo, flexoki, vesper, catppuccin, nightfox, lackluster, zenbones (+ forest/neo/kanagawa/seoul bones) |
| Breaks | cellular-automaton, typr |
Everything above is written down properly inside the editor: :help nvim-config, :help nvim-keymaps, :help nvim-plugins and :help nvim-notebooks.






